Employing interfaces and contracts

Interfaces are one of the best tools a software engineer can use. Once you expose something as an interface, you can freely change the implementation behind it. Interfaces are a construct that's being used within a single process. They are extremely useful for testing interactions with other components, which are plentiful in microservice-based systems. Here is one of the interfaces of our sample application:

type UserManager interface {
Register(user User) error
Login(username string, authToken string) (session string, err error)
Logout(username string, session string) error
}

The UserManager interface defines a few methods, their inputs, and outputs. However, it doesn't specify the semantics. For example, what happens if the Login() method is called for an already logged-in user? Is it an error? Is the previous session terminated and a new session created? Is it returning the existing session without an error (idempotent approach)? These kinds of questions are answered by contracts. Contracts are difficult to specify fully and Go doesn't provide any support for contracts. But, contracts are important and they always exist, even if only implicitly.

Some languages don't support interfaces as a first-class syntactic construct of the language. However, it is very easy to accomplish the same effect. Languages with dynamic typing, such as Python, Ruby, and JavaScript, allow you to pass any object that satisfies the set of attributes and methods used by the caller. Static languages, such as C and C++, get by with sets of function pointers (C) or structs with only pure virtual functions (C++).