2. Best practices for writing neat and maintainable go code

Keywords: Java Go R Language

Writing neat and easy to test and maintain code is very simple at first glance, but it is not easy to do in practice. Fortunately, the birth of go language is accompanied by a set of best practices for us to learn and refer to.

In my experience, these best practices have a positive effect on code quality measurement and can reduce the increase of technical debt.

This chapter will start with the following topics:

·Understand SOLID principle from go Perspective

·Organize code from package level

·Some suggestions and tools for writing maintainable code

SOLID principle of object-oriented design

SOLID is a collection of 5-tone principles. Its full name is:

·   Single responsibility   Single responsibility

· Open/closed   Opening and closing principle

·Liskov substitution

·Interface aggregation interface isolation

·Dependency inversion dependency inversion

Single responsibility

Description of SRP:

『In any well-designed system, objects should only have a single responsibility.』

"In a well-designed system, the responsibility of each object should be single, unified and clear"

In short, the functional implementation of objects should be focused and efficient. Focus represents focus and single function; How can we be efficient? Small and United can be efficient. If the functions are too complex, they will be messy and inefficient.

The following is a negative example of the UAV distribution system. The following fragment is a collection of methods for trying to define the UAV type at the beginning:

// NavigateTo applies any required changes to the drone's speed // vector so that its eventual position matches dst.
func (d *Drone) NavigateTo(dst Vec3) error { //... }
// Position returns the current drone position vector. 
func (d *Drone) Position() Vec3 { //... }
// Position returns the current drone speed vector. 
func (d *Drone) Speed() Vec3 { //... }
// DetectTargets captures an image of the drone's field of view (FoV) using // the on-board camera and feeds it to a pre-trained SSD MobileNet V1 neural
// network to detect and classify interesting nearby targets. For more info // on this model see:
// https://github.com/tensorflow/models/tree/master/research/object_detection 
func (d *Drone) DetectTargets() ([]*Target, error) { //... }

The above code violates the SRP because it mixes cruise capability and image recognition capability into one responsibility.

This example may be feasible, but coupled with image recognition, it is more difficult in the sense of maintenance. For example, I want to change another neural network model to evaluate the impact on image recognition results. What should I do? I want to apply this recognition algorithm to other types of UAVs. What should I do?

How to apply SRP to transform the above code? The premise is to assume that all UAVs are equipped with a camera, so that a method can be developed for UAV photography and image output. Speaking of this, you might say that taking photos and cruising are also two functions? It is true, but this is entirely the difference in understanding caused by different angles of thinking. The description and assignment of the responsibility of an object is the core of the principle itself, and it is very subjective. This subjectivity is based on everyone's coding experience. You can put it another way. The cruise of UAV depends on various sensor data, and taking photos is the data.

In the second step, the code of image recognition is abstracted as a method of neural network. The methods of the remaining UAVs have not changed much, as follows:

// NavigateTo applies any required changes to the drone's speed vector // so that its eventual position matches dst.
func (d *Drone) NavigateTo(dst Vec3) error { 
//... 
}
// Position returns the current drone position vector. 
func (d *Drone) Position() Vec3 { 
//... 
}
// Position returns the current drone speed vector. 
func (d *Drone) Speed() Vec3 { 
//... 
}
// CaptureImage records and returns an image of the drone's field of // view using the on-board drone camera.
func (d *Drone) CaptureImage() (*image.RGBA, error) { 
//... 
}

Another file (perhaps in another package) defines a MobileNet type, which contains the methods to realize image recognition:

// MobileNet performs target detection for drones using the
// SSD MobileNet V1 NN.
// For more info on this model see:
// https://github.com/tensorflow/models/tree/master/research/object_detection 
type MobileNet {
// various attributes... 
}
// DetectTargets captures an image of the drone's field of view and feeds // it to a neural network to detect and classify interesting nearby
// targets.
func (mn *MobileNet) DetectTargets(d *drone.Drone) ([]*Target, error){
//... 
}

In this way, the two responsibilities are clearly separated, or even physically separated into two documents to form a single responsibility.

Open/Close principle

Posted by SystemLord on Fri, 08 Oct 2021 20:21:55 -0700