=================================== Useless code, part 2: the bit rot =================================== Almost 4 years ago I wrote here about some mostly useless and annoying code. It wasn't developed actively during that time, but now it's back, together with bit rot! Initially it was a basic CRUD web thingy, but one of the unexpected tasks was to allow selecting all the entities (from the corresponding database tables) using any combination of the fields of all the directly related entities. That was particularly awkward, since this project is in Haskell, using the Servant framework: all the endpoints are typed (and then Swagger/OpenAPI specification is generated), so the choices I had were to either list and handle hundreds of parameters manually, or to somehow generate them. And I did the latter, somehow, relying on the framework internals, Generics.SOP, and probably something else. It didn't seem maintainable at the time, and it's one of the major parts I disliked about the project, but it still felt better than handling of hundreds of parameters written manually. The current Debian stable repositories provide a compiler (and corresponding standard library) version newer than the old version of the framework accepts, and the newer framework versions changed the internals, apparently requiring a rewrite of that part, not a mere adjustment. Some other parts have also changed, but that's perhaps the largest and the most annoying one. And now some additional--though basic, as the whole project was supposed to be--functionality is needed. Once again I proposed to use PostgREST, learned that frontend is being rewritten anyway, so it's a good time to switch to that; possibly the switch will happen, but the changes are needed before that, with the old frontend. So I ended up adding some properties without local typechecking, building it on a machine with the old system and compiler. Then received credentials for deployment, but the target machine had Debian 11 (the current stable), with different shared library versions. Building everything statically didn't work easily, at least because of the dependency on systemd (used for logging by a library; actually I mentioned it recently, in the "packaging and logging" post), so I just added more systemd until it worked: systemd-nspawn is rather convenient in combination with debootstrap and ``VirtualEthernet=no``, and I'm running that program in a Debian 9 container. Just when I thought that it's almost the time to relax and wait for the new frontend that would use PostgREST, at which point I'd remove all the annoying bits from the backend and update it to build with newer dependencies, and things will probably be almost fine there, I noticed a couple more tasks: more functionality is needed (some computations to do on the backend, to avoid passing more data than necessary to the frontend), and the data should be collected from a source that doesn't provide the data which is mandatory (and used in computations, not just a matter of making it nullable/optional). Possibly will have to pretend that it's a fixed value, which would likely be a problem in the future, or attempt to change it somehow, through all the current awkwardness. Seems like there should be some lessons to learn from it. Perhaps it was a mistake to not set PostgREST from the beginning, though I didn't know about it at that point, and didn't expect the backend to grow complex enough to justify that. As for changing structures, in the ways that are both unexpected and tricky to apply, that's a fairly common issue, even without web-related projects: often there is a bunch of different data models for basically the same data, which you are supposed to connect/unify somehow, with new ones appearing regularly, requiring adjustments of the unified model. Even an RDF ontology (and a triplestore) isn't necessarily a good way to handle that, and that's likely to be awkward to work with. I could have used Haskell stack/Stackage, and/or even developed in a container, but that comes with its own issues, and doesn't really solve the problem: nice software works on different systems and updates when necessary, and doesn't require such hacks. Diving into framework internals certainly messed that up for me this time, introducing quite a bit of technical debt -- but then again, it was hard to avoid at the time when that came up, and I didn't like it back then either. Possibly defining and handling those hundreds of parameters manually instead of generating them would have been somewhat better in the long run, though that would be pretty awkward. Well, at least now there is some hope for PostgREST, reducing the number of annoying and unnecessary custom endpoints (though still leaving some), and hopefully leading to at least a buildable project. ---- :Date: 2022-10-14