Results 1 to 14 of 14

Thread: Delphi en "Feature Flag": best practices

Threaded View

  1. #1
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708

    Delphi en "Feature Flag": best practices

    Hallo allemaal,

    Ik ben benieuwd naar hoe collega developers omgaan met onderstaand vraagstuk, maar laat ik bij het begin beginnen.

    Het bedrijf waar ik werk maakt software dat een code-base heeft dat meer dan 20 jaar oud is, ook hebben we wereldwijd tienduizenden klanten die het pakket 24/7 gebruiken.
    Zoals zo vaak brengt dit veel legacy (lees: spaghetti) code met zich mee, al zijn er ook veel latere stukken code dat netjes volledig object georiënteerd zijn.

    De werkwijze waarmee we nu globaal werken (we zijn met maar een heel klein team):
    • De "Product Owner" (PO) maakt feature request of bug aan en zet dit op naam van één van de developers (dev)
    • De dev in kwestie pakt de laatste code uit master en creëert een eigen (nieuwe) branche voor zijn taak.
    • Dev werkt aan zijn taak, test het en als hij tevreden is pushed hij zijn code en doet een pull request naar master, waarna de wijzigingen gemerged worden met master
    • Vervolgens gaat er een seintje naar de tester (QA), die de nieuwe implementatie (in master) vervolgens aan de tand voelt.
    • Wanneer de QA en PO vinden dat de taak goed volbracht is, krijgt de dev de opdracht om de wijzigingen te cherry picken (of pushen) naar de definitieve klantversie.

    Deze flow zou prima zijn in een ideale wereld, maar helaas leven we daar niet in, en met tienduizenden klanten (en dus ook verschillende instellingen en setups) kan het wel eens gebeuren dat er bij een bepaalde klant ineens iets niet meer werkt.
    Op dit moment is het zo dat er dan een hoge prioriteit taak wordt aangemaakt en dat (afhankelijk van de functie en of er wel of niet een work-around voor is) eventueel een oudere, nog wel correct werkende, versie wordt teruggezet (met het gevolg dat andere, nieuwe, functionaliteit niet meer aanwezig is).

    Nu wil management graag dat wij, in ons van spaghetti code vergeven product, iets van een "Feature Flag" (of "Feature Toggle") inbouwen die @runtime gezet kan worden (in een "Geheim" menu-scherm oid) door de supportafdeling.

    De meest "Simpele" (maar niet echt "Eenvoudige") manier zou zijn om dingen te doen als:
    Delphi Code:
    1. procedure BerekenPrijs(const AAantal: Integer; const AEenheidsPrijs): Currency;
    2. begin
    3.   if gTask1234 then // We moeten de nieuwe code gebruiken wanneer dit aan staat
    4.     Result := AAantal * AEenheidsPrijs
    5.   else
    6.     Result := Round(AAantal * AEenheidsPrijs); // Deze code is fout
    7. end;
    8.  
    9. procedure WeGaanRekenen;
    10. begin
    11.   WriteLn(BerekenPrijs(3, 1.46));
    12. end;
    Maar in de meeste gevallen is dat niet te doen, omdat je in een enkele method op meerdere plaatsen wijzigingen hebben die aan- of uitgezet moeten kunnen worden.
    Nog ingewikkelder wordt het als twee (of meer) collega's toevallig in dezelfde method zaken hebben aangepast (wellicht zelf in dezelfde stukken code).

    Je kunt er ook voor kiezen om het op method niveau te regelen, bijvoorbeeld:
    Delphi Code:
    1. procedure BerekenPrijs_1234(const AAantal: Integer; const AEenheidsPrijs): Currency;
    2. begin
    3.   Result := AAantal * AEenheidsPrijs;
    4. end;
    5.  
    6. procedure BerekenPrijs(const AAantal: Integer; const AEenheidsPrijs): Currency;
    7. begin
    8.   Result := Round(AAantal * AEenheidsPrijs); // Deze code is fout
    9. end;
    10.  
    11. procedure WeGaanRekenen;
    12. begin
    13.   if gTask1234 then // We moeten de nieuwe code gebruiken wanneer dit aan staat
    14.     WriteLn(BerekenPrijs_1234(3, 1.46))
    15.   else
    16.     WriteLn(BerekenPrijs(3, 1.46))
    17. end;
    Maar het gevolg hierbij is dat je complete methods moet gaan kopiëren en dat je in alle aanroepen naar die methods het vlaggetje moet zetten.
    Bij beide oplossingen moet je tevens achteraf, als na enige tijd in het veld blijkt dat de nieuwe code goed is gebleken, alle oude verwijzingen (en vlaggetjes) weer moet verwijderen.

    Een derde idee dat ik had, maar dat is een beetje "Hacky" is om een "Frameworkje" te maken waarin ik nieuwe methods implementeer als hooks en pas als alles akkoord is bevonden de code definitief in het project hang.
    Afgezien van het "Hack"-dingetje is dan de vraag: hoe met de implementatie hiervan om te gaan zodra (bijvoorbeeld) de parameterlijst wijzigt?

    Was onze code-base nu helemaal volgens de (hedendaags) geldende regels geschreven, dan hadden we het geheel misschien nog kunnen automatiseren/vergemakkelijken door op object, method of unit niveau functionaliteit te laten schakelen, maar helaas moeten we het met de code (en resources) doen die we hebben; bij de oplossingen die ik kan bedenken blijven we zitten met een hoop extra werk (ook achteraf): ook onze QA moet bij iedere echte wijzigingen weer gaan testen.

    Mijn vraag is dus eigenlijk: hoe pakken jullie dit aan (indien je soortgelijke functionaliteit al hebben) of kun je meedenken en mij van wat ideeën voorzien?
    Om de handige Harry's voor te zijn: compiler directives kunnen we niet gebruiken, nieuwe code moet echt @runtime moeten worden aan- of uitgezet; support kan geen versies bouwen.

    Alvast bedankt voor het lezen en meedenken!

    Groet,

    Peter
    Last edited by VideoRipper; 18-Nov-21 at 15:10.
    TMemoryLeak.Create(Nil);

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •