Best structure to avoid import cycles in API server

526 views
Skip to first unread message

JohnGB

unread,
Sep 7, 2015, 2:02:02 PM9/7/15
to golang-nuts
In designing an API to avoid import cycles, I have one of two options structure wise, and I'm not sure which one is a better choice, as each have pros and cons.

Background
I'm only describing the two inter-related packages here, as those which are well encapsulated aren't an issue.  There is a user package that contains all the data that we store on a per user basis, as well as all the functions and HTTP handlers that are performed on any user.  There is also a message package that contains the structures and functions that are needed when one user sends a message to another user, or when system messages are sent to a user.  The message package also contains sub-packages for different push notification types (e.g. Google Cloud Messaging, Apple Push Notifications, etc.).

The import cycle problem is that sometimes when a message is sent, to a user, the result from the push notification server may state that the push notification settings for that user need to be changed.  But at the same time, some functions that may be performed on a user may trigger a message to a different user.

Solution 1
Include the code in the message package as part of the user package.  The downside here is that it makes the user package even bigger than it currently is, and somehow feels like it's more entangled than it needs to be.

Solution 2
Have some base package that has all the HTTP handlers in it, which can import both the user and message packages and hence can perform actions on both of them.  The downside to this is that all the handlers would only be able to use exported functions, and so there would be more exported functions than there currently are.

Is there a well proven best practice to handle this situation in Go?

Egon

unread,
Sep 7, 2015, 2:21:28 PM9/7/15
to golang-nuts
There are also potential solutions that use interfaces to abstract away the user generating a message, but without seeing the code hard to suggest anything specific.

Solution 1 would be a good choice if you are absolutely certain that it doesn't collect more packages.

Solution 2 sounds like you might be using getters/setters that shouldn't be there and instead there should be proper data-types. Although there might be other things as well that can cause such problems.

Both Solution 1 and Solution 2 sound like brute-force approach to getting rid of the circular-dependency instead of trying to model the situation without circular dependencies.

It would seem that there are some important packages missing that are the purpose of having message/user in the first place.

One design would be to move all the or core things to a separate package eg (or whatever makes more sense, eg.User, eg.Message, eg.Server etc. and then move interactions to separate contexts/packages. (see code in https://github.com/raintreeinc/knowledgebase/, kb contains all the core things, module contains additions to the core).

user and message basically seem wrong packages to me, it's hard for me to imagine a context where they have sufficient complexity and value to have a package of their own.

+ Egon
Reply all
Reply to author
Forward
0 new messages