De software legacy a oportunitat estratègica: El punt de partida (I)

Quan parlem de software legacy, sovint pensem en aplicacions antiquades o mal dissenyades. Però la realitat és que el “legacy” pot ser qualsevol aplicació que, tot i funcionar correctament, presenta reptes significatius per a la seva evolució i manteniment. Aquesta és la història de com vam abordar la internalització d’una aplicació de gestió logística (Order Management System, OMS), amb el repte afegit d’una integració amb una nova plataforma de comerç electrònic.

El context inicial

L’any 2018 es va desenvolupar l’aplicació amb l’objectiu d’optimitzar el procés de preparació de comandes d’un ecommerce en alça i garantir així una integració eficient amb diferents operadors logístics. Desenvolupada en PHP (Symfony), MySQL, Socket.io i jQuery, l’aplicació gestionava des de l’empaquetat fins a l’enviament, amb funcionalitats com el seguiment d’enviaments, connexió amb transportistes, generació d’etiquetes i mètriques de rendiment de la preparació de les comandes.

Durant anys, aquesta eina va complir el seu propòsit, però amb el temps i l’evolució del negoci, van començar a evidenciar-se limitacions importants.

Deute tècnic acumulat

La situació del deute tècnic era especialment preocupant, ja que afectava múltiples capes del projecte. A nivell d’infraestructura tecnològica, l’aplicació s’executava sobre versions obsoletes tant del framework com del llenguatge base:

  • La versió de Symfony (4.0) no era LTS (Long Term Support) i havia deixat de rebre actualitzacions de seguretat des de gener de 2019
  • PHP 7.1, també havia arribat al final del seu cicle de suport, deixant el sistema sense actualitzacions crítiques de seguretat

Però més enllà de les versions obsoletes, el projecte presentava mancances significatives en aspectes fonamentals del desenvolupament de software:

  • Testing inexistent o inadequat: La falta de tests automatitzats (unitaris, d’integració i end-to-end) no només dificultava la detecció primerenca d’errors, sinó que també feia que qualsevol modificació fos un risc potencial per a l’estabilitat del sistema.

  • Absència d’estàndards de codi: El codebase no seguia patrons ni estàndards documentats, i els que s’aplicaven no estaven alineats amb les millors pràctiques de la indústria. Això dificultava tant el manteniment com la incorporació de nous desenvolupadors al projecte.

  • Documentació insuficient: La documentació existent era escassa i sovint incompleta. Això no només afectava el desenvolupament tècnic, sinó també la comprensió dels processos de negoci implementats en el codi.

  • Control de versions deficient: L’històric de Git era poc explicatiu, amb commits poc granulars i missatges que no seguien cap convenció ni aportaven context sobre els canvis realitzats. Això dificultava entendre l’evolució del codi i les decisions preses al llarg del temps.

Aquesta acumulació de deute tècnic no només representava un risc per a l’estabilitat i seguretat del sistema, sinó que també:

  • Alentia el ritme de desenvolupament de noves funcionalitats
  • Augmentava el risc d’introducció d’errors
  • Dificultava l’onboarding de nous membres a l’equip
  • Incrementava els costos de manteniment
  • Complicava la diagnosi i resolució de problemes

Limitacions estructurals

L’arquitectura inicial presentava problemes d’acoblament que afectaven greument la seva flexibilitat i escalabilitat:

  • Dependència total amb l’e-commerce principal: L’aplicació no podia operar de manera autònoma, ja que totes les operacions logístiques depenien directament de les dades i processos de l’e-commerce. Això feia que qualsevol canvi en la plataforma principal pogués trencar la funcionalitat del sistema.
  • Base de dades compartida que generava problemes de rendiment: Tant l’aplicació logística com l’e-commerce utilitzaven la mateixa base de dades, fet que ocasionava problemes de rendiment, especialment durant pics de càrrega en qualsevol de les dues aplicacions. A més, aquesta configuració complicava la gestió de permisos, ja que qualsevol accés a la base de dades podia comprometre dades crítiques d’altres sistemes.
  • Impossibilitat de funcionar de manera independent: L’aplicació estava dissenyada per operar exclusivament en conjunt amb l’e-commerce. Això no només limitava la seva portabilitat, sinó que també dificultava proves en entorns aïllats o la migració cap a altres plataformes. Les seves dependències no estaven adequadament encapsulades, fent que qualsevol intent d’aïllar-la requerís canvis massius i costosos en tot el sistema, en les principals classes no es respectava el principi de separació de responsabilitats (Single Responsibility Principle).
  • Dificultat per implementar noves funcionalitats:La falta d’adhesió a principis com l’Obert/Tancat (OCP) i la Substitució de Liskov (LSP) dificultava enormement l’evolució del sistema. Les noves funcionalitats requerien modificar codi existent, augmentant el risc d’introduir regressions. A més, la dependència directa entre mòduls feia gairebé impossible seguir el principi d’Inversió de Dependències (DIP).

Aquest conjunt de limitacions estructurals no només reduïa la mantenibilitat i escalabilitat del sistema, sinó que també incrementava els riscos associats a qualsevol modificació o evolució, situant l’aplicació en un estat tècnicament fràgil i estratègicament vulnerable.

Gestió del desenvolupament i alineació estratègica

Un dels reptes més significatius no era només tècnic, sinó estratègic. El desenvolupament extern, tot i ser funcionalment correcte, presentava limitacions importants en l’àmbit organitzatiu:

  • Desconnexió amb l’estratègia global: El desenvolupament es realitzava de manera aïllada, sense una visió completa dels objectius i processos interns de l’empresa. Això resultava en funcionalitats que, tot i podien ser tècnicament correctes, no sempre s’alineaven amb les necessitats reals del negoci.
  • Manca de priorització estratègica: Les noves funcionalitats s’implementaven sense un procés clar de valoració i priorització. No es qüestionava si una funcionalitat era realment necessària, si era la millor manera d’implementar-la, o si existien alternatives més eficients.
  • Desenvolupament reactiu vs. proactiu: El desenvolupament seguia un patró majoritàriament reactiu, resolent necessitats immediates sense considerar l’impacte a llarg termini o les possibles sinergies amb altres processos de l’empresa.
  • Absència de processos de validació: La manca d’un procés estructurat de revisió i validació resultava en funcionalitats que, tot i ser operatives, no sempre representaven la millor solució per als usuaris finals o per als objectius globals de l’empresa.

Aquesta situació no era sostenible a llarg termini, ja que:

  • Generava un producte cada cop més desalineat amb les necessitats reals
  • Dificultava la integració amb altres sistemes i processos de l’empresa
  • Complicava la presa de decisions estratègiques sobre el producte
  • Limitava la capacitat d’innovació i millora continua de l’equip

Impacte del cost basal

Un aspecte sovint oblidat però especialment rellevant en aquest projecte va ser el cost basal, un concepte que considero clau en el desenvolupament de software que es refereix al cost mínim necessari per mantenir operatiu un sistema, fins i tot sense afegir-hi noves funcionalitats o fer-li millores.

En el nostre cas, el cost basal incloïa totes aquelles despeses derivades de la necessitat de mantenir versions obsoletes del framework i del llenguatge, solucionar incidències urgents derivades del deute tècnic acumulat, gestionar la dependència amb altres sistemes, adaptar-se a una arquitectura acoplada i poc coneixement del domini. Tot això consumia una part significativa dels recursos disponibles, afectant directament la capacitat d’invertir en innovació i millora contínua.

Si bé aquest factor no va ser determinant per prendre la decisió d’internalitzar el desenvolupament, va tenir un pes rellevant en la diagnosi inicial del projecte. Sovint, el cost basal es passa per alt en l’avaluació de la sostenibilitat d’un sistema, però en aquest cas, era una evidència clara que l’estratègia actual no era sostenible a llarg termini. A més, va quedar palès, com veurem en posteriors articles, que qualsevol intent de mantenir l’estructura existent augmentaria el cost basal de manera exponencial amb el pas del temps.

Per a una explicació més detallada sobre el concepte de cost basal i la seva importància, recomano consultar l’article original d’Eduardo Ferro


El punt d’inflexió: Un nou repte i una decisió estratègica

En qualsevol projecte de refactorització, es poden adoptar varies estratègies i es habitual trobar-se amb la dicotomia de: l’estratègia (strangler fig) o començar de zero amb un “big bang rewrite”.

Red pill blue pill meme, the question says Choose Refactor Strategy and options between Strangler Fig and Big Band Rewrite

Inicialment, la decisió tècnica va ser treballar dins del mateix projecte legacy, aplicant l’estratègia Strangler Fig, un enfocament que consisteix a desenvolupar un nou mòdul o sistema que, progressivament, substitueixi les parts del sistema antic. Aquesta estratègia ens permetia fer canvis paral·lels (parallel changes), reduint riscos i mantenint la funcionalitat actual mentre construíem una base més sòlida per a les funcionalitats futures.

Tanmateix, des del punt de vista de negoci, es va considerar que aquesta opció suposava un risc massa elevat per al sistema actual, que ja estava operatiu i complint les seves funcions. Es va prendre la decisió d’evitar tocar el projecte existent i apostar per desenvolupar una aplicació independent que complís amb els nous requeriments.

Aquest canvi de rumb ens va portar a fer un fork de la codebase existent, una decisió que, tot i ser tècnicament viable, comportava certs hàndicaps:

  • Duplicació del codebase: Ara caldria mantenir dues bases de codi separades.
  • Bases de dades separades: Es va haver de duplicar i adaptar l’estructura de dades per a cadascun dels sistemes.
  • Infraestructura replicada: Era necessari desplegar un servidor independent i garantir una observabilitat adequada per a cada sistema.
  • Major carrega cognitiva per a l’equip: Totes aquestes duplicitats requerien un esforç addicional per mantenir consistència entre els dos sistemes, augmentant la complexitat i el risc d’errors de l’equip.

Aquest enfocament ens va permetre avançar cap a una solució independent, assegurant l’estabilitat del sistema existent mentre desenvolupàvem un projecte alineat amb els nous objectius estratègics. Tanmateix, era imprescindible analitzar en detall els pros i contres per abordar aquest repte amb confiança i planificació. A més, es va establir un compromís nivell de negoci per no ampliar funcionalitats i mantenir un control estricte del backlog del projecte fins a completar la migració al nou e-commerce.


Diagrama nova arquitectura


Pros Contres
Treballar en un entorn no productiu, reduint riscos en producció Necessitat de mantenir temporalment múltiples projectes
Llibertat per implementar noves tecnologies i patrons des de zero Duplicació temporal d’esforços en manteniment
Dpreocupar-se per les limitacions tècniques o dependències del sistema antic La duplicació de funcionalitats pot alentir el desenvolupament a llarg termini per la necessitat de sincronitzar canvis entre sistemes
Capacitat de centrar-se exclusivament en les funcionalitats necessàries Risc per als deadline per tenir dues bases de codi
Oportunitat d’implementar bones pràctiques des del principi Complexitat en la gestió dels projectes
Major facilitat per incorporar testing des de l’inici Necessitat de mantenir compatibilitat amb dades històriques
Flexibilitat per adaptar-se a nous requeriments de negoci Cost inicial més alt en temps i recursos
Millor alineació amb l’estratègia global de l’empresa Possible pèrdua temporal de funcionalitats no essencials

Conclusions i següents passos

La decisió d’internalitzar i reescriure un software legacy mai és fàcil, especialment quan aquest software compleix la seva funció. La dita de si funciona no ho toquis hi serà sempre present. No obstant això, de vegades és necessari fer un pas enrere per poder fer-ne dos endavant.

En els propers articles d’aquesta sèrie, explorarem com vam abordar aquests reptes, les decisions tècniques i estratègiques que vam prendre, i com vam transformar aquests desafiaments en oportunitats de millora i creixement de tot l’equip.

Plantilla per a les iniciatives

En els meus últims projectes amb responsabilitats compartides de Product Owner i Team Lead en la que tenia més control sobre el backlog del producte, vaig veure la necessitat de crear una plantilla per treballar les nostres iniciatives. Aquest sistema no només ens ajuda a prioritzar el treball enfront d’altres tasques, sinó que també garanteix que tots els implicats comparteixin un mateix context abans de començar. Aquesta metodologia reforça la transparència i l’alineament dins de l’equip i facilita l’avaluació de les decisions durant el desenvolupament.

Què és una iniciativa?

Podem debatre molt sobre organització i jerarquia de les tasques en un backlog, cada equip i empresa son completament diferents. Des del meu punt de vista, una iniciativa és una agrupació de desenvolupaments necessaris per solucionar un problema o implementar una funcionalitat o requeriment. Cada iniciativa pot dividir-se en:

  • Èpiques: Conceptes generals que funcionen com a etiquetes.
  • Històries d’usuari: Unitats més concretes de treball.
  • Tasques: Accions específíques derivades de les històries.

Backlog items

Com es treballa una iniciativa?

Idealment, l’equip es centra en una única iniciativa a treballar, la que té la prioritat més alta i està lo suficientment refinada per poder començar el seu desenvolupament. I que vol dir suficientment refinada us preguntareu? Aquí és on entra la plantilla, la plantilla ens donarà uns mínims, però al igual que una història d’usuari, no ens donarà la solució, sinó que serà el tret de sortida per trobar la millor solució.

Com és la plantilla?

La plantilla conté diferents apartats que permeten capturar tota la informació necessària. Vegem els més importants:

💡 Títol de la iniciativa

Un títol breu i descriptiu que resumeixi el propòsit de la iniciativa.

Taula resum

Inclou informació clau com:

Summary  
🧑‍🏫 Product Name of the product owner/ project manager in charge of the initiative
👩‍💼 Stakeholders Name of the stakeholders involved
👥 Teams Involved Name of the teams

Criteris de priorització

Aquí es pot afegir el criteri de priorització que cada equip consideri, en el nostre cas hem passat per varis criteris, des del RICE a una versió simplificada de la matriu Value/Urgency per quantificar el màxim possible el cost del endarreriment. Us deixo un article del Marc Rodríguez (former Digital Project Manager @ Freshly Cosmetics) on explica com treballavem a nivell de productes per priotitzar objectius.

Priorization criteria  
🎯 RICE Score Points
💎 Value Meh | Bonus | Killer
⏰ Urgency ASAP | Soon | Whenever

📚 Context

L’equip o persona de producte s’ha d’encarregar de donar el màxim de context possible de la iniciativa, deixant clar l’oportunitat que implica aquesta iniciativa, quin impacte ens aporta i el criteri pel qual sabrem que aquesta iniciativa l’hem complementat.

🧐 Problemes a resoldre

A omplir per l’equip o persona de producte que ha proposat la iniciativa. Una taula que connecta la iniciativa amb els objectius globals de l’empresa:

📐 Framing

Aquesta taula s’ha d’omplir per part de l’equip o persona de producte amb l’ajuda d’un referent tècnic de l’equip, aquí es tracta també d’identificar a quins punts claus dels objectius globals de l’empresa impacta. Pot ser una ⭐ North Star o pot ser un OKR, etc, el que s’intenta aquí es identificar si anem alineats o no.

   
⭐ North Star filled by PM/PO
🚀 Direct Impact filled by PM/PO
🌱 Indirect Impact filled by PM/PO
💻 Development effort Low, Middle, High (filled by team lead or team)
📈 KPIs filled by PM/PO

Fins aquest punt de la plantilla, tot el que s’ha demanat no requereix cap tipus de desenvolupament, però es molt rellevant per entendre el que es vol fer i dona la informació suficient per poder-la prioritzar o descartar-la. Si la passem a prioritzar i volem començar-ne el desenvolupament, el que farem, ja per part de l’equip de desenvolupament, es omplir un últim apartat que anirà seguit d’una kick-off per presentar el document i anar tots alineats.

🔭 Descoberta

En aquest apartat s’hauran d’omplir els següents punts:

🛠️ Solució

En aquest punt es tracta d’exposar una proposta de solució, tot i que és a nivell teòric també pot anar acompanyat d’una prova de concepte (POC)

🐉 Riscs

Llistats d’impdiments i riscs que poden afectar el desenvolupament o al producte pel fet d’optar per aquesta solució

🔖 Enllaços i altres documents

Llistat d’altra informació rellevant o enllaços d’interes que poden ser útils. (Diagrames, issue tracker, project managment tool …)

A continuació us deixò la plantilla complerta en format Markdown

# 💡 Initiative Title

| **Summary** |  |
| ----------- | --- |
| **🧑‍🏫 Product** |  Name of the product owner/ project manager in charge of the initiative |
| **👩‍💼 Stakeholders** | Name of the stake holders involved  |
| **👥 Teams Involved** | Name of the teams |

| **Priorization criteria** |     |
| ----------------- | --- |
| **🎯 RICE Score** | Points |
| **💎 Value** | Meh \| Bonus \| Killer |
| **⏰ Urgency** | ASAP \| Soon \| Whenever |

## 📚 Context

The context should be filled by the PM, PO or the person who is proposing the initiative. It should contain the following information:

- **Opportunity**: What is the opportunity that we are trying to take advantage of?
- **Impact**: What is the impact that we are trying to achieve?
- **Success Criteria**: What are the criteria that we will use to measure the success of the initiative?

## 🧐 Problems to solve

The problems to solve should be filled by the PM, PO or the person who is proposing the initiative.

### 📐 Framing

|  | |
| ----------- | --- |
| **⭐ North Star** | filled by PM/PO  |
| **🚀 Direct Impact** | filled by PM/PO  |
| **🌱 Indirect Impact** | filled by PM/PO  |
| **💻 Development effort** | Low, Middle, High (filled by team lead or team) |
| **📈 KPIs** | filled by PM/PO  |

## 🔭 Discovery

### 🛠️ Solution

To be filled by the whole team or the team lead during the Kickoff

### 🐉 Risks

To be filled by the whole team or team lead during the Kickoff

### 🔖 Important links and documents

- [project managment](#)
- [drive folder](#)

Enllaços relacionats

Una Suplica Pel Programari Lleuger

Una súplica pel programari lleuger

L’article “A Plea for Lean Software” de Niklaus Wirth, publicat a “Computer: Cybersquare” el febrer de 1995, aborda la problemàtica del creixement desmesurat del programari en comparació amb la seva funcionalitat, argumentant que els avenços en hardware han permès, però no justificat, aquesta expansió.

Wirth critica la tendència del programari a ser “obès”, que requereix més recursos que mai, per millorar la funcionalitat del programari, i suggereix que la solució és radical en disciplines metodològiques i repercuteix en les funcions essencials.

Tot i ser un article de gairebé 30 anys, es segueixen cometent els mateixos errors i caldria tenir-los presents a l’hora de desenvolupar programari i veure com les bones pràctiques de desenvolupament ens poden ajudar a evitar-lo.

D’aquesta manera enumera i descriu les causes per les que s’ha arribat aquí.

Adopció acrítica de característiques soŀlicitades pels usuaris.

Els desenvolupadors de programari tenim tendència a incorporar qualsevol característica que els usuari demandin, sense considerar, de forma crítica la seva compatibilitat amb el concepte original del sistema. El que ens porta a dissenys complicats, i un ús inadequat del programari fomentant la quantitat enlloc de la qualitat.

Conèixer bé el domini del producte i l’aplicació de patrons tàctics i tècnics per al desenvolupament d’aquests projectes pot ajudar a resoldre aquest problema

Disseny monolític

El fet d’incloure totes les característiques dins del disseny del sistema, sense considerar si tots els el usuaris ho necessiten. Això implica en que cada client pagui per totes les característiques, encara que no les utilitzi.

Aquest punt molt actual sobretot amb l’auge els productes SaaS, on precisament es aquest el model de negoci.

L’aplicació de dissenys monòlits modulars pot ajudar a resoldre aquest problema.

Augment de la potència del hardware

La millor continua en la potència del hardware permet abordar problemes més complexes (complexitat essencial) oferint als desenvolupadors la possibilitat d’implementar solucions més sofisticades i funcionalitats abans impossibles per limitació de recursos, però pel contrari facilita un enfocament menys disciplinat que afavoreix la complexitat accidental.

Aquest fet que es tingui menys en consideració l’eficiència del programari el que es tradueix en un programari més “gras” i possiblement més complicat. A curt plaç pot ser imperceptible, i tot i que la potencia pot ajudar a mitigar aquesta complexitat accidental, només emmascara els problemes de fons, que sorgiran en el la escalabilitat i manteninment

Complexitat per conveniència de l’usuari

Tendència a la interacció amigable de l’usuari amb l’us de finestres, icones, colors, ombres i d’altres elements visuals han fet augmentar la complexitat del programari. S’ha de trobar un equilibri entre la experiència de l’usuari i l’augment de la complexitat.

El fet de tenir un design system ben definit i estructurat i la seva bona aplicació podria mitigar aquesta problemàtica

Equivalència errònia entre complexitat i poder

Existeix la percepció de que un sistema com més complex és, més poderós i sofisticat és. Això fomenta la pràctica d’afegir característiques com més complexes millor, que poden no ser essencials per la funcionalitat del programari. Aquest punt, també bastant relacionat amb el primer d’adopció acrítica dels requeriments.

Aquestes causes subratllen la necessitat d’un enfocament més disciplinat i conscient en el disseny de programari, on es prioritzi la funcionalitat essencial i l’eficiència sobre l’addició indiscriminada de característiques i complexitats innecessàries.

Per acabar, Wirth agafa d’exemple un projecte (Oberon) el que considera com a bon exemple de simplicitat i extensibilitat i ho resumeix en una sèrie de lliçons apreses:

  1. Ús exclusiu d’un llenguatge fortament tipat: La utilització d’un llenguatge de programació amb tipificació forta i estàtica va ser crucial per al disseny eficient del sistema, permetent que el compilador identifiqui inconsistències abans de l’execució, facilitant canvis segurs i accelerant el procés de millora.
  2. Decomposició adequada en una jerarquia de mòduls: Identificar la descomposició més apropiada del sistema en mòduls per minimitzar duplicacions de funcions i codi és una tasca desafiadora però essencial per al disseny eficient.
  3. Extensió de tipus per a un sistema extensible: La construcció d’un sistema extensible, on nous mòduls poden afegir funcionalitats i integrar-se compatiblement amb classes o tipus de dades existents, és fonamental per mantenir un sistema àgil des del començament.
  4. Identificació de primitives flexibles per a extensions: És crucial identificar aquelles primitives que ofereixen més flexibilitat per a futures extensions, evitant alhora la seva proliferació innecessària.
  5. Equip de disseny reduït: Contrari a la creença popular, els sistemes complexos no requereixen grans equips de disseny. Un sistema que no pot ser comprès íntegrament per un individu probablement no s’hauria de construir.
  6. Problemes de comunicació en equips grans: Els problemes de comunicació augmenten amb la mida de l’equip de disseny, cosa que pot posar en perill tant l’equip com el projecte.
  7. Reducció de complexitat i mida a cada pas: La competència d’un programador hauria de mesurar-se per la seva capacitat per trobar solucions simples, no per la productivitat mesurada en línies de codi per dia.
  8. Experiència pràctica pròpia: No hi ha substitut per a lesforç de programació propi. L´organització de l´equip en rols separats és perjudicial; tots han de participar en tots els aspectes del desenvolupament i fer servir el producte.
  9. Qualitat de publicació dels programes: Els programes han de ser refinats fins a assolir qualitat de publicació, dissenyats per ser llegibles tant per humans com per ordinadors, contradient interessos comercials però sense resistència a l’acadèmia.

En conclusió, el manifest de Niklaus Wirth “A Plea for Lean Software” segueix essent profundament rellevant en l’era actual del desenvolupament de programari. Les leccions apreses del projecte Oberon i l’anàlisi de les causes subjacents del programari “obès” ofereixen una guia valuosa per a dissenyadors i desenvolupadors. La necessitat d’una disciplina rigorosa en la incorporació de característiques, un disseny modular que permeti la flexibilitat sense sacrificar la simplicitat, i la importància de l’eficiència en l’aprofitament dels avenços en hardware són principis que ens poden ajudar a evitar la trampa de la complexitat innecessària.

Mentre que els avenços tecnològics han transformat les capacitats del programari i la maquinària, el principi fonamental d’optimitzar per la simplicitat, la claredat i l’utilitat sense sacrificar la funcionalitat roman inalterat. Aprendre de les reflexions de Wirth ens pot capacitar per desenvolupar programari que no només satisfaci les necessitats actuals de manera eficient sinó que també sigui sostenible i adaptable en el futur. En última instància, el desafiament de reduir la complexitat del programari no és simplement una qüestió de preferència personal sinó un imperatiu per a la creació de tecnologia sostenible i accessible.