亵渎小说介绍
This post about moving from PHP to Go was first published elsewhere, and republished here with the author’s permission.
这篇关于从PHP迁移到Go的文章最初是在其他地方发表的,并在得到作者许可的情况下在此处重新发布。
Earlier this year, I made an arguably bad business decision. I decided to rewrite the Laravel application powering Boxzilla in Go.
今年早些时候,我做出了一个糟糕的商业决定。 我决定重写Go中支持Boxzilla的Laravel应用程序。
No regrets though.
虽然没有遗憾。
Just a few weeks later I was deploying the Go application. Building it was the most fun I had in months, I learned a ton, and the end result is a huge improvement over the old application. Better performance, easier deployments and higher test coverage.
仅仅几个星期后,我就部署了Go应用程序。 构建它是我几个月来最有趣的事情,我学到了很多东西,最终结果是对旧应用程序进行了巨大的改进。 更好的性能,更容易的部署和更高的测试覆盖率。
The application is a fairly straightforward database driven API & account area where users can log-in to download the product, view their invoices or update their payment method.
该应用程序是一个非常简单的数据库驱动的API和帐户区域,用户可以在其中登录以下载产品,查看其发票或更新其付款方式。
Stripe and Braintree are used to accept subscription payments. Invoices are handled using MoneyBird and some transactional emails are sent using Mailgun.
Stripe和Braintree用于接受订阅付款。 发票使用处理MoneyBird和一些事务性的电子邮件使用发送Mailgun 。
While Laravel worked well enough for this, some things always felt overcomplicated to me. And what’s with releasing a new “major” version every few months? I’d be fine if the newer versions contained significant improvements, but a lot of the times it just felt like minor naming & directory structure changes to me.
尽管Laravel在这方面做得足够好,但有些事情总是让我感到过于复杂。 每隔几个月发布一个新的“主要”版本是什么? 如果较新的版本包含重大改进,我会很好,但是在很多时候,感觉就像是对我的较小的命名和目录结构的更改。
为什么去? (Why Go?)
Last year I’ve been moving several services over to Go, so I wasn’t completely new to the language. As a developer selling WordPress based products, part of my job is working in an ancient tech stack that is mostly focused on the end user.
去年,我已经将几种服务转移到了Go上,所以我对这种语言并不是完全陌生。 作为销售基于WordPress的产品的开发人员,我的一部分工作是在一个古老的技术堆栈中工作,该堆栈主要关注最终用户。
If I weren’t self-employed, I would simply apply for a new job to make up for this lack of sexy tech. Being my own boss, I owe it to myself to make my day-to-day work fun and not just chase more immediate $$$. If revenue allows (and it does), why not have a little fun?
如果我不是自雇人士,我会简单地申请一份新工作来弥补这种缺乏性感技术的现象。 作为我自己的老板,我有责任使自己的日常工作变得有趣,而不仅仅是追逐更多的即时资金。 如果收入允许(并且确实如此),为什么不找点乐子呢?
It’s a joy to write Go code, the tooling is amazing and it’s not only fast to develop in, the end result is usually crazy fast too. Just reading about the purpose of the Go project sold me on the language.
编写Go代码很高兴,工具很棒,而且开发速度不快,最终结果通常也很快。 刚读完Go项目的目的,就使我对语言产生了兴趣。
I think we’ll see a good amount of people switching from dynamically typed languages like PHP, Python and JavaScript to Go in the next few years.
我认为,在未来几年中,将会有大量人从动态类型的语言(如PHP,Python和JavaScript)切换到Go。
移植代码库 (Porting the Codebase)
Migrating the code to Golang consisted mostly about getting the database interaction right & porting the Blade templates to something we could use in Go.
将代码迁移到Golang主要包括正确地进行数据库交互以及将Blade模板移植到我们可以在Go中使用的东西。
ORMs are one thing that always ends up getting in my way, so I went for a mockable data access layer and plain SQL queries. Meddler was used to get rid of some of the boilerplate for scanning query results into structs.
ORM是总会妨碍我的一件事,因此我选择了可模拟的数据访问层和简单SQL查询。 使用Meddler摆脱了一些样板,将查询结果扫描到结构中。
To support hierarchical templates and partials I open-sourced grender, a tiny wrapper around Go’s standard html/template package. This allowed me to port the Blade template files to Go with relative ease, since I could use the same hierarchical structure and partial templates.
为了支持分层模板和局部组件 ,我开源了grender ,这是Go的标准html / template包的一个小包装。 这使我可以相对轻松地将Blade模板文件移植到Go中,因为我可以使用相同的层次结构和部分模板。
For integrating with Stripe there is the official stripe-go package. For Braintree there is the unofficial braintree-go package, which was neglected for a little while but received renewed attention lately. Since there was no Go package to manage invoices in Moneybird yet, I built and open-sourced moneybird-go.
为了与Stripe集成,有官方的Stripe -Go软件包。 对于Braintree,有一个非正式的braintree-go软件包,该软件包被忽略了一会儿,但最近又受到了新的关注。 由于到目前为止,在Moneybird中还没有Go软件包来管理发票,因此我构建并开源了moneybird-go 。
比较苹果与橙子 (Comparing Apples vs Oranges)
Since Go is a compiled language with a much better standard library than PHP, it is not really fair to compare the two languages like I am about to. That said, I thought it would be fun to share some numbers.
由于Go是一种编译语言,具有比PHP更好的标准库,因此像我将要比较的这两种语言真的不公平。 就是说,我认为分享一些数字会很有趣。
性能 (Performance)
wrk was used to perform some simple HTTP benchmarks for both applications returning the HTML for the login page.
wrk用于为返回登录页面HTML的两个应用程序执行一些简单的HTTP基准测试。
Concurrency | Avg. latency | Req / sec | Transfer / sec | |
---|---|---|---|---|
Laravel | 1 | 3.87ms | 261.48 | 1.27MB |
Laravel | 100 | 108.86ms | 917.27 | 6.04MB |
Go | 1 | 325.72μs | 7365.48 | 34.27MB |
Go | 100 | 11.63ms | 19967.31 | 92.91MB |
Go | 200 | 37.68ms | 22653.22 | 105.41MB |
并发 | 平均 潜伏 | 要求/秒 | 传输/秒 | |
---|---|---|---|---|
Laravel | 1个 | 3.87毫秒 | 261.48 | 1.27兆字节 |
Laravel | 100 | 108.86毫秒 | 917.27 | 6.04兆字节 |
走 | 1个 | 325.72微秒 | 7365.48 | 34.27兆字节 |
走 | 100 | 11.63毫秒 | 19967.31 | 92.91兆字节 |
走 | 200 | 37.68毫秒 | 22653.22 | 105.41MB |
Unfortunately, the Laravel application (or PHP-FPM socket) kept falling over once I increased the number of concurrent “users” past 100.
不幸的是,一旦我将并发“用户”的数量增加到100以上,Laravel应用程序(或PHP-FPM套接字)就一直崩溃。
NetData provided the following graphs to see how the server was holding up under all this load.
NetData提供了以下图表,以查看服务器在所有这些负载下的承受能力。
Golang with 100 concurrent connections
具有100个并发连接的Golang
Laravel with 100 concurrent connections
具有100个并发连接的Laravel
Please note that I ran the benchmark from the same machine as the applications were running on, so this heavily influences both graphs.
请注意,我在运行应用程序的同一台计算机上运行了基准测试,因此这会严重影响两个图表。
代码行 (Lines of Code)
Let’s compare the lines of code in both applications, including all vendor dependencies.
让我们比较两个应用程序中的代码行,包括所有供应商依赖性。
find . -name '*.php' | xargs wc -l
156289 total
The Laravel version consists of just over 156.000 lines of code. This is excluding development dependencies which, with Laravel, are needed to run tests etc.
Laravel版本包含超过156.000行代码。 这不包括开发依赖关系,而Laravel需要运行测试等。
find . -name '*.go' | xargs wc -l
33624 total
The Golang version on the other hand consists of 33.000 lines of code. That’s one fifth of the code for exactly the same functionality.
另一方面,Golang版本包含33.000行代码。 这是完全相同功能的代码的五分之一。
Let’s exclude external dependencies in the Laravel application so we know how much lines were actually written by me.
让我们在Laravel应用程序中排除外部依赖关系,以便我们知道我实际写了多少行。
find . -name '*.php' -not -path "./vendor/*" | xargs wc -l
13921 total
And for Golang.
对于Golang。
find . -name '*.go' -not -path "./vendor/*" | xargs wc -l
6750 total
The result is slightly more even when just looking at managed lines of code. Still, it’s the exact same application with half the amount of code.
即使仅查看托管代码行,结果也要稍微多一些。 尽管如此,它是使用一半代码的完全相同的应用程序。
测试覆盖率 (Test Coverage)
Testing is a first class citizen in Golang, and test files live right next to the actual source files.
测试是Golang的头等公民,测试文件紧邻实际源文件存在。
license.go
license_test.go
subscription.go
subscription_test.go
This makes it incredibly convenient to apply test driven development.
这使得应用测试驱动的开发变得异常方便。
In our Laravel application we mostly had integration tests that checked whether the request handlers returned a proper response. Overall test coverage was quite low, mostly due to tight coupling which in turn was mostly my fault. Writing the same application a second time really helps here too.
在我们的Laravel应用程序中,我们主要进行了集成测试,以检查请求处理程序是否返回了正确的响应。 总体测试覆盖率很低,主要是由于紧密耦合,而这又主要是我的错。 再次编写相同的应用程序确实也有帮助。
TLDR (TLDR)
I did something you should never do: rewrote an application in a different language because I felt like it. Had lots of fun and got a much smaller and faster application in return.
我做了您不应该做的事情:用另一种语言重写应用程序,因为我感觉很喜欢。 获得了很多乐趣,并且得到了更小,更快的应用程序。
亵渎小说介绍