Let's consider your typical web application. In an MVC application, you may eventually want to introduce a "Service" layer that abstracts complex business logic such as user registration. So in your controller, you'd pass an instance of a services.User struct and simply call the Register() method on it.
Now, if services.User was simply a struct, we could have a relatively simple source code structure, like so:
- [other directories here]/
- services/
- user.go
- [other service structs here]
- main.go
And the services/user.go would look like so :
package services
type User struct { ... }
func NewUserService(){ ... }
func (u User) Register() { ... }
Which is all reasonably easy to read, so far. Let's say we take it one step further. In the spirit of making our web app easily testable, we'll turn all our Service structs into Service interfaces. That way, we can easily mock them for unit tests. For that purpose, we'll create a "AppUser" struct (for use in the actual application) and a "MapUser" struct (for mocking purposes). Placing the interfaces and the implementations in the same services directory makes sense - they're all still service code, after all.
Our services folder now looks like this:
- services/
- app_user.go // the AppUser struct
- [other services here]
- map_user.go // the MapUser struct
- [other services here]
- user.go // the User interface
- [other service structs here]
As you can tell, this makes the services package and directory a lot more difficult to handle - you can easily imagine how chaotic it would look with a dozen different interfaces, each of which at least have at least 1 implementation. If I change the User interface in user.go, I'd have to dart all across the directory listing to find all it's implementations to change, which is not at all ideal.
Additionally, it becomes pretty crazy when you type services.New(...) and you're greeted with perhaps 50 or so autocomplete suggestions ; the services package has become nothing but a shambling monster.
One of the simplest ideas I had to solve this is to go against convention and embrace repetition:
- services/
- userService/
- app.go // the AppUser struct
- map.go // the MapUser struct
- interface.go // the User interface
- [other services here]
This keeps all the UserService related code in a logical, self contained package. But having to constantly refer to userService.UserService is pretty darn ugly.
I've looked at all kinds of web application templates, and none of them (beyond the ones that are incredibly barebones) have an elegant solution to this structural. Most (if not all) of them simply omit interfaces completely to solve it, which is unacceptable.