Seed 2019-05-29

By Max Woerner Chase

One thing I noticed while working on Dennis was that I was dividing the code into different components, roughly per-module. Some code is responsible for displaying graphics, some is a generic implementation of a high-level design pattern, some is for generating fake events for testing purposes, some code is for generating fake events for testing purposes. It's hard for me to come up with a precise count, but nearly half of the source files would have general utility for game programming, in that I could imagine using them to make a game in a different "genre" than roguelike. This makes me think of trying to use the same code in multiple distinct projects, and thus think "How would I like to do that?"

The standard dichotomy for this question of coordinating this kind of reusable code is "monorepo" vs "multirepo". I don't want to rehash the pros and cons as applied to either an abstract repository that exists for rhetorical purposes, or a specific closed-source repository; there's plenty of both of those rundowns on the internet, as well as some open-source examples.

So, in Dennis, right now, there are several modules that have no in-project dependencies. These are potential candidates for factoring out into their own projects. Some of them are project-specific and just happen to not import stuff, so they shouldn't be broken out. (And maybe this is an indicator that some of their interface should be broken out within the project? I'm not sure.)

But suppose I go "You know what, this vector code seems pretty generic, and I'd rather not copy it around"... I'd want to create a new project containing the vector code, and if it somehow has other code, remove that code. Make sure the new project has a different name, and a fresh semver, get it working. Then, add a dependency on the new project, and remove the old code, get it working, and cut a new release of the original project.

In an internet-approved monorepo, each project is a directory under the repository root, and near as I can tell, semver isn't really a thing in the relevant workflows. I'm not sure anyone's laid out any "here's how you multirepo" guides in contrast to the "here's how you monorepo" ones, but here's something that occurred to me... The biggest friction I've had, that projects like cookiecutter are meant to deal with, is in bringing a fresh repository from "nothing" to "valid configuration for building". Doing that is a pain, it has a lot of busywork, so I would say that creating fresh repositories is hard. But, in a distributed world, in a world of Mercurial and Pijul, Darcs, Fossil, Bazaar, and, yes, Git, if you have one repo in a valid configuration for building, you have as many repos in a valid configuration for building as you want. Suppose the workflow for making a new project isn't based on init, cp, or mkdir, but clone?

What I'm visualizing is a collection of projects that all derive from a common "seed" repo that represents a minimal project. The "seed" repo should be in the paths config for all other repositories. In the event of collaboration, the "default" url should be the shared remote repo; I haven't thought too hard yet about how collaboration should actually work. So, tasks involved in this layout:

(Maybe I want to have a "seed" branch that is kept in synch between all repos, and merged into master?) (I'm moderately tempted to see how much effort it would take to formalize this on top of Pijul. Maybe avoid the topic-branch stuff. Do this with Pijul, and there's a seed repo that holds the common set of patches. Maybe use branches kind of like, okay, there's master, and release. Pushes and development hit master, builds are from release, and hm, I haven't thought this all the way through.)

Since I'm thinking about this for personal projects that I might or might not open-source all or any of, I'm going to focus on stuff I can set up up on my laptop.

Okay, I looked into Pijul a little more, and here's what I think I want whatever script I write, working title "seed", to do:

The high-level idea I have behind the configuration file is that, for a given task, such as "run tests", there should be a simple command to accomplish that.

Okay, this idea isn't all-the-way baked, but I think there's some potential in prototyping it. I'll give it a shot later.