===================================
 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