preface
People outside the city want to go in, people in the city want to come out. — Qian Zhongshu, Fortress Besieged
With the growing popularity of Container Orchestration, Micro Services, Cloud Technology and other technologies in the IT industry, Golang (Go language, Go, for short, is increasingly popular with software engineers, making it a hot back-end programming language today. The list of software projects developed with Golang includes stars like Docker (container technology) and Kubernetes (Container Programming) that have upended the IT industry, There are also powerful and useful well-known projects such as Prometheus (monitoring system), Etcd (distributed storage), and InfluxDB (timing database). Of course, Go is by no means limited to containers and distributed systems. Golang is now widely used by many large Internet enterprises to build back-end Web applications, such as Toutiao, JINGdong, Qiuniuyun, etc. The framework crawler space, long dominated by Python, is being challenged by Golang with the rise of the simple and easy-to-use crawler framework Colly. Golang has become the programming language most software engineers want to learn today. Below is the result of HackerRank’s 2020 survey of programmer skills.
So is **Go really a lifesaver for backend developers? Does it improve the technical skills and productivity of programmers so that they can advance further in their careers? Is the Go language really worth spending a lot of time learning? ** This article will introduce the language features of Golang in detail as well as its advantages and disadvantages and application scenarios. With the above questions, IT will analyze all aspects of Go language for readers to help beginners in the IT industry and developers interested in Go to further understand this popular language.
Golang profile
It’s no coincidence that Golang was born at Internet giant Google. We all know that Google has a culture of doing 20% Side projects, allowing engineers to create disruptive innovations in an easy environment. Golang incubates during that 20 percent of the time. The founders of Go are some of the biggest names in IT, including Rob Pike, a member of the Unix core team, Ken Thompson, the author of C, and Robert Griesemer, a key contributor to the V8 engine. Go came to be known to the public after the explosion of container technology Docker, which was opened source in 2014. Since then, Go has become popular with many developers because of its simple syntax and rapid compilation speed, and many excellent projects, such as Kubernetes, have emerged.
Go has many advantages over other popular traditional programming languages, especially its high compilation speed and natural concurrency, which make it a preferred language for developing distributed applications quickly. Go language is a statically typed language, that is to say, Go language needs to compile like Java, C#, and has a complete type system, which can effectively reduce the code quality problems caused by type inconsistency. Therefore, Go is ideal for building large IT systems that require both stability and flexibility. This is why many large Internet companies use Golang to reconstruct old code: traditional static OOP languages (such as Java and C#) are stable but inflexible; Dynamic languages (such as PHP, Python, Ruby, Node.js) are flexible but lack stability. So it’s only natural that Golang, which has its cake and eat it too, is being embraced by developers. After all, Java/PHP/Python/Ruby has been suffering for a long time.
Go is not without its drawbacks, however. In a dialectic way of thinking, we can speculate that some of Golang’s salient features will be its double-edged sword. For example, Golang’s simple syntax will limit its ability to handle complex problems. In particular, Go’s lack of Generics has made it much more complicated to build a generic framework. While this glaring issue is likely to be addressed effectively in version 2.0, it also reflects the shortcomings of star programming languages. Of course, Go’s shortcomings don’t stop there. Go users also make fun of its verbose Error Handling, lack of strict Duck Typing, date formatting issues, and more. Below, we will make an in-depth analysis of the advantages and disadvantages of Golang and the application scenarios of the project from the superficial aspects to the profound aspects, starting from the language characteristics of Golang.
Language features
Concise syntax features
The syntax of Go is very simple, at least in terms of variable declarations, struct declarations, function definitions, and so on.
Variable declarations are not as verbose as in Java or C, and new variables can be declared in Golang using the := syntax. For example, when you define a variable directly with :=, Go automatically declares the assignment object’s type as the type from which the assignment came, saving a lot of code.
func main(a) {
valInt := 1 // Automatically infer the int type
valStr := "hello" // Automatically infer to string
valBool := false // Automatically inferred as bool
}
Copy the code
Golang also has many ways to save code. You can see that the new keyword is not mandatory in Go to generate a new Instance of a Class. Furthermore, conventions for public and private properties (variables and methods) are separated directly by the case of the first letter of the property variable, rather than using the traditional public and private keywords. The following examples can help readers understand these features.
// Define a struct class
type SomeClass struct {
PublicVariable string // Public variables
privateVariable string // Private variables
}
// Public method
func (c *SomeClass) PublicMethod(a) (result string) {
return "This can be called by external modules"
}
// Private methods
func (c *SomeClass) privateMethod(a) (result string) {
return "This can only be called in SomeClass"
}
func main(a) {
// Generate an instance
someInstance := SomeClass{
PublicVariable: "hello",
privateVariable: "world",}}Copy the code
If you implement this example in Java, you might see lengthy.java class files, such as this one.
// SomeClass.java
public SomeClass {
public String PublicVariable; // Public variables
private String privateVariable; // Private variables
// constructor
public SomeClass(String val1, String val2) {
this.PublicVariable = val1;
this.privateVariable = val2;
}
// Public method
public String PublicMethod(a) {
return "This can be called by external modules";
}
// Private methods
public String privateMethod(a) {
return "This can only be called in SomeClass"; }}...// Application.java
public Application {
public static void main(String[] args) {
// Generate an instance
SomeClass someInstance = new SomeClass("hello"."world"); }}Copy the code
It can be seen that in Java code, in addition to the multilayer curly brackets that are easy to see, there are also a large number of public, private, static, this and other keywords used to modify, which seem unusually wordy; The Golang code, on the other hand, relies on simple conventions, such as capitalization, to avoid many repetitive modifiers. Of course, there are some differences in the type system between Java and Go, which can lead to Go’s inability to handle complex problems, which will be discussed later. In summary, the conclusion is that Go’s syntax is very concise in statically typed programming languages.
Built-in concurrent programming
Aside from its powerful performance, the main reason why Go is the preferred language for distributed applications is its natural concurrent programming. This concurrent programming feature comes primarily from Goroutines and channels in Golang. Here is an example of using coroutines.
func asyncTask(a) {
fmt.Printf("This is an asynchronized task")}func syncTask(a) {
fmt.Printf("This is a synchronized task")}func main(a) {
go asyncTask() // Execute asynchronously without blocking
syncTask() // Execute synchronously, block
go asyncTask() // Wait for the previous syncTask to complete and then execute asynchronously without blocking
}
Copy the code
As you can see, the keyword go plus function call allows it to be executed as an asynchronous function without blocking subsequent code. If the go keyword is not included, it is treated as synchronous code execution. If you are familiar with the async/await, Promise syntax in JavaScript, or even multithreaded asynchronous programming in Java and Python, you will find that they are not on the same order of magnitude as Go asynchronous programming!
Communication between asynchronous functions, or coroutines, can be implemented using channels specific to the Go language. Here is an example of a channel.
func longTask(signal chan int) {
// for with no arguments
// is equivalent to the while loop
for {
// Receive signal channel transmission
v := <- signal
// Stop the loop if the received value is 1
if v == 1 {
break
}
time.Sleep(1 * Second)
}
}
func main(a) {
// Declare the channel
sig := make(chan int)
// Call longTask asynchronously
go longTask(sig)
// Wait 1 second
time.Sleep(1 * time.Second)
// Pass the value to the channel SIG
sig <- 1
// longTask will then receive the sig value and terminate the loop
}
Copy the code
Interface oriented programming
Go language is not strict object oriented programming (OOP), it adopts interface oriented programming (IOP), is a more advanced programming mode than OOP. As part of the OOP architecture, IOP puts more emphasis on rules and constraints, as well as conventions for interface type methods, allowing developers to focus as much on more abstract program logic as possible, rather than wasting time on more detailed implementations. Many large projects use the IOP programming model. If you want to learn more about interface programming, check out the code Path personal technology blog’s previous post, Why TypeScript is a Necessary Language for Developing Large front-end Projects, for a detailed explanation.
Go, like TypeScript, uses duck typing to verify interface inheritance. The following example illustrates the duck type nature of the Go language.
// Define the Animal interface
interface Animal {
Eat() // declare the Eat method
Move() // Declare the Move method
}
// ==== defines Dog Start ====
// Define the Dog class
type Dog struct{}// Implement the Eat method
func (d *Dog) Eat(a) {
fmt.Printf("Eating bones")}// Implement the Move method
func (d *Dog) Move(a) {
fmt.Printf("Moving with four legs")}// ==== defines Dog End ====
// ==== define Human Start ====
// Define the Human class
type Human struct{}// Implement the Eat method
func (h *Human) Eat(a) {
fmt.Printf("Eating rice")}// Implement the Move method
func (h *Human) Move(a) {
fmt.Printf("Moving with two legs")}// ==== define Human End ====
Copy the code
As you can see, although the Go language can define interfaces, unlike Java, the Go language does not display the keyword modifier syntax for declaring interface implementations. In Go, if you want to inherit an interface, you just implement all the methods declared by that interface in the structure. This way, to the Go compiler, you define a class that inherits the interface. In this example, we say that anything that can both Eat and Move is an Animal. Both dogs and humans happen to be able to eat and move, so they are both counted as animals. This inheritance, which relies on the compatibility of the implementation, is the duck type: if an animal looks like a duck and sounds like a duck, it must be a duck. This duck type is more flexible than traditional OOP programming languages. However, as we will discuss later, this approach to programming can cause some problems.
Error handling
The Go language’s error handling is notoriously verbose. Here’s a simple example.
package main
import "fmt"
func isValid(text string) (valid bool, err error){
if text == "" {
return false, error("text cannot be empty")}return text == "valid text".nil
}
func validateForm(form map[string]string) (res bool, err error) {
for _, text := range form {
valid, err := isValid(text)
iferr ! =nil {
return false, err
}
if! valid {return false.nil}}return true.nil
}
func submitForm(form map[string]string) (err error) {
ifres, err := validateForm(form); err ! =nil| |! res {return error("submit error")
}
fmt.Printf("submitted")
return nil
}
func main(a) {
form := map[string]string{
"field1": ""."field2": "invalid text"."field2": "valid text",}iferr := submitForm(form); err ! =nil {
panic(err)
}
}
Copy the code
While the entire code above is fictional, you can see that the Go code is riddled with if err :=… ; err ! = nil { … } and so on. This is because the Go language requires the developer to manage errors themselves, meaning that errors in functions need to be explicitly thrown, otherwise the Go program doesn’t do any error handling. Because Go does not have the try/catch syntax for error handling in traditional programming languages, it lacks flexibility in error management, leading to the situation of “Err flying everywhere”.
However, the law of dialectics tells us that this approach also has advantages. First, it forces Go developers to regulate error management at the code level, which drives developers to write more robust code. Second, this explicit error return avoids the temptation to “try/catch a shuttle,” which can lead to bugs that can’t be accurately located, resulting in unpredictable problems. Third, because there are no try/catch parentheses or extra blocks of code, the Go code looks cleaner and more readable overall.
other
Go language certainly has many other features, but the author believes that the above features are more distinctive in Go language, and are relatively strong distinguishing characteristics. Other features of Go include, but are not limited to, the following.
- Compile quickly
- cross-platform
defer
Delay theselect/case
Channel selection- Compile directly into an executable program
- Unconventional dependency management (you can refer directly to the Github repository as a dependency, for example
import "github.com/crawlab-team/go-trace"
) - Unconventional date format (“2006-01-02 15:04:05”, you read that right, it is said to be the founding date of Golang!)
Advantages and Disadvantages
Given the many language features of Go, you should already have a basic understanding of Golang. Some of the language features also hint at its strengths and weaknesses relative to other programming languages. Go language is hot right now, but while praising and embracing Golang, you have to understand some of its shortcomings.
I’m not going to Go into a lengthy analysis of the pros and cons of Go, but here are some relevant facts, so you can decide for yourself. Here is an incomplete list of the pros and cons of Golang’s language features.
features | advantages | disadvantages |
---|---|---|
Grammar is simple | Improve development efficiency and save time | Difficult to deal with some complex engineering problems |
Naturally supported concurrency | Greatly reduce the difficulty of asynchronous programming, improve development efficiency | There are some learning costs for developers unfamiliar with channels and coroutines |
The type system |
|
|
Error handling | Enforce constraint error management to avoid”try/catch A shuttle” |
Verbose error handling code, full ofif err := ... |
Compile quickly | That’s definitely a plus | How can it be a weakness? |
Unconventional dependency management |
|
It relies heavily on Github, where searching for Go language modules is relatively imprecise |
Unconventional date format | Follow 6-1-2-3-4-5, which is relatively easy to remember | For developers accustomed to the YYYY-MM-DD HH: MM: SS format, this is not very comfortable |
In fact, each feature has its corresponding advantages and disadvantages in a certain situation, and cannot be generalized. Statically typed and interface oriented programming, like Go, is a modern programming language between dynamic and traditional statically typed OOP, neither lacking in type constraints nor as verbose as strict OOP. This position, while making Golang more efficient, also eliminates the need for OOP syntax features, and thus lacks the ability to quickly build generic engineering frameworks (not that Go can’t build generic frameworks, but it’s not as easy as Java or C#). In addition, Go developers love or hate the language’s “weird” error-handling practices: they can create more robust applications, but at the expense of some code simplicity. Remember, Go was designed to be “simple,” and therefore designed to be as simple as possible while pursuing high performance.
There is no denying that the concurrency support built into the Go language is a very innovative feature of recent years, which is why it has been widely adopted by distributed systems. At the same time, it is very fast compared to Java, which can compile in ten minutes. In addition, Go does not sacrifice stability for simplicity of syntax; Instead, it formalizes the entire Go project code style from simple constraints. Thus, ** “Fast,” “Concise,” “Robust” ** are the design goals of Go. In the process of learning Golang, we should not mindlessly accept everything about it, but should judge its application in practical projects according to its own characteristics.
Applicable scenario
From the previous discussion of Golang’s dimensions, we can conclude that Go is not a panacea for back-end development. In actual development, developers should avoid using Golang as a back-end development language mindlessly under any circumstances. Instead, engineers should fully understand all aspects of a candidate technology (language, framework, or architecture), including its relevance to business needs, its integration with the development team, and its learning, development, and time costs, before deciding on a technology. After learning some programming languages including the front and back end, the author found that they have their own advantages and corresponding disadvantages. A programming language is never a bad language if it is widely known. Therefore, the author will not assert that “XXX is the best language in the world”, but share with the reader personal thoughts on technology selection for specific application scenarios. Of course, this is a technical article for Go, so I’ll share some of the scenarios where I think Golang is best used.
Distributed application
Golang is well suited for distributed application scenarios. The main goal of a distributed application is to maximize the overall performance and efficiency of the system by using as many computing resources and network bandwidth as possible. Go is a leader in supporting highly concurrent and asynchronous programming. As mentioned earlier, Go has two concurrency features built into it, Goroutine and Channel, which make asynchronous programming very easy for back-end developers. Golang also includes the sync library, which includes Mutex (Mutex), WaitGroup (WaitGroup), and Pool (temporary object Pool) interfaces to help developers safely control the concurrent behavior of Go applications in concurrent programming. Golang also has many distributed application development tools, such as distributed storage system (Etcd, SeaweedFS), RPC library (gRPC, Thrift), mainstream database SDK (Mongo-Driver, Gnorm, Redigo), etc. All of these can help developers effectively build distributed applications.
Web crawler
Developers who know anything about web crawlers have probably heard of Scrapy, or at least Python. There are numerous technical books on Python web crawler in the market, such as Cui Qingcai’s Python 3 Network Development Practice and Wei Shidong’s Python 3 Web Crawler’s High performance crawler framework Scrapy, which has been the first choice of crawler engineers since its release.
However, due to the recent rapid development of Go, more and more crawler engineers have noticed the great advantages of developing web crawlers with Golang. Among them, the Colly crawler framework written in Go language now has 13K + star on Github. Its concise API and efficient collection speed, attracted many crawler engineers, occupy a part of the crawler world’s top Scrapy share. As mentioned above, the built-in concurrency feature of Go language makes crawler programs that rely heavily on network bandwidth more efficient and greatly improves the data collection efficiency. In addition, as a static language, Go has better constraints than Python, which makes it more robust and stable.
The backend API
Golang has many excellent back-end frameworks, most of which fully support the functional requirements of modern back-end systems: RESTful apis, routing, middleware, configuration, authentication, and more. Also, backend applications written in Golang perform very well, often with very fast response times. The author used Golang to rebuild Python’s back-end API in Crawlab, an open source crawler management platform, and the response speed was optimized from hundreds of milliseconds to tens of milliseconds or even a few milliseconds. The practice proved that Go language completely overtakes dynamic language in terms of back-end performance. Some of the best-known backend frameworks in Go are Gin, Beego, Echo, Iris.
Of course, this is not to say that writing the back end in Golang is the right choice. The author will use Java and C# in his work. After using their respective mainstream frameworks (SpringBoot and.net Core), I found that although these two traditional OOP languages have long-winded syntax, their syntax features are very rich, especially generics, which can easily deal with some business requirements with complex logic and high repeatability. Therefore, I think it’s a good idea to look into Java or C# when considering writing back-end apis in Go, which do a great job of writing back-end business functions.
conclusion
This article starts with the main grammatical features of Go language, and analyzes the advantages and disadvantages of Go language as a back-end programming language step by step, as well as its trial scenarios in actual software project development. The author believes that the main differences between Go language and other languages lie in simple syntax, natural support for concurrency, interface oriented programming, error handling and other aspects, and analyzes the positive and negative aspects of each language feature. Finally, according to the previous analysis, the author concluded the application scenarios of Go language as a back-end development programming language, that is, distributed applications, web crawlers and back-end APIS. Of course, the practical application of Go goes beyond that. In fact, Golang has been used to develop several well-known databases, such as the timing databases Prometheus and InfluxDB, and TiDB, also known as NewSQL. In addition, Go also has some advantages in machine learning, but for now, Google doesn’t seem to be promoting Go in machine learning because of Swift’s intention to work with TensorFlow, but some potential open source projects are emerging. Examples include GoLearn, GoML, Gorgonia, etc.
While understanding the advantages and scenarios of Go, it is important to realize that Go is not all-powerful. It also has some disadvantages compared to other mainstream frameworks. Developers preparing to adopt Go as a working development language need to fully understand its language features to make the most appropriate technology selection. Just like playing tennis, it is necessary to master not only forehand and backhand, but also serve, high pressure ball, volley and other technical movements, so as to play tennis well.
community
If you are interested in the author’s article, you can add the author’s wechat tikazyQ1 and mark “code of Tao”, and the author will pull you into the “code of Tao” communication group.