📜 ⬆️ ⬇️

Go in terms of PHP programmer

I bring to your attention the translation of the article Go from PHP engineer's perspective from the site sobit.me .

As a PHP programmer, have you ever thought about the idea of ​​learning other programming languages?

For many years, the choice of many companies falls on PHP to create full-fledged monolithic applications. Moreover, over the past 5 years, frameworks ( Symfony , Laravel , Zend ), tools ( Composer , Monolog ), and a rapidly growing community ( PHP-FIG ) have helped many developers create software at the enterprise level. Many companies, such as Facebook, Yahoo !, Wikipedia, Wordpress, Tumblr, began their history with PHP, and this did not prevent them from becoming successful in the following years.
')
However, a successful business is developing, and with it grows the required number of developers to maintain successful growth. The organizational structure makes it clear that it would be nice to break an existing monolithic application. At a certain point, the strategy begins to stabilize and teams focus on independent services.

In this article, we will try to understand how far we can go, having only PHP in our arsenal, and where Go can enter to help solve the problems we have to face.

PHP and microservices


Every PHP developer knows that if he manages to bring the initialization time of a large monolithic application to 30ms, this is a great result! Add to this 50-100ms to handle the request itself, and we have an amazing total response time.

Since we are planning to break our monolith, what will happen if we decide to stick to this architecture for our services? Simple calculations, and we already spend 300ms only for initialization if the services have contacted each other 10 times during a single request. Unpleasant user experience!

While PHP is shining in the world of web development, its capabilities in microservice architectures have not yet matured. Natural terms — such as wait-time processing, health checks, metrics collection, breakers — are often unfamiliar to a PHP programmer. Many of them can be found in various frameworks in many other languages ​​right out of the box. Their support in the PHP ecosystem is too small, if it exists at all.

Meet Go


From Wikipedia:

Go (often also Golang) is a compiled, multi-threaded programming language developed by Google. The initial development of Go began in September 2007, while Robert Grizmer, Rob Pike and Ken Thompson, who had previously worked on the Inferno operating system development project, were directly involved in its design. Officially, the language was introduced in November 2009.

Go was developed by Google. He was not a fun 20% project, nor was he intended to achieve something inaccessible to others. It was created only because of the frustration of the difficulty that very large teams created by working on very large parts of the application in languages ​​with a wide range of possibilities.

Despite such remarkable features as easy concurrency or quick compilation, the main feature that makes language special is incredible simplicity. By the way, the number of keywords in Go is 25 , while in PHP there are 67 of them .

Go appeared at about the same time that PHP gained namespace support (2009). After only 6 years, dozens of great projects have been created on it, among others Docker , Kubernetes , etcd , InfluxDB . Many companies, such as Cloudflare, Google, Dropbox, SoundCloud, Twitter, PayPal, trust him when writing their backend systems.

Returning to microservices


Let's take a look at the problems that we talked about recently and try to understand what we can do with Go.

Go applications are quickly compiled into native code. Many people claim that the compile time is so fast that, while they switch to the browser and click "Refresh", the application is already recompiled, restarted and processes the request. Even in large code bases, there is a feeling that you are working with an interpreted language, just like with PHP.

Traditional "Hello, World!" The API fits into 10 lines of code and responds faster than a millisecond. The use of all processor cores allows developers to simultaneously run complex parts of the application. The ecosystem allows you to select any transport protocol, such as JSON over HTTP , gRPC , Protocol Buffers or Thrift . Requests are easily traceable to Zipkin . Metrics are exported to various backends, from statsd to Prometheus . It is possible to limit the bandwidth of requests with the help of limiters and to protect client-service communication with the help of interrupts.

More about Go


Tongue


Go is a strong typing language, which forces you to specify the type of a variable when it is declared:

var name string = "sobit" 

Variables can determine the type of value being assigned. The code above is similar to the simplified version:

 var name = "sobit" //   : name := "sobit" 

Now let's remember how we change the values ​​of two variables in PHP:

 <?php $buffer = $first; $first = $second; $second = $buffer; 

And the equivalent in Go:

 first, second = second, first 

This is possible due to multiple return values. Example with function:

 func getName() (string, string) { return "sobit", "akhmedov" } first, last = getName() 

In Go code you will not find the usual foreach , while and do-while . They are combined into a single for statement:

 // foreach ($bookings as $key => $booking) {} for key, booking := range bookings {} // for ($i = 0; $i < count($bookings); $i++) {} for i := 0; i < len(bookings); i++ {} // while ($i < count($bookings)) {} for i < len(bookings) {} // do {} while (true); for {} 

Although there are no so-called "classes" or "objects" in Go, it contains a type of variable that matches the same definition where the data structure combines code and behavior. In Go, this is called "structure." Let's illustrate with an example:

 type rect struct { //   width int height int } func (r *rect) area() int { //    return r.width * r.height } r := rect{width: 10, height: 15} //  fmt.Print(r.area()) 

Sometimes it is useful to create and complex structures. For example:

 type Employee struct { Name string Job Job } type Job struct { Employer string Position string } //   e := Employee{ Name: "Sobit", Job: { Employer: "GetYourGuide", Position: "Software Engineer", }, } 

There are many other features that I would like to talk about, but this would be a duplication of the excellent Effective Go document from the official website and an endless article. But I want to take a moment and present you parallelism in Go, which, in my opinion, is one of the most interesting topics about this language. Before we begin, you need to know two things about parallelism in Go — the gorutines and the channels .

Gorutina has a simple model: it is a function that is performed in parallel with other Gorutins in a single address space. When the call ends, the gorutina goes quiet. The simplest example is to create a heartbeat function that displays the message "I'm alive" every second:

 func heartbeat() { for { time.Sleep(time.Second) fmt.Println("I'm still running...") } } 

How do we now run it in the background, while still being able to continue to perform other tasks? The answer is simpler than you could imagine, just add the prefix go :

 go heartbeat() // keep doing other stuff 

This approach is comparable to the initiation of events in the style of "run-and-forget". But what if we do not need to “forget”, and we are interested in the result of the performance of a function? It is in this case that channels come to the rescue:

 func getName(id int, c chan string) { c <- someHeavyOperationToFindTheName(id) } func main() { c := make(chan string, 2) //   go getName(1, c) //  go getName(2, c) //  ,   //     fmt.Printf("Employees: %s, %s", <-c, <-c) //  } 

To summarize, we just launched the same function twice, while allowing the application to work on other tasks, and requested the results at the moment when we needed them.

Instruments


Go was designed, I repeat, with simplicity in mind. The authors have taken a radical approach to solving everyday developer actions. Say goodbye to the endless debate "tab or space" and programming standards from community groups that are trying to somehow facilitate the exchange of code. Go contains the go fmt tool, which takes responsibility for the style of your code. You no longer need to send IDE configuration files to each other, you do not need to try to remember whether you need to put an opening bracket on the same line or the next.

Library documentation can be read using go doc , while go vet helps you find potential problems in your code. Installation is supported by the libraries with a simple go get github.com/[vendor]/[package] command go get github.com/[vendor]/[package] go test [package] , and tests are run using go test [package] . As you can see, most of the tools that developers include in each application in each language are already here, right out of the box.

Scan


Application development is a necessary action and does not depend on the programming language and what is written with its help. As a PHP programmer, how many Capistrano or Envoy configurations have you written during your professional career? How many manually modified files did you have to transfer to hosting providers during FTP?

Here is the most common and simple PHP application deployment:


Some teams use a more advanced approach:


Of course, besides this, you need to make sure that at least PHP-FPM and PHP are installed on the target and build server, and it would be better for them to match the versions both between themselves and with the version that developers use locally.

Now let's talk about the process of unfolding the Go app:


And that's all. The only difference between a potentially simple and advanced version is whether there is a standalone server for this task or not.

The beauty is that you don’t even need to install Go on target servers, and even if they run on different operating systems or are built on different processor architectures, you can still prepare artifacts for them all (even for Windows) from one and same server builds or any other machine.

Conclusion


No one ever recommended splitting the system into microservices before it matured enough for this. Being small, the business must remain flexible and respond quickly to convenient cases in the market. This is not an ideal environment for creating microservices, and you can get more value from a monolithic application. In this case, PHP with its ecosystem is ideally suited for this strategy.

When an organization stabilizes and it becomes easy to draw the boundaries of its contexts, building microservices in PHP to support them can be painful. There are different tools and techniques in many other languages ​​to help this architecture. You run the risk of either creating your own tools or discarding them altogether - both options can be costly for your organization.

On the other hand, creating microservices on Go is worth consideration. The language is simple to write and understand. The learning curve is not as steep as in the case of Java or Scala , and performance is not far behind C. Compile time helps developers stay efficient, while support for multi-core and networked machines allows you to create powerful applications.

Additional materials


The best place for a new gopher, in my opinion, is the training section on the official website. It includes an interactive introduction to Go , where you can try it out right in the browser, as well as a best-practice document that will help in writing clean, idiomatic code.

If this is not enough, there is also a gathering of community initiatives to help hone the skills gained.

If you like JetBrains IDE just like me, you should look in the direction of the Go plugin for IntelliJ , which was created mostly by the same JetBrains developers. It can be installed on almost any of their IDEs, including PhpStorm . For other IDE and text editors, visit the wiki page .

When you feel ready to create your first microservice on Go for production, I would advise you to take a look at the Go kit . This is a set of programming tools that tries to control the general problems of distribution systems, allowing developers to focus on business logic.

Less significant is the ability to create client-side JavaScript applications using GopherJS , as well as fully native or SDK applications for iOS and Android .

Source: https://habr.com/ru/post/277987/


All Articles