This may be a more general question than just polylith, but this is the context that I'm working in, so here goes. Is there a convention about where you should initialize database tables and possibly seed them with data? For example, if I'm creating a database component, should I ensure the tables are created when that component is instantiated? Or is a better approach to have a schema component where each schema can be instantiated independently?
I have seen a few different examples, but I wasn't sure if there was a best practice.
I think it's better (safer) to have an explicit database migration project that can be run as needed.
At work, we have a migration project with a base, that is a CLI, and then a couple of components that deal with regular migrations (e.g., that you'd run in dev, CI, QA, production, ...) and dev-specific stuff that you'd run in dev/CI only.
Since the whole repo in Polylith is versioned atomically, then your deployment can always run the "current" migration artifact as part of that process, since it'll be in sync with your code by definition.
Do you use a specific tool for migrations?
If you're only building a single, deployable application/artifact, you could include the migration step as part of startup I guess, but I don't like the "magic" of that in general.
We started writing our migration stuff back in 2010 so it's custom. If we were starting over, I'd use Migratus I think.
One of the key decision points is how automated you want your migrations (to QA, production, etc) and also how you want to handle dev/test-only migrations (e.g., adding known test data). The former will include fixed metadata stuff, if your system needs it, since that'll need to go to QA / production. The latter should never go to QA / production.
Thanks! I'll check out Migratus. I've used a tool called Prisma before that has a built-in migration tool, but I don't think it has a Clojure client.
We have a table in the DB that tracks what migrations have been applied, and then we have a folder full of NNNNN*.sql files where NNNNN is just an increasing number. NNNNNdev*.sql files only get applied on dev/test envs. So it's pretty simplistic. Migratus is more robust and supports both up and down migrations (our system only does up migrations).
(we're at NNNNN = 00983 at this point 🙂 )
Part of why I started thinking about this is that I set up an H2 database instance for local development, but I'm wondering if it would be easier to just go ahead and setup a migration strategy to whatever database I want to ultimately use.
Probably PostgreSQL
I am a big fan of using the same database on all tiers. And there's a purely embedded PostgreSQL if you don't want to deal with a local install for dev/test -- see the :test deps in next.jdbc's deps.edn and the test fixture code that starts the in-memory PG instance.
Okay, I will definitely look at that. It sounds like it will be very beneficial to go ahead and get the database side of the project in place before I move on to other things.
At least sketch out the machinery for dealing with schema change over time. It'll make all your subsequent development easier.
Yup my project uses migratus, it's good. Rather than have migrations handled by a project, they're in the db component itself.. But after reading the idea of handling them in a project+base, I feel like that would have solved a few issues I encountered initially; and would help not just running migrations automatically every time the application starts (works for now but will cause issues later I'm sure). glad I read this discussion!