Developing libraries which need to persist data

Here comes a newbie design question when it comes to developing libraries which need to persist data.

As a hypothetical example, suppose we want to create a library which will be included in a Phoenix project to add certain capabilities, such as CMS-like functionality. This would entail persisting some data, like content pages, comment threads on content pages, etc.

I imagine that either A) the Phoenix application which includes the library will need to handle the database-related operations, or B) the library itself will include its own database somehow.

My current understanding/presumption is that A would be the more appropriate approach, and perhaps implementing some kind of protocol to which the consuming application must adhere.

When it comes to persisting data, what would be the best approach of developing such a library in a way that would make it clean and easy for other developers to include in their Phoenix projects?

IME the nicest is to use Ecto and allow providing the Ecto.Repo to use for queries (and migrations) to the init of your library. That way the application can decide where the repo lives (own database / shared, which backend, etc.) but your library can handle all the data storage. Please also namespace any tables (and other db artifacts) created/used by the library to avoid name collisions.

If you want to get really fancy the library could eventually offer other storage approaches (e.g. a NoSQL alternative) with Ecto being just one and offer that as a configuration option with different strategies implemented in separate modules in your librar, but I would resist that sort of complexity until really necessary :slight_smile:

1 Like

Many thanks for pointing me in the right direction, @aseigo! Much appreciated.

By any chance, do you happen to know of a library which does something like what you are describing, which I could take a look at to see how it should be done?

Random example: https://github.com/cpjk/canary

It retreives the Repo from config.exs, which is no longer recommended (in favor of run-time options, since app config is compile-time, and only allows one configuration even if you are using the library in multiple places). But other than that detail, you can see how it would work there, just imagine replacing the call to Application.get_env to get the repo module with code to take the Repo as a part of the options passed in to either the init of the application (if it is meant to be supervised) or as a param to functions

And in case you have not seen it, a useful resource that covers a number of library best-practice topics: https://hexdocs.pm/elixir/master/library-guidelines.html

2 Likes

Aha, very nice! Thanks for the example.

I had not seen that best-practice article either. That will be very useful!