Database access from multiple packages.

688 views
Skip to first unread message

Shawn Milochik

unread,
Jul 19, 2014, 1:37:49 AM7/19/14
to golan...@googlegroups.com
Let's say I want to write an application, and have decided to decompose the functionality into individual packages for maintainability. These packages aren't going to be re-used by any other application -- they're all parts of a whole functioning system.

I want all these packages to use the same database. Looking at the database itself you'd see all the table names in one database, not necessarily realizing that they are owned by different packages which do not communicate with each other directly.

1. Do I share credentials to each package and let each make its own connection, or do I create a connection in package main and share that?

2. Regardless of the answer to #1, what is the best way to share? So far I think the best solution is to create some kind of RegisterDB function in each package, and have main's init() get the database info then call it for each package. An alternative I've thought of is to make a package that knows where to get the config file for the app, read it, and return either the connection info or an actual database connection. Then all of the packages would import that package and call it in their init() methods.

This seems like a need that must come up a lot in practice, but I wasn't able to find anything addressing this with a Google search and a search of this list's history, although it could be that the terms "share database connection multiple packages golang" aren't the right ones to use -- it mostly brings up results about connection pools and database driver packages.

Thanks for reading.

Chris Kastorff

unread,
Jul 19, 2014, 2:39:11 AM7/19/14
to golan...@googlegroups.com
I use a separate config package just for "globals" like this; it
includes variables for things like API secret keys, shared static file
paths, database connections, and database credentials. I initialize
those variables in main.main by parsing flags and env vars and then
opening a single database pool, before the dependent packages are used,
then all those packages just import and use the variables from the
config package.
> --
> You received this message because you are subscribed to the Google
> Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to golang-nuts...@googlegroups.com
> <mailto:golang-nuts...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout.

egon

unread,
Jul 19, 2014, 6:36:37 AM7/19/14
to golan...@googlegroups.com, Sh...@milochik.com
I would say pass in the connection/repository somehow, it makes testing and seeing the package outside effects easier. Also, if necessary, make them oblivious to what they are connected to by introducing a repository interface. e.g.

type Repo interface {
Add(*Item) (id int)
ItemById(id int) *Item
ListIems() []*Item
}

Then writing tests using mock Repo will be trivial. The Repo allows to easily switch out the persistance layer as well, e.g. instead of DB you can use the disk. Of course I'm not quite sure how complicated the database is, so the extra layer may be an overhead in code size.

+ egon

Shawn Milochik

unread,
Jul 22, 2014, 2:23:22 PM7/22/14
to golan...@googlegroups.com
Thanks to Chris and Egon for the suggestions. It sounds like there isn't one iron-clad "best" way to do it, and that I'll need to put more thought into the design and testing needs of the application and its API to find the best fit. 


Camilo Aguilar

unread,
Nov 18, 2014, 8:33:36 PM11/18/14
to golan...@googlegroups.com, sh...@milochik.com
What did you end up doing Shawn?

Shawn Milochik

unread,
Nov 18, 2014, 8:56:12 PM11/18/14
to golan...@googlegroups.com
The app hasn't been written yet for time reasons, but after more experience I'm planning to go with a "manager" interface, as demonstrated by Francesc here:

This also seems compatible with the approach Egon recommended, although I didn't get that aspect of it at the time. It's becoming clear that for ease of testing and refactoring this is the better approach.

If you consider testing and refactoring, the global approach isn't good. Passing in something that satisfies an interface just makes for a better codebase in general. This was reinforced by a couple of talks I saw at GothamGo this weekend. I'll post links once the videos are up (unless someone beats me to it).

Shawn

Camilo Aguilar

unread,
Nov 18, 2014, 10:04:56 PM11/18/14
to golan...@googlegroups.com, Sh...@milochik.com
I went with Chris's suggestion of having a config package and it worked quite well and it is pretty clean. Of course having interfaces between layers is also very convenient, but that's a different problem. 
Reply all
Reply to author
Forward
0 new messages