Inici
didacrios.cat.web.brid.gy
Inici
@didacrios.cat.web.brid.gy
Un bloc en català dedicat a compartir coneixements, experiències i reflexions sobre tecnologia, desenvolupament de programari i bones pràctiques per construir […]

[bridged from https://didacrios.cat/ on the web: https://fed.brid.gy/web/didacrios.cat ]
Comprendre el domini i construir l'equip: Les bases del canvi (II)
Al començar un projecte complex com el que estem abordant, és essencial tenir el màxim context possible, però tambe partir de zero en el coneixement del domini i anar explorant amb l’ajuda dels _domain experts_. Aquesta activitat no només ajuda a l’equip tècnic a alinear-se amb els objectius del negoci, sinó que també ajudar a fer-se un mapa global establint les bases per prendre millors decisions al llarg del cicle de vida del producte. Per entendre com funcionava l’aplicatiu existent, identificar els diferents procesos que s’executaven i saber com estaven representats al codi així com establir un llenguatge comú amb l’anterior equip i els usuaris actuals del aplicatiu vam realitzar unes primeres sessions que no van ser gaire fructíferes, fins al punt de valorar si podiem ferun traspàs més traumàtic prescindint d’aquestes i espavilar-nos pel nostre compte. ## EventStorming Al incorporar-me com a _tech lead_ des d’un principi vaig tenir clar que degut a la complexitat del projecte i si volia que l’equip tingués un _ownership_ real del producte haviem de donar un enfocament _domain-driven_ tant al projecte com a l’equip. Això ens permetria moure el domini al centre de la narrativa, d’aquesta manera alineariem tot l’equip al voltant d’un llenguatge comú (_ubiquitous language_) que ens facilitaria la comunicació i ens permetria fer un mapa de l’estat actual de l’aplicació. Així que un cop format aquest equip inicial vam començar a prepar sessions d’EventStorming. Aquesta metodologia visual ens va ajudar a descompondre els processos clau del sistema i identificar esdeveniments i entitats de domini rellevants. Per a facilitar les sessions vam utilitzar una plantilla de Miro que ja porta una mica de guía i llegenda de les referències claus que s’han de tenir en compte per enfocar una sessió d’aquest tipus. Si voleu fer una sessió vindria bé que els participans tinguin un mínim de noció d’alguns conceptes amb els que hauran de trrballar, ja sigui fent fer una mica de _prework_ o fer una explicació al iniciar la sessió. flowchart TD subgraph Legend["Llegenda Event Storming"] direction TB Event["Event"]:::event Command["Command"]:::command Aggregate["Aggregate"]:::aggregate Policy["Policy"]:::policy Actor["Actor"]:::actor Note["Note"]:::note end classDef event fill:#fc5e03,stroke:#782c00,stroke-width:2px,corner-radius:5px; classDef command fill:#00b2e8,stroke:#005c78,stroke-width:2px,corner-radius:5px; classDef aggregate fill:#ffbf00,stroke:#7a5c00,stroke-width:2px,corner-radius:5px; classDef policy fill:#6f00ff,stroke:#240054,stroke-width:2px,corner-radius:5px; classDef actor fill:#ffdd00,stroke:#756600,stroke-width:2px,corner-radius:5px; classDef note fill:#fa0000,stroke:#660000,stroke-width:2px,corner-radius:5px; Per maximitzar l’efectivitat de les sessions vam desenvolupar un procés estructurat en diverses fases: 1. **Exploració d’Events de Domini** (Foto inicial) * Identificar els esdeveniments clau del sistema * Ordenar-los cronològicament * Detectar gaps i dependències * Validar la seqüència amb els experts 2. **Refinament i Anàlisi** * Afegir notes explicatives * Documentar dubtes i preguntes * Entrar més en detall en cada esdeveniment * Marcar punts de decisió crítics 3. **Modelatge del Domini** * Identificar agregats (_aggregates_) i les seves fronteres * Definir actors i els seus rols * Establir comandes (_commands_) que inicien processos * Documentar polítiques (_policies_) i regles de negoci * Identificar triggers externs i interns de cada esdeveniment 4. **Documentació i Validació** * Netejar i organitzar la informació recollida * Establir relacions clares entre elements * Validar el model amb tots els stakeholders * Crear documentació de referència L’ _EventStorming_ no només ens va servir per entendre el domini, sinó que també va ser el punt de partida per aplicar els principis de _Domain-Driven Design (DDD)_ tant a nivell estratègic com tàctic. ### Domain-Driven Design Estratègic Un dels punts més importants en la fase inicial del projecte va ser decidir com estructurar el domini a nivell estratègic. La complexitat del sistema, combinada amb la necessitat d’alinear els objectius tècnics amb els del negoci, ens va portar a adoptar principis de Domain-Driven Design (DDD). Durant aquest procés, una de les eines més útils va ser el _Context Mapping_. Tot i que treballàvem amb un monolit encara pendent de refactorització, vam invertir temps a identificar diversos _Bounded Contexts_ dins del domini. A la pràctica, això volia dir que, tot i haver descrit i delimitat diversos contextos conceptuals, a nivell tècnic operàvem dins d’un únic _Bounded Context_ amb un sol _Shared Kernel_. Aquesta realitat monolítica no ens va impedir aprofitar els beneficis d’aquesta anàlisi. Encara que no aprofundíssim en el _Context Mapping_ de manera exhaustiva, utilitzar aquestes tècniques en aquesta etapa va ser clau per assegurar que el projecte tingués un camí clar cap a una arquitectura orientada al domini. Aquest enfocament no només facilita el desenvolupament tècnic, sinó que també promou una millor col·laboració entre els equips tècnics i els de negoci. #### Establint els Límits (_Bounded Contexts_) Identificar els _Bounded Contexts_ ens va permetre entendre millor com es relacionaven les diferents parts del sistema, tant entre si com amb els sistemes externs. Aquest exercici no només ens va ajudar a gestionar la complexitat de manera més eficient, sinó que també va establir una base clara per als passos evolutius posteriors del projecte. A mesura que el sistema evolucioni cap a una arquitectura més modular, aquestes decisions inicials serviran de guia per descompondre el monòlit en components més manejables i alineats amb els contextos definits També ens va ajudar a entendre on havíem de dirigir els esforços de desenvolupament i quines parts del sistema podien ser simplificades, desacoblades o eliminades. Tècnicament, ens vam centrar especialment en la implementació de _Anti-Corruption Layers_ (ACL), ja que ens permetien interactuar amb sistemes externs sense comprometre la integritat del nostre sistema. En el nostre cas, inicialment vam identificar cinc grans contexts clarament diferenciats: * Assignació de comandes * Generació d’etiquetes * Preparació de comandes * Integració E-commerce * Preparació de comandes massiu Aquestes decisions no només han establert els fonaments per a una arquitectura sostenible, sinó que també han garantit que els processos de desenvolupament siguin més focalitzats i alineats amb les necessitats del negoci. #### Llenguatge Ubic (_Ubiquitous language_) Un altre aspecte fonamental va ser establir un llenguatge ubic (_ubiquitous language_) sòlid. Els avantatges d’establir aquest llenguatge són molt superiors a qualsevol sobresforç de traducció o al risc de malinterpretar conceptes. Els experts de domini (_Domain Experts_) i els programadors han de coŀlaborar activament per crear aquest llenguatge comú, que va més enllà d’un simple glossari de termes. Es tracta d’un recurs viu i dinàmic que connecta l’equip tècnic amb els experts del domini. L’esforç en la seva implementació ha facilitat la comunicació, reduït malentesos i assegurat que el codi sigui una representació fidel del domini. Desenvolupar software no és només una qüestió tècnica; és una activitat basada en la comunicació i la coŀlaboració. Gràcies al llenguatge ubic, tots els membres de l’equip treballen alineats, cosa que resulta en solucions tècniques més eficients i que responen millor a les necessitats del negoci. ### _Domain-Driven Design_ Tàctic Un cop definit el marc estratègic, vam passar a implementar principis de DDD tàctic en el sistema. Això ens va permetre estructurar el codi de manera que reflectís la realitat del domini i fos més sostenible a llarg termini. #### Entitats (_Entities_) i Objectes de Valor (_Value Objects_) Les entitats (Entities) i els objectes de valor (Value Objects) són dos conceptes fonamentals en el Domain-Driven Design (DDD). Per entendre com funcionen, és important destacar les seves diferències i el paper que juguen dins del domini. #### Entitats (_Entities_) Les entitats són elements del domini que tenen una identitat única que perdura al llarg del temps, fins i tot si els seus atributs canvien. Aquesta identitat única és el que les distingeix d’altres elements del mateix tipus. A més, les entitats solen tenir un cicle de vida definit dins del sistema. Exemples d’entitats que vam identificar en el projecte són: * Order: Representa una ordre de compra amb una identitat única i un estat associat. * Product: Element del catàleg amb atributs com el codi SKU, preu i descripció. * Carrier: Empresa encarregada de lliurar les comandes amb opcions de servei específiques. * Shop: Identifica de quin e-commerce o plataforma ens ha arribat la comanda. * Customer: Persona o entitat que realitza la comanda i rep el producte. #### Objectes de Valor (Value Objects) Els objectes de valor, en canvi, són elements del domini que no tenen identitat pròpia. El seu valor és el que els defineix, i per això, dos objectes de valor amb els mateixos atributs són considerats equivalents. Això els fa immutables i ideals per encapsular conceptes clau que poden aparèixer en diverses parts del domini. Alguns exemples d’objectes de valor en el projecte inclouen: * ProductReference: Codi únic per identificar un producte. * ProductEan13: Codi de barres EAN-13 associat a un producte. * OrderReference: Identificador únic d’una comanda. * Price: Amb moneda i valor precís. * Weight: Amb unitats de mesura estandarditzades. * ShippingNumber: Número d’identificació per seguiment. Aquest enfocament ens ajuda a crear codi més comprensible i modular, ja que cada element del sistema té una responsabilitat clara i ben definida. Exemple d’un objecte de valor: <?php readonly class ProductEan13 { public string $value; public function __construct( string $value ) { $pattern = '/^\d{13}$/'; if (!preg_match($pattern, $value)) { throw new \Exception('Invalid product Ean13'); } $this->value = $value; } } #### Serveis (Services) En una aplicació complexa com la nostra, el concepte de Serveis juga un paper central en el manteniment d’un codi net i modular. Els serveis es classifiquen en diferents capes i tipus segons el seu propòsit i els patrons que implementen. Explorem l’estructura i els patrons que fem servir per organitzar i implementar serveis de manera efectiva. ##### Serveis de Domini Els Serveis de Domini encapsulen lògica de negoci que no encaixa directament en cap entitat o valor específic. Són serveis que operen estrictament dins de les regles del domini i no tenen dependències amb components d’infraestructura. <?php class CheapestCarrierGetter { public function get( DeliveryOptionCarrierCollection $deliveryOptionCarriers, Weight $orderWeight, Country $country, PostalCode $postalCode, bool $isCashOnDelivery = false, ): Carrier { // Lògica per obtenir el transportista més econòmic } } ##### Serveis d’Aplicació Els Serveis d’Aplicació encapsulen i coordinen lògica que combina operacions de domini amb interaccions externes per implementar escenaris específics de negoci o aplicació. Aquests serveis centralitzen i simplifiquen la implementació d’operacions complexes, assegurant una separació clara entre el domini i la infraestructura. Els més coneguts són els casos d’ús (use cases) però en el nostre cas també tindrem _Command Handlers_ i _Event Handlers_. graph TD ApplicationServices["Application Services"] --> UseCases["Use Cases"] ApplicationServices --> EventHandlers["Event Handlers"] ApplicationServices --> CommandHandlers["Command Handlers"] Els Use Cases representen accions o processos específics que l’aplicació necessita realitzar per complir amb els requisits de negoci. Encapsulen la lògica necessària per executar operacions complexes, incloent-hi interaccions amb serveis de domini i infraestructura, mantenint el domini net i focalitzat. Podriem dir que la seva responsabilitat hauria de ser nomes la d’orquestrar entre aquestes dues capes, i deixant la responsabilitat cap al domini, com diu Vaughn Vernon _“Keep Application Services thin, using them only to coordinate tasks on the model.”_ Els _Command Handlers_ són la porta d’entrada per a les modificacions en el domini. En rebre un _Command_ , validen la petició, deleguen la lògica de negoci als agregats corresponents i, finalment, publiquen un esdeveniment que reflecteix el canvi produït en el sistema. D’altra banda els _Event Handlers_ actuen com a _listeners_ a canvis en el sistema. Escolten esdeveniments i executen accions específiques en resposta, com ara enviar notificacions, actualitzar altres agregats o integrar-se amb sistemes externs. Aquesta reacció desacoblada permet construir sistemes més flexibles i escalables. Ampliaré els detalls i conceptes en pròximes entrades quan parlem sobre l’evolució de l’aplicatiu com a una arquitectura basada en events i sistemes de cues(Event-Driven Architecture, EDA). <?php readonly class NotifyShopOnOrderShipped implements EventHandlerInterface { public function __construct( private OrderRepositoryInterface $orderRepository, private ExternalOrderUpdaterFactory $externalOrderUpdaterFactory, private LoggerInterface $logger ) {} public function __invoke(OrderShippedDomainEvent $event): void { // Lògica per notificar la botiga quan una comanda ha estat enviada $order = $this->orderRepository->findById($event->getOrderId()); if (!$order) { $this->logger->error("Comanda no trobada", ['orderId' => $event->getOrderId()]); return; } $updater = $this->externalOrderUpdaterFactory->create($order); $updater->updateStatus('shipped'); $this->logger->info("Notificació d'enviament completada", ['orderId' => $order->getId()]); } } ##### Serveis d’Infraestructura Els Serveis d’Infraestructura implementen operacions que depenen de components externs com bases de dades, sistemes de fitxers o serveis de tercers. Sovint actuen com adaptadors per garantir que el domini es mantingui agnòstic a la implementació concreta. <?php class MonologLogger implements LoggerInterface { private $logger; public function __construct(Logger $logger) { $this->logger = $logger; } public function info(string $message, array $context = []): void { $this->logger->info($message, $context); } public function warning(string $message, array $context = []): void { $this->logger->warning($message, $context); } public function critical(string $message, array $context = []): void { $this->logger->critical($message, $context); } public function error(string $message, array $context = []): void { $this->logger->error($message, $context); } } ##### Classificació dels serveis Com hem vist, els serveis ens serveixen per desacoblar i descomposar lògica de la nostra aplicació d’una forma més granular i independent., aquí us deixo una classificació de serveis comuns que hem identificat en els nostre projecte, agrupant-los segons la seva funció principal i associant-los a patrons de disseny coneguts. Aquesta classificació ens permet tenir una visió més estructurada de la nostra arquitectura i facilita la presa de decisions a l’hora de dissenyar noves funcionalitats. Tipus de Servei | Descripció | Patró | Exemple ---|---|---|--- **Transformers** | Converteixen dades entre diferents formats o representacions. | _Adapter_ | Convertir respostes d’API externes en models de domini. **Builders** | Construeixen objectes complexos pas a pas. | _Builder_ | Crear un objecte `Order`. **Factories** | Creen objectes de domini assegurant que compleixen regles i restriccions. | _Factory_ | Crear instàncies de `Product`. **Presenters** | Donen format a les dades per a la interfície d’usuari o respostes d’API. | _Decorator_ | Enriquir dades per mostrar-les a l’usuari. **Notifiers** | Envien notificacions (correu, SMS, etc.). | _Observer_ | Notificar l’usuari de canvis importants. **Validators** | Asseguren que objectes compleixin regles de negoci. | _Strategy_ | Validar sol·licituds d’usuari o formularis. **Clients** | Interactuen amb aplicacions o serveis externs. | _Proxy_ | Consumir APIs externes per obtenir informació. * * * Tots aquests conceptes de domini són només una petita mostra de tot el que vam arribar a fer modelat. Evidentment, tampoc ho vam fer de cop ni vam encertar tot a la primera: hi ha moltes parts que encara van quedar pendents de reestructurar, conceptes que no vam acabar d’aclarir del tot i repositoris que sabíem que no tenien sentit, però que havíem de mantenir per funcionalitats, però que haviem d’acabar d’eliminar. Però amb aquesta feina feta inicialment, es va permetre que tot l’equip participés en aquest procés i tingués un compromís (_commitment_) per tot el que estàvem construint. Per aprofundir en aquests conceptes de DDD i com aplicar-los, recomano llegir els llibres següents: * “Domain-Driven Design: Tackling Complexity in the Heart of Software” d’Eric Evans: L’obra fundacional sobre DDD que introdueix i explica en profunditat els conceptes d’entitats i objectes de valor. * “Implementing Domain-Driven Design” de Vaughn Vernon: Un llibre pràctic que ofereix exemples concrets de com implementar DDD en projectes reals. * “Domain-Driven Design in PHP” de Carlos Buenosvinos, Christian Soronellas & Keyvan Akbary ## Construïnt equip El procés d’adopció de DDD va anar paraŀlel a la formació i evolució de l’equip. Aquí és on vull parlar del model d’etapes de Tuckman (1965): _Forming, Storming, Norming, Performing_ , ja que considero que l’evolució de l’equip va seguir aquesta seqüència i això ens va ajudar d’una banda a alinear les nostres pràctiques tècniques i d’altra a desenvolupar una cultura de col·laboració i confiança en l’equip. Tal com descriu Tuckman (1965), comprendre i abraçar aquestes etapes és clau per construir equips d’alt rendiment. La referència original pot trobar-se al seu treball: Tuckman, B. W. (1965). Developmental sequence in small groups. Psychological Bulletin, 63(6), 384–399. Segons aquest model, els equips passen per quatre fases distintives per arribar al màxim rendiment. Durant la fase inicial (_Forming_), els membres de l’equip s’introdueixen i defineixen objectius generals. A la fase de _Storming_ , emergeixen conflictes mentre es comencen a establir els rols. Amb el temps, en la fase de _Norming_ , els equips aconsegueixen una dinàmica de treball cohesionada, que culmina en _Performing_ , on es treballa de manera eficient cap als objectius comuns. ### Formació (_Forming_) L’equip es va formar inicialment amb dos desenvolupadors, que van començar revisant el projecte i documentant el seu funcionament, mentre altres membres tancaven els seus respectius projectes per incorporar-se en aquest. Per la meva banda em vaig incorporar com a _tech lead_ i vaig començar a repasar la nova documentació que s’havia generat i establir establir les bases tècniques i organitzatives del projecte i l’equip en quant a processos, estàndards i eines. ### Tempesta (_Storming_) No podríem dir que hi va haver grans desavinences dins l’equip, però sí que vam veure la necessitat de “regular” certs aspectes per tal d’anar tots més alineats. Es va fer més palesa aquesta necessitat quan vam incorporar dues persones més a l’equip i el _roadmap_ començava a prendre forma. Això va fer que ens plantegéssim com volíem treballar, comunicar-nos i sobretot com fer visibles totes aquestes decisions i coneixements en un projecte que estava en constant evolució. Així que rapidament vam passar a la fase de _Norming_ per establir les bases de com volíem treballar i com volíem organitzar-nos. ### Estandarització (_Norming_) Durant aquest període vam acordar diversos aspectes per facilitar el treball en equip: * Team Agreements: Normes per al treball en equip i la comunicació com la definició de cerimonies, horaris de reunions, canals de comunicació, etc. * Coding Standards: Guies per escriure codi net i mantenible seguint les bases de DDD, Arquitectura Hexagonal i principis SOLID. * Procés de Desenvolupament: Definició de les eines, processos i pràctiques a seguir per a mantenir un flux de treball eficient, amb l’objectiu de millorar la qualitat del codi i la productivitat de l’equip fomentant una cultura de col·laboració i aprenentatge. * Límits de WIP (Work In Progress): Per garantir un flux sostenible de treball. Té un capitol a part per reforçar la seva importància, com a part de la metodologia Lean a la que ens vam acostar. * Deployments: Regles per a desplegaments controlats i fiables, incloent les limitacions horàries i els procediments de rollback. * Deute Tècnic: Definició i gestió del deute tècnic acumulat així com facilitar un marc per identifcar-lo i prioritzar-lo si s’escau * ADR: Registre i justificació de decisions arquitectòniques per garantir la coherència i la traçabilitat de les decisions preses. ### Rendiment (_Performing_) Amb tota la feina feta en les etapes anteriors, havíem creat un marc de treball que ens permetia centrar-nos en el desenvolupament del producte de manera eficient i sense preocupacions, més enllà de les de prioritzar aquelles iniciatives que aportessin més valor en el context de cada moment. Això va permetre que l’equip es centressi en la implementació de funcionalitats de negoci a la vegada que es millorava la qualitat del codi, ens formavem i manteniem la documentació viva. ## Documentació Tot aquest esforç no tenia sentit si no es feia d’alguna manera visible. Ho vam documentar perquè estigués accessible en qualsevol moment i fàcil d’actualitzar. Utilitzàvem GitLab per gestionar el codi del projecte, així que vam activar la funcionalitat de GitLab Pages i després d’una mica d’investigació vam utilitzar Jekyll amb el tema Just the Docs. Per organitzar la informació, vam basar-nos en el model Diátaxis: * **Tutorials** : Guies per a funcionalitats del aplicatiu, destinades principalment a l’usuari final (exemple: Configuració de Transportistes). * **Guies** : Instruccions pràctiques i solucions de problemes específics, tant per a usuaris finals com desenvolupadors (exemple: Com instal·lar l’aplicació). * **Explicacions** : Coneixements en profunditat dels processos d’equip i estàndards (exemple: Team agreements i estàndards de codi). * **Referències** : Informació detallada per a desenvolupadors (exemple: ADRs, arquitectura del aplicatiu). Un següent pas que no vam arribar a implementar del tot va ser automatitzar la documentació tècnica mitjançant Event Catalog i AsyncAPI.
didacrios.cat
April 9, 2025 at 2:12 AM
Lean Software Development Muda
## Lean Software Development: Muda (I) Aquest estiu he revisat el llibre _Lean Software Development: An Agile Toolkit_ de Mary & Tom Poppendieck i aprofitaré per fer una serie d’articles resum dels punts que crec més interessants del llibre. En aquesta primera entrega parlarem del desperdici o el malbaratament (_waste, muda_). El desperdici (_waste, muda_) és tot allò que al client no li aporta un valor directe. Les pràctiques àgils en el desenvolupament de software busquen eliminar aquest desperdici, i el primer pas per fer-ho és saber-lo identificar. Una de les pràctiques _lean_ ens diu que per a identificar el desperdici cal classificar-lo, així que influenciats pels 7 desperdicis del _lean manufacturing_ es proposa classificar el desperdici en el desenvolupament de programari en 8 categories. ### Feina feta parcialment (_Partially Done Work_) Fa referencia a desenvolupaments que es queden a mitges i no s’arriben a desplegar en un entorn de producció, aquest tipus de desenvolupaments tendeixen a quedar-se obsolets en poc temps, interferint en el desenvolupament d’altres tasques que s’han de realitzar. El principal problema es que el que s’ha fet no s’arriba desplegar, per tant no hi ha _working software_, el que ens impossibilita obtenir feedback i saber si realment funciona, si causa algun efecte no previst en el sistema o si realment estem solucionant el problema que voliem solventar. S’ha de tenir en compte que en aquests desenvolupaments s’ha fet també una inversió en recursos (planificació, priorització, definició, disseny, codificació…), que encara no ha generat resultats, això implica que es “cancela una gran inversió”, convertint-se en un risc si ho extrapolem a nivell financer. Així doncs, el fet de reduir la feina parcialment redueix riscos i es converteix al mateix temps en una estrategia per a la reducció del desperdici. ### Processos extra (_Extra Processes_) T’has preguntat mai si la burocràcia i la paperassa són necessaris? La burocràcia consumeix recursos, és lenta, es perd, queda obsoleta, i molts cops ningú li fa cas. En el desenvolupament de programari, també hi ha burocràcia. Molts processos de desenvolupament requereixen d’omplir formularis de sol·licitud, requeriments, tests, actualitzar seguiments, reportar hores, documentar, etc. Planteja’t si realment, al client, tots aquest processos importen i l’ajuden a tenir un producte més valuós, i en el cas de que ho sigui, recorda aplicar aquestes 3 regles: Que sigui la minima possible (_Keep it short_). que sigui a alt nivell, clara i consisa. (_Keep it high level_) i que estigui fora del procés de desenvolupament. (_Do it off line_). En la majoria de desenvolupaments, hi ha requeriments escrits. En aquests casos, el fet que aquests requeriments siguin fàcilment accessibles i evaluats per a la seva comprovació es pot considerar una activitat que aporta valor. Estem parlant de taules i/o plantilles que fan que tant els clients com els desenvolupadors puguin ràpidament entendre i validar. L’utilització de pràctiques com BDD (_Behaviour Driven Design_), ATDD (_Acceptance Test-Driven Development_), _Specification by Example_ , reduirien el desperdici en tant que es consideren pràctiques que aporten valor. Una altra forma d’identificar si la burocràcia aporta valor o no es el fet d’identificar si hi ha algú que l’estigui esperant. Hi ha algú que escriu escenaris per a que es puguin interpretar i programar? Doncs probablement aquesta burocràcia aporta valor. Tot i això s’ha de treballar en millorar l’eficiencia en aquest sentit i buscar la millor manera de transmetre la informació, per exemple, no escriure requeriments i utilitzar pràctiques com les citades anteriorment o bé que els detalls d’implementació no fer-los massa aviat i limitar-se a aprofundir-hi en la iteració en la que s’haurien d’implementar. ### Funcionalitats extra (_Extra Features_) Pot semblar molt bona idea afegir funcionalitats extra, per si de cas es necessiten. Als programadors ens encanta afegir complexitat tècnica i funcionalitats extra. Això que ens pot semblar inofensiu, és un dels mes grans desperdicis. Cada linia de codi s’ha de compilar, integrar, testejar, desplegar i després, s’ha de mantenir. Cada linia de codi incrementa la complexitat i es un punt de fallida (_failure point_). Fins i tot hi ha la possibilitat de que aquella part de codi quedi obsoleta abans de que s’utilitzi, ja que en realitat mai s’ha arribat a demanar. Quan el codi no es necessita ara, és un desperdici. Que no us tempti la serp. ### Canvi de tasques (_Task Switching_) Gent treballant en multiples projectes és despedici de per se. Cada cop que un programador canvia de tasca, hi ha un lapse de temps significatiu en el que es despren de les referencies de l’antiga tasca i comença a entrar en la dinàmica de la nova (DeMarco & Lister, 2003). Si algú forma part de varis equips i projectes, les interrupcions i canvis de tasques es fan exponencials, tot això és desperdici. Així doncs la millor forma de completar 2 projectes que utilitzen els mateixos recursos, és fer-los un després de l’altre. Goldratt (1997) planteja que quan tens 2 projectes d’aproximadament 2 setmanes de duració cadascún, esperes tenir-los enllestits en 4 setmanes. Si els realitzes al mateix temps, al afegir els canvis de context el resultat final és que el tens més aviat en 5 setmanes enlloc de les 4. El fet d’afegir un excés de feina en el desenvolupament crea desperdici, fent que les coses vagin més lentes. Tot va més fluid per una canonada que no està plena (Poppendieck & Poppendieck, 2003). ### Esperant (_Waiting_) Un dels maxims desperdicis en el desenvolupament de programari es esperar a que les coses passin. Endarrerir l’inici d’un projecte, la conformació de l’equip, la confecció de requeriments, les revisions de codi, les proves, desplegar funcionalitats, tot això és desperdici. Els endarreriments son comuns i poden arribar a forma part de la normalitat i no veure’ls com a desperdici. Quin és el problema d’esperar? Les esperes fan que el client no rebi valor aviat. Quan el client vol implementar una necessitat o solucionar un problema la velocitat en la que obtindrà la solució anirà estrictament lligada a la velocitat en la que va el nostre proces de desenvolupament. En certs entorns, potser aquest no és un dels principals problemes. Però si que ho és si desenvolupes programari per a un domini en constant canvi, en el que s’han de prendre moltes decisions, i aquestes no són àgils. Un dels principis fonamentals de _lean_ és pospondre les decisions fins a l’ultim moment responsable (_the Last Responsible Moment_), de tal manera que puguis decidir més endavant, quan tingui més context. Aquesta és una de les millors formes de manejar la incertesa. Posposar una decisió també és una decisió. Es podria pensar que això i procrastinar ve a ser el mateix, però en realitat es una estrategia per evitar riscos. Una mala decisió feta molt al inici d’un projecte el pot comprometre per complet, ja sigui fent que el desenvolupament vagi molt més lent o lligar-se a infrastructures innecesaries, així que les decisions que s’han d’anar prenent han de ser decisions que no et collin massa, i siguin el maxim d’adaptables posibles. ### Moviment (_Motion_) Quan un programador té dubtes, que és el que ha de fer fins aconseguir una resposta? Hi ha gent disponible per solucionar problemes tècnics? I els funcionals? El client o el seu representant (PO, PM) està disponible per contestar-li? Pot el programador interpretar correctament la feina a fer de forma senzilla sense haver d’anar a trobar algun company? El desenvolupament de programari requereix d’una gran concentració, cada cop que se li plantegi alguna de les situacions anteriors li faran perdre el focus. Tenir l’equip disponible i treballant conjuntament fara que aquests no siguin grans problemes. La gent no es la única que es mou, els requeriments, la documentació, el codi, també està en constant moviment durant el cicle de desenvolupament. Traslladar tota aquesta informació és també un desperdici, tots aquests artefactes no poden contenir la totalitat de la informació, sempre hi ha informació que es retindrà en els seus creadors com a individual o grup. Es per això que també, traslladar aquests recursos entre diferents grups també és desperdici. ### Defectes (_Defects_) El principal desperdici causat pels defectes és l’impacte del defecte sobre el producte i el temps en que passa desapercebut. Un greu defecte que es localitza al cap de 3 minuts no és un gran desperdici. Però un petit problema que fa setmanes que ningú se n’ha adonat, es un desperdici molt més gran. Així doncs, per tal de reduir l’impacte dels defectes el millor és identificar-los el més aviat possible i per fer-ho cal testar, integrar, i desplegar el més aviat possible. ### Activitats de la gestió (_Management Activities_) Les activitats de gestió no afegixen valor directament a un producte, però tenen un gran impacte en el malbaratament en una organització. Considera per exemple el sistema de gestió de tàsques i projectes. En aquest cas minimitzar el desperdici implica mantenir al minim la feina fet a mitges, i això prové normalment de com es gestiona un projecte i les seves tasques. Si aquest sistema no va fluït probalement esdevingui en un gran generador de desperdici i malbaratament de recursos. Els sistemes de control i seguiment tampoc aporten valor, i si existeixen acostumen a indicar que hi ha massa feina a fer. En _lean manufacturing_ quan es parla d’un sistema _just-in-time_ , es parla d’un sistema en que la feina es realitza de forma eficient i flueix de tal forma que no es necessari el seu control amb sistemes complicats d’analisis i seguiments. Sistemes d’autorització per a la revisió i aprovació de canvis de requisits acostumen a aportar endarreriments enlloc de valor. Aquests sistemes també esdevenent simptoma d’un desperdici més gran lligat també a una definició previa i prematura de llargs requeriments. Aprendre a identificar el desperdici és un process constant de canviar la manera que tenim de pensar sobre el que realment és i no és necessàri. ## Bibliografia * DeMarco, T., & Lister, T. (2013). Peopleware: productive projects and teams. Addison-Wesley. * Goldratt, E. M. (1997). Critical chain: A business novel. Routledge. * Poppendieck, M., & Poppendieck, T. (2003). Lean software development: an agile toolkit. Addison-Wesley.
didacrios.cat
April 9, 2025 at 2:12 AM
Alias Per Les Connexions Ssh
## Alias de terminal Si hem de realitzar connexions a varis servidors, es fàcil que no recordem sempre les IP. Es aquí on podem utilitzar alias En Linux podem configurar alias de moltes maneres, bé podria ser des de la nostra terminal al `.bashrc` o `.zshrc`. Per exemple, si vull fer-me un alias d’access a la meva Raspberry PI i no anar sempre escribin l’usuari i la seva IP puc fer-me el seguent alias 1) Obrim el fitxer rc de la nostra terminal, en el meu cas Oh My nano ~/.zshrc 2) Afegim el alias alias ssh-rpi='ssh root@192.168.1.39' Reiniciem la terminal o refresquem el fitxer source ~/.zshrc I ara només ens cal utilitzar l’ordre i introduir la clau d’accés ssh-rpi ## Alternativa a alias de terminal Podem utilitzar el fitxer de configuració de ssh per configurar els diferents servidors amb un nom nano ~/.ssh/config Aquí podem configurar els nostres servidors amb un nom Host rpi Hostname 192.168.1.39 User root Ara només cal accedir al servidor ssh mitjançant la següent comanda ssh rpi ## Desant el login dels servidors ssh Anem un pas més enllà i podem guardar la clau d’accés amb la comanda `ssh-copy-id`. Aqui podrem utilitzar el nom que hem assignat al nostre servidor ssh-copy-id rpi Ens demanarà l’usuari per a l’usuari root de la nostra Raspberry PI I ara ja tenim accés sense haver d’introduir la contrasenya
didacrios.cat
April 9, 2025 at 2:12 AM
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.
didacrios.cat
April 9, 2025 at 2:12 AM
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. ## 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 * La metodología de desarrollo de Producto que utiliza Freshly Cosmetics para crecer a toda velocidad
didacrios.cat
April 9, 2025 at 2:12 AM
De software legacy a oportunitat estratègica: El punt de partida
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”. 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. * * * * * * 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.
didacrios.cat
April 9, 2025 at 2:12 AM
De software legacy a oportunitat estratègica: El punt de partida
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”. 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. * * * * * * 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.
didacrios.cat
January 30, 2025 at 10:14 PM
Comprendre el domini i construir l'equip: Les bases del canvi (II)
Al començar un projecte complex com el que estem abordant, és essencial tenir el màxim context possible, però tambe partir de zero en el coneixement del domini i anar explorant amb l’ajuda dels _domain experts_. Aquesta activitat no només ajuda a l’equip tècnic a alinear-se amb els objectius del negoci, sinó que també ajudar a fer-se un mapa global establint les bases per prendre millors decisions al llarg del cicle de vida del producte. Per entendre com funcionava l’aplicatiu existent, identificar els diferents procesos que s’executaven i saber com estaven representats al codi així com establir un llenguatge comú amb l’anterior equip i els usuaris actuals del aplicatiu vam realitzar unes primeres sessions que no van ser gaire fructíferes, fins al punt de valorar si podiem ferun traspàs més traumàtic prescindint d’aquestes i espavilar-nos pel nostre compte. ## EventStorming Al incorporar-me com a _tech lead_ des d’un principi vaig tenir clar que degut a la complexitat del projecte i si volia que l’equip tingués un _ownership_ real del producte haviem de donar un enfocament _domain-driven_ tant al projecte com a l’equip. Això ens permetria moure el domini al centre de la narrativa, d’aquesta manera alineariem tot l’equip al voltant d’un llenguatge comú (_ubiquitous language_) que ens facilitaria la comunicació i ens permetria fer un mapa de l’estat actual de l’aplicació. Així que un cop format aquest equip inicial vam començar a prepar sessions d’EventStorming. Aquesta metodologia visual ens va ajudar a descompondre els processos clau del sistema i identificar esdeveniments i entitats de domini rellevants. Per a facilitar les sessions vam utilitzar una plantilla de Miro que ja porta una mica de guía i llegenda de les referències claus que s’han de tenir en compte per enfocar una sessió d’aquest tipus. Si voleu fer una sessió vindria bé que els participans tinguin un mínim de noció d’alguns conceptes amb els que hauran de trrballar, ja sigui fent fer una mica de _prework_ o fer una explicació al iniciar la sessió. flowchart TD subgraph Legend["Llegenda Event Storming"] direction TB Event["Event"]:::event Command["Command"]:::command Aggregate["Aggregate"]:::aggregate Policy["Policy"]:::policy Actor["Actor"]:::actor Note["Note"]:::note end classDef event fill:#fc5e03,stroke:#782c00,stroke-width:2px,corner-radius:5px; classDef command fill:#00b2e8,stroke:#005c78,stroke-width:2px,corner-radius:5px; classDef aggregate fill:#ffbf00,stroke:#7a5c00,stroke-width:2px,corner-radius:5px; classDef policy fill:#6f00ff,stroke:#240054,stroke-width:2px,corner-radius:5px; classDef actor fill:#ffdd00,stroke:#756600,stroke-width:2px,corner-radius:5px; classDef note fill:#fa0000,stroke:#660000,stroke-width:2px,corner-radius:5px; Per maximitzar l’efectivitat de les sessions vam desenvolupar un procés estructurat en diverses fases: 1. **Exploració d’Events de Domini** (Foto inicial) * Identificar els esdeveniments clau del sistema * Ordenar-los cronològicament * Detectar gaps i dependències * Validar la seqüència amb els experts 2. **Refinament i Anàlisi** * Afegir notes explicatives * Documentar dubtes i preguntes * Entrar més en detall en cada esdeveniment * Marcar punts de decisió crítics 3. **Modelatge del Domini** * Identificar agregats (_aggregates_) i les seves fronteres * Definir actors i els seus rols * Establir comandes (_commands_) que inicien processos * Documentar polítiques (_policies_) i regles de negoci * Identificar triggers externs i interns de cada esdeveniment 4. **Documentació i Validació** * Netejar i organitzar la informació recollida * Establir relacions clares entre elements * Validar el model amb tots els stakeholders * Crear documentació de referència L’ _EventStorming_ no només ens va servir per entendre el domini, sinó que també va ser el punt de partida per aplicar els principis de _Domain-Driven Design (DDD)_ tant a nivell estratègic com tàctic. ### Domain-Driven Design Estratègic Un dels punts més importants en la fase inicial del projecte va ser decidir com estructurar el domini a nivell estratègic. La complexitat del sistema, combinada amb la necessitat d’alinear els objectius tècnics amb els del negoci, ens va portar a adoptar principis de Domain-Driven Design (DDD). Durant aquest procés, una de les eines més útils va ser el _Context Mapping_. Tot i que treballàvem amb un monolit encara pendent de refactorització, vam invertir temps a identificar diversos _Bounded Contexts_ dins del domini. A la pràctica, això volia dir que, tot i haver descrit i delimitat diversos contextos conceptuals, a nivell tècnic operàvem dins d’un únic _Bounded Context_ amb un sol _Shared Kernel_. Aquesta realitat monolítica no ens va impedir aprofitar els beneficis d’aquesta anàlisi. Encara que no aprofundíssim en el _Context Mapping_ de manera exhaustiva, utilitzar aquestes tècniques en aquesta etapa va ser clau per assegurar que el projecte tingués un camí clar cap a una arquitectura orientada al domini. Aquest enfocament no només facilita el desenvolupament tècnic, sinó que també promou una millor col·laboració entre els equips tècnics i els de negoci. #### Establint els Límits (_Bounded Contexts_) Identificar els _Bounded Contexts_ ens va permetre entendre millor com es relacionaven les diferents parts del sistema, tant entre si com amb els sistemes externs. Aquest exercici no només ens va ajudar a gestionar la complexitat de manera més eficient, sinó que també va establir una base clara per als passos evolutius posteriors del projecte. A mesura que el sistema evolucioni cap a una arquitectura més modular, aquestes decisions inicials serviran de guia per descompondre el monòlit en components més manejables i alineats amb els contextos definits També ens va ajudar a entendre on havíem de dirigir els esforços de desenvolupament i quines parts del sistema podien ser simplificades, desacoblades o eliminades. Tècnicament, ens vam centrar especialment en la implementació de _Anti-Corruption Layers_ (ACL), ja que ens permetien interactuar amb sistemes externs sense comprometre la integritat del nostre sistema. En el nostre cas, inicialment vam identificar cinc grans contexts clarament diferenciats: * Assignació de comandes * Generació d’etiquetes * Preparació de comandes * Integració E-commerce * Preparació de comandes massiu Aquestes decisions no només han establert els fonaments per a una arquitectura sostenible, sinó que també han garantit que els processos de desenvolupament siguin més focalitzats i alineats amb les necessitats del negoci. #### Llenguatge Ubic (_Ubiquitous language_) Un altre aspecte fonamental va ser establir un llenguatge ubic (_ubiquitous language_) sòlid. Els avantatges d’establir aquest llenguatge són molt superiors a qualsevol sobresforç de traducció o al risc de malinterpretar conceptes. Els experts de domini (_Domain Experts_) i els programadors han de coŀlaborar activament per crear aquest llenguatge comú, que va més enllà d’un simple glossari de termes. Es tracta d’un recurs viu i dinàmic que connecta l’equip tècnic amb els experts del domini. L’esforç en la seva implementació ha facilitat la comunicació, reduït malentesos i assegurat que el codi sigui una representació fidel del domini. Desenvolupar software no és només una qüestió tècnica; és una activitat basada en la comunicació i la coŀlaboració. Gràcies al llenguatge ubic, tots els membres de l’equip treballen alineats, cosa que resulta en solucions tècniques més eficients i que responen millor a les necessitats del negoci. ### _Domain-Driven Design_ Tàctic Un cop definit el marc estratègic, vam passar a implementar principis de DDD tàctic en el sistema. Això ens va permetre estructurar el codi de manera que reflectís la realitat del domini i fos més sostenible a llarg termini. #### Entitats (_Entities_) i Objectes de Valor (_Value Objects_) Les entitats (Entities) i els objectes de valor (Value Objects) són dos conceptes fonamentals en el Domain-Driven Design (DDD). Per entendre com funcionen, és important destacar les seves diferències i el paper que juguen dins del domini. #### Entitats (_Entities_) Les entitats són elements del domini que tenen una identitat única que perdura al llarg del temps, fins i tot si els seus atributs canvien. Aquesta identitat única és el que les distingeix d’altres elements del mateix tipus. A més, les entitats solen tenir un cicle de vida definit dins del sistema. Exemples d’entitats que vam identificar en el projecte són: * Order: Representa una ordre de compra amb una identitat única i un estat associat. * Product: Element del catàleg amb atributs com el codi SKU, preu i descripció. * Carrier: Empresa encarregada de lliurar les comandes amb opcions de servei específiques. * Shop: Identifica de quin e-commerce o plataforma ens ha arribat la comanda. * Customer: Persona o entitat que realitza la comanda i rep el producte. #### Objectes de Valor (Value Objects) Els objectes de valor, en canvi, són elements del domini que no tenen identitat pròpia. El seu valor és el que els defineix, i per això, dos objectes de valor amb els mateixos atributs són considerats equivalents. Això els fa immutables i ideals per encapsular conceptes clau que poden aparèixer en diverses parts del domini. Alguns exemples d’objectes de valor en el projecte inclouen: * ProductReference: Codi únic per identificar un producte. * ProductEan13: Codi de barres EAN-13 associat a un producte. * OrderReference: Identificador únic d’una comanda. * Price: Amb moneda i valor precís. * Weight: Amb unitats de mesura estandarditzades. * ShippingNumber: Número d’identificació per seguiment. Aquest enfocament ens ajuda a crear codi més comprensible i modular, ja que cada element del sistema té una responsabilitat clara i ben definida. Exemple d’un objecte de valor: <?php readonly class ProductEan13 { public string $value; public function __construct( string $value ) { $pattern = '/^\d{13}$/'; if (!preg_match($pattern, $value)) { throw new \Exception('Invalid product Ean13'); } $this->value = $value; } } #### Serveis (Services) En una aplicació complexa com la nostra, el concepte de Serveis juga un paper central en el manteniment d’un codi net i modular. Els serveis es classifiquen en diferents capes i tipus segons el seu propòsit i els patrons que implementen. Explorem l’estructura i els patrons que fem servir per organitzar i implementar serveis de manera efectiva. ##### Serveis de Domini Els Serveis de Domini encapsulen lògica de negoci que no encaixa directament en cap entitat o valor específic. Són serveis que operen estrictament dins de les regles del domini i no tenen dependències amb components d’infraestructura. <?php class CheapestCarrierGetter { public function get( DeliveryOptionCarrierCollection $deliveryOptionCarriers, Weight $orderWeight, Country $country, PostalCode $postalCode, bool $isCashOnDelivery = false, ): Carrier { // Lògica per obtenir el transportista més econòmic } } ##### Serveis d’Aplicació Els Serveis d’Aplicació encapsulen i coordinen lògica que combina operacions de domini amb interaccions externes per implementar escenaris específics de negoci o aplicació. Aquests serveis centralitzen i simplifiquen la implementació d’operacions complexes, assegurant una separació clara entre el domini i la infraestructura. Els més coneguts són els casos d’ús (use cases) però en el nostre cas també tindrem _Command Handlers_ i _Event Handlers_. graph TD ApplicationServices["Application Services"] --> UseCases["Use Cases"] ApplicationServices --> EventHandlers["Event Handlers"] ApplicationServices --> CommandHandlers["Command Handlers"] Els Use Cases representen accions o processos específics que l’aplicació necessita realitzar per complir amb els requisits de negoci. Encapsulen la lògica necessària per executar operacions complexes, incloent-hi interaccions amb serveis de domini i infraestructura, mantenint el domini net i focalitzat. Podriem dir que la seva responsabilitat hauria de ser nomes la d’orquestrar entre aquestes dues capes, i deixant la responsabilitat cap al domini, com diu Vaughn Vernon _“Keep Application Services thin, using them only to coordinate tasks on the model.”_ Els _Command Handlers_ són la porta d’entrada per a les modificacions en el domini. En rebre un _Command_ , validen la petició, deleguen la lògica de negoci als agregats corresponents i, finalment, publiquen un esdeveniment que reflecteix el canvi produït en el sistema. D’altra banda els _Event Handlers_ actuen com a _listeners_ a canvis en el sistema. Escolten esdeveniments i executen accions específiques en resposta, com ara enviar notificacions, actualitzar altres agregats o integrar-se amb sistemes externs. Aquesta reacció desacoblada permet construir sistemes més flexibles i escalables. Ampliaré els detalls i conceptes en pròximes entrades quan parlem sobre l’evolució de l’aplicatiu com a una arquitectura basada en events i sistemes de cues(Event-Driven Architecture, EDA). <?php readonly class NotifyShopOnOrderShipped implements EventHandlerInterface { public function __construct( private OrderRepositoryInterface $orderRepository, private ExternalOrderUpdaterFactory $externalOrderUpdaterFactory, private LoggerInterface $logger ) {} public function __invoke(OrderShippedDomainEvent $event): void { // Lògica per notificar la botiga quan una comanda ha estat enviada $order = $this->orderRepository->findById($event->getOrderId()); if (!$order) { $this->logger->error("Comanda no trobada", ['orderId' => $event->getOrderId()]); return; } $updater = $this->externalOrderUpdaterFactory->create($order); $updater->updateStatus('shipped'); $this->logger->info("Notificació d'enviament completada", ['orderId' => $order->getId()]); } } ##### Serveis d’Infraestructura Els Serveis d’Infraestructura implementen operacions que depenen de components externs com bases de dades, sistemes de fitxers o serveis de tercers. Sovint actuen com adaptadors per garantir que el domini es mantingui agnòstic a la implementació concreta. <?php class MonologLogger implements LoggerInterface { private $logger; public function __construct(Logger $logger) { $this->logger = $logger; } public function info(string $message, array $context = []): void { $this->logger->info($message, $context); } public function warning(string $message, array $context = []): void { $this->logger->warning($message, $context); } public function critical(string $message, array $context = []): void { $this->logger->critical($message, $context); } public function error(string $message, array $context = []): void { $this->logger->error($message, $context); } } ##### Classificació dels serveis Com hem vist, els serveis ens serveixen per desacoblar i descomposar lògica de la nostra aplicació d’una forma més granular i independent., aquí us deixo una classificació de serveis comuns que hem identificat en els nostre projecte, agrupant-los segons la seva funció principal i associant-los a patrons de disseny coneguts. Aquesta classificació ens permet tenir una visió més estructurada de la nostra arquitectura i facilita la presa de decisions a l’hora de dissenyar noves funcionalitats. Tipus de Servei | Descripció | Patró | Exemple ---|---|---|--- **Transformers** | Converteixen dades entre diferents formats o representacions. | _Adapter_ | Convertir respostes d’API externes en models de domini. **Builders** | Construeixen objectes complexos pas a pas. | _Builder_ | Crear un objecte `Order`. **Factories** | Creen objectes de domini assegurant que compleixen regles i restriccions. | _Factory_ | Crear instàncies de `Product`. **Presenters** | Donen format a les dades per a la interfície d’usuari o respostes d’API. | _Decorator_ | Enriquir dades per mostrar-les a l’usuari. **Notifiers** | Envien notificacions (correu, SMS, etc.). | _Observer_ | Notificar l’usuari de canvis importants. **Validators** | Asseguren que objectes compleixin regles de negoci. | _Strategy_ | Validar sol·licituds d’usuari o formularis. **Clients** | Interactuen amb aplicacions o serveis externs. | _Proxy_ | Consumir APIs externes per obtenir informació. * * * Tots aquests conceptes de domini són només una petita mostra de tot el que vam arribar a fer modelat. Evidentment, tampoc ho vam fer de cop ni vam encertar tot a la primera: hi ha moltes parts que encara van quedar pendents de reestructurar, conceptes que no vam acabar d’aclarir del tot i repositoris que sabíem que no tenien sentit, però que havíem de mantenir per funcionalitats, però que haviem d’acabar d’eliminar. Però amb aquesta feina feta inicialment, es va permetre que tot l’equip participés en aquest procés i tingués un compromís (_commitment_) per tot el que estàvem construint. Per aprofundir en aquests conceptes de DDD i com aplicar-los, recomano llegir els llibres següents: * “Domain-Driven Design: Tackling Complexity in the Heart of Software” d’Eric Evans: L’obra fundacional sobre DDD que introdueix i explica en profunditat els conceptes d’entitats i objectes de valor. * “Implementing Domain-Driven Design” de Vaughn Vernon: Un llibre pràctic que ofereix exemples concrets de com implementar DDD en projectes reals. * “Domain-Driven Design in PHP” de Carlos Buenosvinos, Christian Soronellas & Keyvan Akbary ## Construïnt equip El procés d’adopció de DDD va anar paraŀlel a la formació i evolució de l’equip. Aquí és on vull parlar del model d’etapes de Tuckman (1965): _Forming, Storming, Norming, Performing_ , ja que considero que l’evolució de l’equip va seguir aquesta seqüència i això ens va ajudar d’una banda a alinear les nostres pràctiques tècniques i d’altra a desenvolupar una cultura de col·laboració i confiança en l’equip. Tal com descriu Tuckman (1965), comprendre i abraçar aquestes etapes és clau per construir equips d’alt rendiment. La referència original pot trobar-se al seu treball: Tuckman, B. W. (1965). Developmental sequence in small groups. Psychological Bulletin, 63(6), 384–399. Segons aquest model, els equips passen per quatre fases distintives per arribar al màxim rendiment. Durant la fase inicial (_Forming_), els membres de l’equip s’introdueixen i defineixen objectius generals. A la fase de _Storming_ , emergeixen conflictes mentre es comencen a establir els rols. Amb el temps, en la fase de _Norming_ , els equips aconsegueixen una dinàmica de treball cohesionada, que culmina en _Performing_ , on es treballa de manera eficient cap als objectius comuns. ### Formació (_Forming_) L’equip es va formar inicialment amb dos desenvolupadors, que van començar revisant el projecte i documentant el seu funcionament, mentre altres membres tancaven els seus respectius projectes per incorporar-se en aquest. Per la meva banda em vaig incorporar com a _tech lead_ i vaig començar a repasar la nova documentació que s’havia generat i establir establir les bases tècniques i organitzatives del projecte i l’equip en quant a processos, estàndards i eines. ### Tempesta (_Storming_) No podríem dir que hi va haver grans desavinences dins l’equip, però sí que vam veure la necessitat de “regular” certs aspectes per tal d’anar tots més alineats. Es va fer més palesa aquesta necessitat quan vam incorporar dues persones més a l’equip i el _roadmap_ començava a prendre forma. Això va fer que ens plantegéssim com volíem treballar, comunicar-nos i sobretot com fer visibles totes aquestes decisions i coneixements en un projecte que estava en constant evolució. Així que rapidament vam passar a la fase de _Norming_ per establir les bases de com volíem treballar i com volíem organitzar-nos. ### Estandarització (_Norming_) Durant aquest període vam acordar diversos aspectes per facilitar el treball en equip: * Team Agreements: Normes per al treball en equip i la comunicació com la definició de cerimonies, horaris de reunions, canals de comunicació, etc. * Coding Standards: Guies per escriure codi net i mantenible seguint les bases de DDD, Arquitectura Hexagonal i principis SOLID. * Procés de Desenvolupament: Definició de les eines, processos i pràctiques a seguir per a mantenir un flux de treball eficient, amb l’objectiu de millorar la qualitat del codi i la productivitat de l’equip fomentant una cultura de col·laboració i aprenentatge. * Límits de WIP (Work In Progress): Per garantir un flux sostenible de treball. Té un capitol a part per reforçar la seva importància, com a part de la metodologia Lean a la que ens vam acostar. * Deployments: Regles per a desplegaments controlats i fiables, incloent les limitacions horàries i els procediments de rollback. * Deute Tècnic: Definició i gestió del deute tècnic acumulat així com facilitar un marc per identifcar-lo i prioritzar-lo si s’escau * ADR: Registre i justificació de decisions arquitectòniques per garantir la coherència i la traçabilitat de les decisions preses. ### Rendiment (_Performing_) Amb tota la feina feta en les etapes anteriors, havíem creat un marc de treball que ens permetia centrar-nos en el desenvolupament del producte de manera eficient i sense preocupacions, més enllà de les de prioritzar aquelles iniciatives que aportessin més valor en el context de cada moment. Això va permetre que l’equip es centressi en la implementació de funcionalitats de negoci a la vegada que es millorava la qualitat del codi, ens formavem i manteniem la documentació viva. ## Documentació Tot aquest esforç no tenia sentit si no es feia d’alguna manera visible. Ho vam documentar perquè estigués accessible en qualsevol moment i fàcil d’actualitzar. Utilitzàvem GitLab per gestionar el codi del projecte, així que vam activar la funcionalitat de GitLab Pages i després d’una mica d’investigació vam utilitzar Jekyll amb el tema Just the Docs. Per organitzar la informació, vam basar-nos en el model Diátaxis: * **Tutorials** : Guies per a funcionalitats del aplicatiu, destinades principalment a l’usuari final (exemple: Configuració de Transportistes). * **Guies** : Instruccions pràctiques i solucions de problemes específics, tant per a usuaris finals com desenvolupadors (exemple: Com instal·lar l’aplicació). * **Explicacions** : Coneixements en profunditat dels processos d’equip i estàndards (exemple: Team agreements i estàndards de codi). * **Referències** : Informació detallada per a desenvolupadors (exemple: ADRs, arquitectura del aplicatiu). Un següent pas que no vam arribar a implementar del tot va ser automatitzar la documentació tècnica mitjançant Event Catalog i AsyncAPI.
didacrios.cat
January 30, 2025 at 10:11 PM
Lean Software Development Muda
## Lean Software Development: Muda (I) Aquest estiu he revisat el llibre _Lean Software Development: An Agile Toolkit_ de Mary & Tom Poppendieck i aprofitaré per fer una serie d’articles resum dels punts que crec més interessants del llibre. En aquesta primera entrega parlarem del desperdici o el malbaratament (_waste, muda_). El desperdici (_waste, muda_) és tot allò que al client no li aporta un valor directe. Les pràctiques àgils en el desenvolupament de software busquen eliminar aquest desperdici, i el primer pas per fer-ho és saber-lo identificar. Una de les pràctiques _lean_ ens diu que per a identificar el desperdici cal classificar-lo, així que influenciats pels 7 desperdicis del _lean manufacturing_ es proposa classificar el desperdici en el desenvolupament de programari en 8 categories. ### Feina feta parcialment (_Partially Done Work_) Fa referencia a desenvolupaments que es queden a mitges i no s’arriben a desplegar en un entorn de producció, aquest tipus de desenvolupaments tendeixen a quedar-se obsolets en poc temps, interferint en el desenvolupament d’altres tasques que s’han de realitzar. El principal problema es que el que s’ha fet no s’arriba desplegar, per tant no hi ha _working software_, el que ens impossibilita obtenir feedback i saber si realment funciona, si causa algun efecte no previst en el sistema o si realment estem solucionant el problema que voliem solventar. S’ha de tenir en compte que en aquests desenvolupaments s’ha fet també una inversió en recursos (planificació, priorització, definició, disseny, codificació…), que encara no ha generat resultats, això implica que es “cancela una gran inversió”, convertint-se en un risc si ho extrapolem a nivell financer. Així doncs, el fet de reduir la feina parcialment redueix riscos i es converteix al mateix temps en una estrategia per a la reducció del desperdici. ### Processos extra (_Extra Processes_) T’has preguntat mai si la burocràcia i la paperassa són necessaris? La burocràcia consumeix recursos, és lenta, es perd, queda obsoleta, i molts cops ningú li fa cas. En el desenvolupament de programari, també hi ha burocràcia. Molts processos de desenvolupament requereixen d’omplir formularis de sol·licitud, requeriments, tests, actualitzar seguiments, reportar hores, documentar, etc. Planteja’t si realment, al client, tots aquest processos importen i l’ajuden a tenir un producte més valuós, i en el cas de que ho sigui, recorda aplicar aquestes 3 regles: Que sigui la minima possible (_Keep it short_). que sigui a alt nivell, clara i consisa. (_Keep it high level_) i que estigui fora del procés de desenvolupament. (_Do it off line_). En la majoria de desenvolupaments, hi ha requeriments escrits. En aquests casos, el fet que aquests requeriments siguin fàcilment accessibles i evaluats per a la seva comprovació es pot considerar una activitat que aporta valor. Estem parlant de taules i/o plantilles que fan que tant els clients com els desenvolupadors puguin ràpidament entendre i validar. L’utilització de pràctiques com BDD (_Behaviour Driven Design_), ATDD (_Acceptance Test-Driven Development_), _Specification by Example_ , reduirien el desperdici en tant que es consideren pràctiques que aporten valor. Una altra forma d’identificar si la burocràcia aporta valor o no es el fet d’identificar si hi ha algú que l’estigui esperant. Hi ha algú que escriu escenaris per a que es puguin interpretar i programar? Doncs probablement aquesta burocràcia aporta valor. Tot i això s’ha de treballar en millorar l’eficiencia en aquest sentit i buscar la millor manera de transmetre la informació, per exemple, no escriure requeriments i utilitzar pràctiques com les citades anteriorment o bé que els detalls d’implementació no fer-los massa aviat i limitar-se a aprofundir-hi en la iteració en la que s’haurien d’implementar. ### Funcionalitats extra (_Extra Features_) Pot semblar molt bona idea afegir funcionalitats extra, per si de cas es necessiten. Als programadors ens encanta afegir complexitat tècnica i funcionalitats extra. Això que ens pot semblar inofensiu, és un dels mes grans desperdicis. Cada linia de codi s’ha de compilar, integrar, testejar, desplegar i després, s’ha de mantenir. Cada linia de codi incrementa la complexitat i es un punt de fallida (_failure point_). Fins i tot hi ha la possibilitat de que aquella part de codi quedi obsoleta abans de que s’utilitzi, ja que en realitat mai s’ha arribat a demanar. Quan el codi no es necessita ara, és un desperdici. Que no us tempti la serp. ### Canvi de tasques (_Task Switching_) Gent treballant en multiples projectes és despedici de per se. Cada cop que un programador canvia de tasca, hi ha un lapse de temps significatiu en el que es despren de les referencies de l’antiga tasca i comença a entrar en la dinàmica de la nova (DeMarco & Lister, 2003). Si algú forma part de varis equips i projectes, les interrupcions i canvis de tasques es fan exponencials, tot això és desperdici. Així doncs la millor forma de completar 2 projectes que utilitzen els mateixos recursos, és fer-los un després de l’altre. Goldratt (1997) planteja que quan tens 2 projectes d’aproximadament 2 setmanes de duració cadascún, esperes tenir-los enllestits en 4 setmanes. Si els realitzes al mateix temps, al afegir els canvis de context el resultat final és que el tens més aviat en 5 setmanes enlloc de les 4. El fet d’afegir un excés de feina en el desenvolupament crea desperdici, fent que les coses vagin més lentes. Tot va més fluid per una canonada que no està plena (Poppendieck & Poppendieck, 2003). ### Esperant (_Waiting_) Un dels maxims desperdicis en el desenvolupament de programari es esperar a que les coses passin. Endarrerir l’inici d’un projecte, la conformació de l’equip, la confecció de requeriments, les revisions de codi, les proves, desplegar funcionalitats, tot això és desperdici. Els endarreriments son comuns i poden arribar a forma part de la normalitat i no veure’ls com a desperdici. Quin és el problema d’esperar? Les esperes fan que el client no rebi valor aviat. Quan el client vol implementar una necessitat o solucionar un problema la velocitat en la que obtindrà la solució anirà estrictament lligada a la velocitat en la que va el nostre proces de desenvolupament. En certs entorns, potser aquest no és un dels principals problemes. Però si que ho és si desenvolupes programari per a un domini en constant canvi, en el que s’han de prendre moltes decisions, i aquestes no són àgils. Un dels principis fonamentals de _lean_ és pospondre les decisions fins a l’ultim moment responsable (_the Last Responsible Moment_), de tal manera que puguis decidir més endavant, quan tingui més context. Aquesta és una de les millors formes de manejar la incertesa. Posposar una decisió també és una decisió. Es podria pensar que això i procrastinar ve a ser el mateix, però en realitat es una estrategia per evitar riscos. Una mala decisió feta molt al inici d’un projecte el pot comprometre per complet, ja sigui fent que el desenvolupament vagi molt més lent o lligar-se a infrastructures innecesaries, així que les decisions que s’han d’anar prenent han de ser decisions que no et collin massa, i siguin el maxim d’adaptables posibles. ### Moviment (_Motion_) Quan un programador té dubtes, que és el que ha de fer fins aconseguir una resposta? Hi ha gent disponible per solucionar problemes tècnics? I els funcionals? El client o el seu representant (PO, PM) està disponible per contestar-li? Pot el programador interpretar correctament la feina a fer de forma senzilla sense haver d’anar a trobar algun company? El desenvolupament de programari requereix d’una gran concentració, cada cop que se li plantegi alguna de les situacions anteriors li faran perdre el focus. Tenir l’equip disponible i treballant conjuntament fara que aquests no siguin grans problemes. La gent no es la única que es mou, els requeriments, la documentació, el codi, també està en constant moviment durant el cicle de desenvolupament. Traslladar tota aquesta informació és també un desperdici, tots aquests artefactes no poden contenir la totalitat de la informació, sempre hi ha informació que es retindrà en els seus creadors com a individual o grup. Es per això que també, traslladar aquests recursos entre diferents grups també és desperdici. ### Defectes (_Defects_) El principal desperdici causat pels defectes és l’impacte del defecte sobre el producte i el temps en que passa desapercebut. Un greu defecte que es localitza al cap de 3 minuts no és un gran desperdici. Però un petit problema que fa setmanes que ningú se n’ha adonat, es un desperdici molt més gran. Així doncs, per tal de reduir l’impacte dels defectes el millor és identificar-los el més aviat possible i per fer-ho cal testar, integrar, i desplegar el més aviat possible. ### Activitats de la gestió (_Management Activities_) Les activitats de gestió no afegixen valor directament a un producte, però tenen un gran impacte en el malbaratament en una organització. Considera per exemple el sistema de gestió de tàsques i projectes. En aquest cas minimitzar el desperdici implica mantenir al minim la feina fet a mitges, i això prové normalment de com es gestiona un projecte i les seves tasques. Si aquest sistema no va fluït probalement esdevingui en un gran generador de desperdici i malbaratament de recursos. Els sistemes de control i seguiment tampoc aporten valor, i si existeixen acostumen a indicar que hi ha massa feina a fer. En _lean manufacturing_ quan es parla d’un sistema _just-in-time_ , es parla d’un sistema en que la feina es realitza de forma eficient i flueix de tal forma que no es necessari el seu control amb sistemes complicats d’analisis i seguiments. Sistemes d’autorització per a la revisió i aprovació de canvis de requisits acostumen a aportar endarreriments enlloc de valor. Aquests sistemes també esdevenent simptoma d’un desperdici més gran lligat també a una definició previa i prematura de llargs requeriments. Aprendre a identificar el desperdici és un process constant de canviar la manera que tenim de pensar sobre el que realment és i no és necessàri. ## Bibliografia * DeMarco, T., & Lister, T. (2013). Peopleware: productive projects and teams. Addison-Wesley. * Goldratt, E. M. (1997). Critical chain: A business novel. Routledge. * Poppendieck, M., & Poppendieck, T. (2003). Lean software development: an agile toolkit. Addison-Wesley.
didacrios.cat
January 30, 2025 at 10:10 PM
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.
didacrios.cat
January 30, 2025 at 10:10 PM
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. ## 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 * La metodología de desarrollo de Producto que utiliza Freshly Cosmetics para crecer a toda velocidad
didacrios.cat
January 30, 2025 at 10:10 PM
Alias Per Les Connexions Ssh
## Alias de terminal Si hem de realitzar connexions a varis servidors, es fàcil que no recordem sempre les IP. Es aquí on podem utilitzar alias En Linux podem configurar alias de moltes maneres, bé podria ser des de la nostra terminal al `.bashrc` o `.zshrc`. Per exemple, si vull fer-me un alias d’access a la meva Raspberry PI i no anar sempre escribin l’usuari i la seva IP puc fer-me el seguent alias 1) Obrim el fitxer rc de la nostra terminal, en el meu cas Oh My nano ~/.zshrc 2) Afegim el alias alias ssh-rpi='ssh root@192.168.1.39' Reiniciem la terminal o refresquem el fitxer source ~/.zshrc I ara només ens cal utilitzar l’ordre i introduir la clau d’accés ssh-rpi ## Alternativa a alias de terminal Podem utilitzar el fitxer de configuració de ssh per configurar els diferents servidors amb un nom nano ~/.ssh/config Aquí podem configurar els nostres servidors amb un nom Host rpi Hostname 192.168.1.39 User root Ara només cal accedir al servidor ssh mitjançant la següent comanda ssh rpi ## Desant el login dels servidors ssh Anem un pas més enllà i podem guardar la clau d’accés amb la comanda `ssh-copy-id`. Aqui podrem utilitzar el nom que hem assignat al nostre servidor ssh-copy-id rpi Ens demanarà l’usuari per a l’usuari root de la nostra Raspberry PI I ara ja tenim accés sense haver d’introduir la contrasenya
didacrios.cat
January 30, 2025 at 10:10 PM