Hello, you may have seen my blog go quiet for a while. After two years of a global pandemic, I decided to take some more time with my family and also offload some knowledge and responsibilities around the Maintaina Horde codebase to my fellow team members at B1 Systems. I also took some time considering some very fundamental Horde design implications. One of these is horde/core.
You can use the Horde Framework and its libraries in two different styles. The first style I would call loosely coupled. Most libraries try to depend on as few as possible other horde libraries and concentrate on specific purposes. That makes them reusable outside of the wider context of the framework. For example, the backend for Michael Rubinsky’s blog uses the Horde Router, the Horde Controller library and the Horde Injector DIC as a kind of micro framework without much supporting code. A custom binder simulates setup of view paths normally performed by a horde environment.
The alternative is the “horde app” use case or tightly integrated use case. Your site will have a horde base app providing common capabilities and one or multiple modules or horde apps. They integrate with a framework-generated topbar, can use an inter-app API, react to a common styling choice etc. Developers benefit from being able to reuse solutions for preference storage and UI, configuration, permissions, user groups, predefined callbacks for webdav, rpc, language and presentation handling etc. This is all great if you just want to build some addon to your Horde Groupware installation. In other cases, Horde’s base does a lot of stuff you do not really need or want. I want to change that.
The horde/core library started out as a spinoff off the horde base app. It contains a lot of glue for putting together backends, drivers, config files, caches and it also provides base classes needed by the horde applications. The horde base app contains the endpoints for RPC, route-based UI, webdav, caldav. It also contains a micro bootstrapping file called horde/lib/core.php. This file installs an error handler, sets up some basic PHP sanity stuff, does some magic around Horde’s own autoloader, defines some constants and hooks into horde/config/horde.local.php, allowing the admin to inject some early-init custom magic. Our horde-installer-plugin for composer makes use of this hook to setup the composer autoloader (and some more constants) in a backward compatible way.
I think, outside of support for old-style code bases, none of this should happen. But our current implementation of the controller framework still depends on that magic and uses code in horde/core which also depends on it. In pre-composer environments, horde needs some tricks to find out basic facts about where it is, where everything else is, how to setup autoloading etc. In modern environments, we should neither pollute the global namespace with constants and global variables nor should we have an involved, tightly coupled setup process way before we even look at the app and route called for. We need to reorder how and when things are done.
Both developers and runtime operators benefit from this redesign. Developers can reduce boilerplate when relying on much, but not all of the Horde Framework and not exactly building a module for a horde installation. They are less entangled in conventions which do not make sense anymore. Operators will notice a lower memory, i/o and computation footprint, resulting in higher speed. This is because we throw out a lot of overhead unrelated to the current call. In the old setup we even created an IMAP connection when the current user was forbidden to use the mail component and the screen shown was for changing passwords or handling preferences. Yes, even when downloading an addressbook you would have triggered and IMAP connection handshake. We do not need that and by now, we have to tools to avoid it.
Stay tuned for more details in upcoming articles.