basis

Programming is solving problems. A program is essentially a collection of problem-solvers which in-turn solve smaller real-life problems.

Take for example restaurants. Restaurants’ main objective is to sell food for as many people as possible. However, since restaurants want to sell to as many people as people their human workers often disappoint due to human short-term memory limitations. A solution to this problem that could reduce costs and increase revenue is to have a simple program run on their computer to keep track of all orders. Thereby reducing the accuracy mistakes and providing more stability to the restaurant.

interfaces

An interface is a way that a program can create a specific pattern of data structures. Suppose you have a data-structure of a football. The football contains its length and its parent game (football). Well, a lot of games have balls, so why limit your function or problem-solver to a single type of data structure when you can allow for more?

That’s where interfaces come in. Interfaces will allow your program to be flexible by re-using clear patterns. They also allow you to specify and be as cohesive as possible with data structures. Your data structures will contain the guts and interfaces will be the specification.

testing

One thing I extremely like about interfaces is that, due to their simplicity, you can essentially implement mocks to use in testing units. Why connect to an actual MySQL database to fetch mock items when you can implement a mock database.

Testing with interfaces is a lot more palatable because you don’t have to re-implement real-world states and instead focus on specific situations. Which ties into functional programming.

functional programming

Functional programming is a style of programming in-which no single function can mutate another. Instead functions take an input and produce an output without modifying the input by itself.

Which means:

// bad
func LoadDatabase(f os.File) {
	globalDatabase = Database{}
}
// good
func LoadDatabase(f os.File) Database { 
// ....  
}

The reason why this is so important is because by having virtually no mutations, you will not face side effects that are brought up only in production. There are some situations where you could use mutations to better the program even more.

An example of using mutations to your advantage would be efficient caching. Suppose you wanted to implement the factorial algorithm, that is

$$ 6! = 6 * 5 * 4 * 3 * 2 * 1 $$

You could use caching, which is technically mutating, to improve your algorithm’s results. So, instead of it re-computing the same result every single time, it just fetches it from memory which is a lot more time efficient than re-computing it.

Even then, you’d probably be better off with an additional function that returns the computation or a cached version so that you can better debug your program.