Softwaregeneratie


pijl schuin blauw naar transparant
Bij AFAS werken we aan de nieuwe versie van ons ERP-product Profit. Behalve dat we voor deze nieuwe versie een CQRS-architectuur gebruiken, is er nog een punt waarin deze nieuwe versie behoorlijk verschilt van de huidige versie. Profit Next wordt namelijk niet door ontwikkelaars geprogrammeerd, althans niet direct. Bij de afdeling Architecture en Innovatie (A&I) doen we aan softwaregeneratie: we schrijven software die software maakt. Softwaregeneratie is geen nieuw concept, veel bedrijven passen met verschillende maten van succes softwaregeneratie toe .

In de ICT-wereld heerst er echter wel een zeker scepticisme over software generatie. Het blijkt toch zeer moeilijk te zijn om een software generator te bouwen die echt ‘snapt’ wat de modelleur/ontwerper bedoelt, en genoeg gedrag kan genereren zonder weer in een programmeertaal te verzanden. Een van de eerste pogingen om een software generator te maken had dan ook de toepasselijke naam “The last one”. Als in, het laatste programma ooit geschreven door een persoon. Helaas zagen de mensen in 1981 dit toch echt anders, en kwam een wereldwijde adoptie hiervan niet van de grond. In dit stuk leggen we uit hoe AFAS deze uitdaging benadert en welke keuzes we onderweg hebben gemaakt.

Waarom

AFAS Profit de software die Next uiteindelijk gaat vervangen is een groot product, het bevat ruim 20 jaar aan software ontwikkeling en miljoenen regels code. Om dit product volledig in een klein aantal jaar opnieuw te schrijven is een enorme klus.  Dan is het makkelijker, om over 10 jaar opnieuw een nieuwe versie gaan uitbrengen. Dit doen we door de functionaliteit los te trekken van programmeertaal of tools, door deze beschrijving te definiëren. Dit houdt in dat wanneer we switchen van technologie of architectuur, we alleen die onderdelen van de generator hoeven te vervangen.

Deze klus wordt door een relatief klein team opgepakt. Wat we willen doen is automatisering automatiseren. Want waarom zouden we alleen andere beroepsgroepen proberen weg te automatiseren? In de ICT kunnen we dat ook.

Maar hoe werkt dat dan?

De modelleur gebruikt Studio, de ontwerpomgeving voor Profit Next, om een applicatie model te maken. Hier komt een applicatie definitie uit. Dit is een Platform Independent Model (PIM), wat een beschrijving is van het proces of bedrijf waar wij de software voor genereren, maar wat geen beschrijving is van de software zelf. De applicatie definitie bevat bijvoorbeeld geen keuzes over de UI, of hoe de architectuur van deze applicatie moet zijn. Dit klinkt ook heel raar in de oren, een domein expert zal waarschijnlijk niks weten over goed UI-design, of technische infrastructuur. Deze keuzes worden niet door de modelleur gemaakt, maar in de generator bepaald op basis van patroonherkenning. We leggen de PIM neer als een pure beschrijving van het bedrijf en de processen die we met de gegenereerde software modelleren.

Generator

Na het modelleren van de software wordt de PIM als definitie opgeslagen en is het beschikbaar als input voor de software generator. Deze PIM bevat de minimale informatie die nodig is om de software te genereren en moet eerst worden verrijkt voordat we er echt code mee kunnen genereren.

Bij het inlezen van het PIM in de generator worden er dus eerst een aantal verijkingsfases uitgevoerd. Het model wordt gecontroleerd op consitentie, niet actieve modelelementen worden verwijderd. Met behulp van patronen worden technische eigenschappen toegevoegd die nodig zijn in verdere fases. Verder worden berekende eigenschappen geanalyseerd, en hun dependencies bijgehouden. Aan het einde van de verijkingsfases is er een model ontstaan dat toegespitst is op is om een software applicatie te genereren.



Na het verrijken wordt de verrijkte PIM aan meerdere modelbuilders meegegeven. Doel van deze modelbuilders is om voor hun specifieke onderdeel van PIM naar een Platform Dependent Model (PSM) te gaan. De verrijkte PIM beschrijft de gehele applicatie, maar we willen dat beide PSM’s de deelgebieden beschrijven. Deze opdeling van deelgebieden is niet op basis van functionaliteit. De generator is agnostisch qua implementatie: het technische verschil tussen componenten is klein. We delen de PSM’s op in deelgebieden op basis van de architectuur in het systeem. Profit Next wortdt gegenereerd met een CQRS-architectuur, we splitsen de PSM dan ook op in de 3 systemen die los van elkaar staan: de command, query, en UI. Zeker het apart genereren van de UI geeft voordelen aangezien hier ook andere talen/ tools worden gebruikt dan voor het genereren van de backend.


Als laatste stap worden de PSM’s omgezet naar echte code. Dit doen we met behulp van templating. Alle gegenereerde code wordt met behulp van templates gegenereerd, deze templates worden zo ‘dom’ mogelijk neergezet, we willen eventuele complexe generatie logica in de modelbuilders al klaar hebben gezet. De templates worden ingevuld en afhankelijk  van de template als JavaScript of C# bestanden als output aangeboden.



Wordt onze gehele Profit Next applicatie dan gegenereerd met de templates? Nee, er is een duidelijk verschil tussen de onderliggende architectuur en de implementatie. De onderliggende architectuur blijft hetzelfde ongeacht de implementatie, en er is dus ook geen reden om deze te genereren. Onze CQRS-architectuur vormt de basis waar de implementatie aan wordt toegevoegd. De combinatie van de gegenereerde backend en frontend code vormen samen met de onderliggende architectuur de gegenereerde applicatie.

Uitdagingen

Natuurlijk zijn er nog wel een aantal uitdagingen waar we met deze oplossing tegenaanlopen. De modeldefinitie wordt constant verrijkt zodat we meer patronen kunnen ondersteunen. Dit leidt tot meer uitwerkingen van patronen die met elkaar conflicteren. Dit is een probleem waar veel codegenerators tegenaan lopen, en waar ook veel tijd in verloren kan gaan. We proberen hier pragmatisch in te zijn en zoveel mogelijk combinaties uit te sluiten. We kunnen dit doen omdat we nu al weten dat de software die we genereren een ERP-systeem moet zijn. Patronen of situaties die nooit in dat systeem voorkomen zullen we ook niet hoeven te ondersteunen.

De generator zal partieel generatie binnen de verschillende PSM’s moeten ondersteunen. Wanneer een klant een kleine aanpassing doet aan zijn model, willen we niet de complete PSM’s opnieuw genereren. Hier houden we nu rekening mee, door de modelinformatie zoveel mogelijk in kleine blokken op te delen. Maar ook andere issues, zoals de dataconversie tussen opvolgende Next implementaties, andere issues spelen hier een rol.

De generator is de link tussen de functionele modelkant en de techniek en is veruit het grootste onderdeel in ontwikkeling. Onze belangrijkste uitdaging in de komende jaren is dan om de generator onderhoudbaar te houden. De bewegingen die we zien in ons PIM model, waar steeds meer wordt afgeleid in plaats van hard neergezet en de verbondenheid van de patronen die we ondersteunen zal alleen maar toenemen, in combinatie met de hoeveelheid patronen die we ondersteunen. Er zullen meer gecompliceerde situaties worden gegenereerd Deze doorgronden, en de redenen waarom code zo wordt gegenereerd zal moeilijker worden als we onderhoudbaarheid niet controleren.