This article is not for those who already write on go.
It is for programmers in other languages that are not interested in whether it is worth spending time on go.
What distinguishes go, for example, from java and how it can be useful.
Principles go
Once you could just take and create a new programming language.
Now the language has a chance to take some place only if it has clear principles, which its creators follow. In other words - own face.
The go principles are simplicity and productivity.
The principle of simplicity is:
If you can do without something, you need to do without it.
The principle of productivity:
The most valuable is the time spent by the developer. It should be minimized by all available means.
')
I will illustrate the principle of simplicity:
There are very few language constructs in go. For example, only one cycle. Go can be learned in two evenings.
The go refused from dynamic loading of libraries - the result of compiling one large executable file
There is no warning in go when compiled. Any incorrectness or verbosity is a compilation error.
The autoformat of a code at the level of the language is built in go. There is only one canonical view of go code.
Now a few examples of productivity:
The go code is 20-30 percent shorter than the similar one in Java (there are simply not superfluous words, for example, there is no semicolon at the end of each sentence, there are no parentheses in the condition or loop operators etc).
Go has a very fast compiler (a few seconds to compile a large project).
Productivity is not only the language itself, but also the standard tools supplied with it.
Productivity tools
Profilers
I'll start with a little digression about how I, a java programmer, came to use go.
I was doing a game project - a multiplayer space shooter.
Initially, I wrote the server part in java. She worked.
But very quickly everything came up against performance.
No more than 300 clients could be started on one server.
This is too small for the game to be profitable.
What could I do with this as a java programmer?
In fact, a little:
1) Using the gaze method, look for inefficient places in the code, try to correct them and, after each change, re-run load tests. This method is obviously ineffective.
2) Immerse yourself in the study of alternative server libraries, try different options. It also does not give any guarantees - perhaps problems in my own code, or even in the java language itself.
3) Finally, I could buy one or more paid profilers and try to get some information from them. But there are problems here. If we use a local server that is in our office, I could not create the necessary load, because we do not have the necessary number of free machines in our office to run several thousand clients. If you use an external server, then a rather complicated configuration was required to run the profiler there. Finally, the choice of a profiler is in itself a non-trivial task.
In go, this problem is solved very conveniently.
The profiler there is part of the language.
You can enable it on any server, and the result of its work is a file that can be downloaded to your machine and leisurely examined using very handy tools.
These tools will show exactly which lines of code spend the most memory and CPU cycles.
Their use makes it possible to quickly and efficiently find and fix all problem areas. (Which, by the way, almost always turn out to be not where you expect to find them.)
In my project, the server rewritten to go initially "pulled" only 20 clients (much worse than in Java). After working with profilers, this number increased to 2500.
Race detector
Another headache for all multi-threaded application writers is race conditions.
These are such elusive bugs that arise only if the stars converge in a certain way. That is, if the streams are launched in one order, there is a bug, if in the other it is not. And the order is unpredictable.
In go, there is a standard tool for solving this problem - race detector. If enabled, the go program will write to the log about all unsafe calls to shared memory from different threads.
Using the race detector, you can quickly and purposefully find and eliminate all problem areas.
Interesting designs
I do not intend to teach go programming and will not begin to disassemble all of its constructions. I want to dwell only on the three most interesting ones. All of them describe paradigms that are not in pure form in Java. And these paradigms are very useful.
These are interfaces, gorutiny and channels.
Interfaces
The go interface is similar to the interface in Java or c #. This is a set of method signatures, but without implementations.
The main difference is that go does not require declaring that some entity implements some kind of interface.
It is enough that the entity simply has all the necessary methods.
What does this give? Decoupling
You can take someone else's library. Find there an entity with some set of methods, create an interface with the same set and use this entity as this interface. You do not need to change someone else's code, do not tie your code to other entities, and do not need to write adapters, which are the classic boilerplate code. Another illustration of the principle of productivity.
Gorutiny
First, for multitasking applications in programming languages, processes were invented. They were heavy, had their own address space, and quickly "devoured" the resources of the system. Then came the threads (or threads). They were much easier and worked in the same address space. If the processes were usually run by units or tens, then threads could already have hundreds. However, with careless use and they could take away all the resources of the system. Each thread still occupied some resources, even if it was blocked.
To limit the number of threads, we started using thread pools.
Gorutinas can be thought of as tasks performed by one common large thread pool. In Go, the gorutines are extremely cheap. You can run millions of gorutin without problems for performance. The only requirement is that the gorutines must be “small”. That is, a gorutin should quickly do its job and either exit or block (which is the same thing from the point of view of the gorutin planner).
Channels
Channels are the racially correct means of communication between the gorutines.
In go there is an important rule:
Communicate by shared state. Share state by communication.
Its meaning - do not use variables to which more than one gorutina has access.
Instead, make the gorutines send data to each other.
This data transfer is just done through the channels.
A channel in go is a queue (buffer) at one end of which you can write and read from the other.
At the same time, the gorutin is blocked when trying to write to a crowded channel or read from an empty channel.
But the most interesting - go has a design for simultaneous reading from several channels.
Gorutina can list several channels on which she will sit and wait for a message to appear in one of them. Upon receiving this message, the gorutina is unlocked, processes it, and (usually) waits for the next message again.
So, for example, in the chat server of a gorutina can wait for both a message from the user and a signal about leaving the chat. At the same time.
Dependency management
Dependency management tools such as maven or gradle exist today for all serious languages.
Go went further and did support dependency management at the level of the language itself.
When importing a package (with a construction similar to import in Java), you can specify both the local name and the address of the package in any modern version control system (for example, in git).
For example, "github.com/gorilla/websocket"
Go will download the package itself and include it in your project. If a package has already been downloaded, it will simply be used. You can also ask go to upgrade all packages to their latest versions.
Here, however, there is one unpleasant moment - go always downloads the latest version of the package. If several people work on a project, this can lead to different versions of packages from different developers.
To solve this problem, use external tools - package managers.
One of the best to date - glide.
At the heart of glide are two actions:
1) Find all the dependencies of the project, and write them to a file
2) Download these dependencies
In this case, the file can be edited manually, indicating, if necessary, other versions of the packages (other than the last).
The GIT uses the commit identifier as a version identifier (in other version control systems, their specific identifiers are used).
Weaknesses go
Any principle has not only strengths, but also weak ones.
In go, in my opinion, there is one bad and one terrible thing, which flow from the principle of simplicity.
The bad is the lack of generics. Awful - error handling by checking the code returned by the function.
Without generics, you have to abandon strict typing.
And error handling leads to a large number of the same type of code. Which, besides, it is possible to forget to write at all and to leave an error raw.
In addition, following the principle of productivity, it was decided to enter into the go garbage collector. This is not bad in itself. But it is important to understand that this same collector will start every few seconds and noticeably slow down the system. With this, however, you can successfully fight.
findings
Should Java programmer go completely to go? Not. Anyway, bye. Java is on average faster. It has more useful libraries and established ways to create applications.
Should go be used to solve certain problems? Definitely worth it.
What tasks are best solved by go? Creation of multi-threaded high-loaded server solutions, in which the threads communicate with each other a lot.
Which language is better to learn a beginner - go or Yav? There is no definite answer, but over time there will be more and more arguments in favor of go.
The age of the language plays a role. Older language is overgrown with "historical" things. Something was added a long time ago, now nobody needs it, but it is impossible to throw it away, since backward compatibility will be broken.
Some constructions of the language or standard libraries, previously relevant, now look out of place, it seems more logical to do these unclaimed things outside the standard language.
For some standard problems accumulated a lot of alternative solutions of different quality. For a newbie, all this is a large amount of useless but necessary knowledge in the style: “Here you have to be especially careful. Here we have a puddle.
Go was created much later and today it contains everything that is in demand now and nothing superfluous.