- The following is what the SOLID acronym initials stand for:
- Single responsibility
- Open/Closed
- Liskov substitution
- Interface segregation
- Dependency inversion
- The code conflates two responsibilities: retrieving/mutating the state of a document and creating a signature for the document's content. Furthermore, the proposed implementation is inflexible as it forces the use of a specific signing algorithm. To address this problem, we can remove the Sign method from the Document type and provide an external helper that can sign not only instances of Document but also any type that can export its content as a string:
- The idea behind the interface segregation principle is to provide clients with the smallest possible interface that satisfies their needs and thus avoid depending on interfaces that will not actually be used. In the provided example, the write method receives an *os.File instance as an argument. However, as the function implementation probably only needs to be able to write data to the file, we could achieve the same result by passing an io.Writer in the place of the *os.File instance. Apart from breaking the dependency to the *os.File concrete type, this change will also allow us to reuse the implementation for any type that implements io.Writer (for example, sockets, loggers, or others).
- The use of util as a package name is not a recommended practice due to the following reasons:
- It provides little context as to the package's purpose and contents.
- It can end up as the home for miscellaneous, possibly unrelated types and/or methods that would undoubtedly violate the single responsibility principle.
- Import cycles cause the Go compiler to emit compile-time errors when you attempt to compile and/or run your code.
- Some of the advantages of using zero values when defining new Go types are as follows:
- An explicit constructor is not required as Go will automatically assign the zero value to the fields of an object when it is allocated.
- The types can be embedded into other types and used out-of-the-box without any further initialization (for example, embedding a sync.Mutex into a struct).