Introduction

Last update: Nov 8, 2021

In 2011 i quit my job and started working as a full time freelancer. I was already taking on work for a couple of years before that but this seemed like a good moment for me to take this leap, which i already wanted to do for a while.

Most of my initial clients where seeking solutions that had a quite a bit of overlap but at the same time where completely different. Most of my work can be categorized as e-commerce software but usually with additional components specific to a certain production process or market or other requirements that make off the shelf products less suitable. So i decided to make something with a high degree of re usability, investing more time in abstractions and thereby hopefully increase my output in terms of both quality and productivity.

As it was my responsibility these stores, often my clients main source of income, kept working regardless of (breaking) updates from software vendors, i decided to build my own system. Even though many of my customers regularly question this choice, which i a very valid thing to question, even now in retrospective i still consider this one of the best choices made and my arguments for doing so still hold firmly in my believe system today. When you manufacture a car you know all it's bits and pieces, it's limitations, weaknesses and strengths. By doing so you grow a level of confidence about your product and services and the direction you are going in that is at least harder to achieve by using off the shelf products which also places both your and your clients destiny in the hands of some third party that may very well go bankrupt or just stop supporting the current version of their software which seemingly always happens at the least convenient moment in time.

A few years after the completion of version 1, which was somewhere around 2015. i decided that it was time to retire this version and start from scratch to incorporate a lot of new wishes and right from the start include all the (often hard) lessons learned while building version one. The landscape of course changes quickly and many of the tools and sub systems become somewhat outdated. At the moment of writing i still have a hand full of customers (mainly webshops) that operate on version one and without exception they are still very happy with their system and business it generates for them. With an average operational lifespan of 3 years for a webshop i am actually proud of the fact that these customers are still doing doing such good business on the outdated but safe code that i wrote such a long time ago. I still maintain their software and from time to time release some security updates but completely new functionality is only created on specific customer demand of course.

Architecture

Last update: Nov 8, 2021

Hurah is based on the MVC design pattern where all three of the basic components that make up this pattern are automatically generated based on the definition of the datamodel. During the code generation process all code is made up out of an abstract base layer which will be regenerated on each deployment and a customization layer for the developer to edit when certain unsupported behavior needs to be implemented.

The base layer is generated each time during deployment whereas the customization layer won't be touched after initial generation. This behavior is consistent everywhere in the application allowing the developer to zoom in and out the granularity of his or her modifications.

Because of the customization layer and underlying code generation process only a tiny fraction of the code needs to be committed to a version control system and as probably most developers know, less code generally speaking also means less bugs.

A transcending category of classes is generated during the code generation process which carries a range of interrelated features that operates in all three fields of the MVC pattern.

Responsibilities
  • User interface generation.
  • Form design tools.
  • A wide and extensible range of standardized UI components.
  • Design time checks (is this form logically possible?).
  • Design tools for collection containing views .
  • Generators for collection containing views .
  • Filtering, sorting, inline editing, inline adding and reporting features.
  • Configurable input validation on a per form, per field level.
  • Per form per field configurable specialized behaviors.
  • Access control on a per user or per group basis.
  • Standardization and transformation.
  • Add extensible support for generic high level data types.
  • Disclose and provide configuration options of API endpoints.
  • Expose form generation directives to external apps / applications .
  • Maintain, serve and inform about inter model relationships.
  • Event triggering and hooks.
  • Configurable and extendable event handling system.
  • Serve pre generated set of context aware commonly used event types.
  • Embedded context aware templating system based on (Twig) .
  • Decouples underlying storage mechanism.
  • Adds support for any of storage system or data source imaginable.
  • Provide support for virtual models.
  • Batch processing.
  • Design workflows.

Datamodel design

While the system is in essence datamodel independent, the code generation functionality was initially based on the schema definition description files of Propel ORM and still is compatible with this form of describing a datamodel. As time passed by and additional capabilities became required i had to make a decision about how to incorporate this into the system. The choice i made here was to fork the DTD file and by doing so have an easy path for backwards compatibility and simultaneously lean on a piece battle tested code, of course with the drawback of losing the capability to, more or less blindly, trust on incremental updates they provide. Fortunately we have composer and no additional components in the system have Propel as a dependency so pertaining this status quo has until now been without any effort.

Note: Propel ORM is still the object–relational mapping library of choice but it's functionality is now only a relatively small portion of the functionality that is generated based on this file.

ERD tool

Datamodel manipulation does not require manually editing an xml file anymore however. A visual representation of the datamodel with editing capabilities is also available for use. The entity relationship editor will generate an xml file for you and execute all the code generation features in the background allowing you to change the code base of the application from within the application it self.

Code structure

Last update: Nov 9, 2021

I am currently in the proces of decoupling as much code as i can and publish individual or logically grouped components into separate composer packages to lower the amount of external dependencies. This process is not going very fast but i am steadily making progress here. Each decoupled library is shipped with a sufficient amount of unit tests and before each release these tests validated trough the process of continuous integration offered by Circle CI. When any of the tests fail, the release is cancelled.