paint-brush
Com afrontar la complexitat en dissenyar sistemes de programariper@fairday
64,370 lectures
64,370 lectures

Com afrontar la complexitat en dissenyar sistemes de programari

per Aleksei23m2024/02/05
Read on Terminal Reader
Read this story w/o Javascript

Massa Llarg; Per llegir

La complexitat és l'enemic! Aprenem a afrontar-ho!
featured image - Com afrontar la complexitat en dissenyar sistemes de programari
Aleksei HackerNoon profile picture

De què es tracta?

Cada dia, cada moment de la nostra carrera d'enginyer, ens trobem amb molts problemes diferents de complexitat diversa i situacions en què hem de prendre una decisió o ajornar-la per manca de dades. Sempre que construïm nous serveis, construïm infraestructures o fins i tot formem processos de desenvolupament, toquem un món enorme amb diversos reptes.


És un repte, i potser fins i tot impossible, enumerar tots els problemes. Trobareu alguns d'aquests problemes només si treballeu en un nínxol específic. D'altra banda, n'hi ha moltes que tots hem d'entendre com resoldre, ja que són crucials per construir sistemes informàtics. Amb una alta probabilitat, els trobareu en tots els projectes.


En aquest article, compartiré les meves experiències amb alguns dels problemes que he trobat durant la creació de programes.

Què és la preocupació transversal?

Si mirem a la Viquipèdia, trobarem la següent definició


En el desenvolupament de programari orientat a aspectes, les preocupacions transversals són aspectes d'un programa que afecten diversos mòduls, sense possibilitat d'encapsular-se en cap d'ells. Aquestes preocupacions sovint no es poden descompondre clarament de la resta del sistema tant en el disseny com en la implementació, i poden provocar dispersió (duplicació de codi), embolcalls (dependències significatives entre sistemes) o ambdues coses.


Descriu molt què és, però vull ampliar-ho i simplificar-ho una mica:

Una preocupació transversal és un concepte o component del sistema/organització que afecta (o "talla") moltes altres parts.


Els millors exemples d'aquestes preocupacions són l'arquitectura del sistema, el registre, la seguretat, la gestió de transaccions, la telemetria, el disseny de bases de dades i molts altres. Anem a elaborar molts d'ells més endavant en aquest article.


A nivell de codi, les preocupacions transversals sovint s'implementen utilitzant tècniques com la programació orientada a aspectes (AOP) , on aquestes preocupacions es modulareixen en components separats que es poden aplicar a tota l'aplicació. Això manté la lògica empresarial aïllada d'aquestes preocupacions, fent que el codi sigui més llegible i fàcil de mantenir.

Classificació d'aspectes

Hi ha moltes maneres possibles de classificar els aspectes segmentant-los amb diferents propietats com l'abast, la mida, la funcionalitat, la importància, l'objectiu i altres, però en aquest article faré servir una classificació d'abast senzilla. Amb això vull dir cap a on es dirigeix aquest aspecte específic, ja sigui tota l'organització, un sistema particular o un element específic d'aquest sistema.


Per tant, dividiré els aspectes en Macro i Micro .


Per aspecte macro , entenc principalment consideracions que seguim per a tot el sistema, com l'arquitectura del sistema escollida i el seu disseny (monolític, microserveis, arquitectura orientada a serveis), pila tecnològica, estructura organitzativa, etc. Els aspectes macro es relacionen principalment amb l'estratègia i l'alt nivell. decisions.


Mentrestant, l'aspecte Micro està molt més a prop del nivell de codi i desenvolupament. Per exemple, quin marc s'utilitza per interactuar amb la base de dades, l'estructura del projecte de carpetes i classes, o fins i tot patrons de disseny d'objectes específics.


Tot i que aquesta classificació no és ideal, ajuda a estructurar una comprensió dels possibles problemes i la importància i l'impacte de les solucions que els apliquem.


En aquest article, el meu enfocament principal se centrarà en els aspectes macro.

Aspectes macro

Estructura organitzativa

Quan vaig començar a conèixer l'arquitectura del programari, vaig llegir molts articles interessants sobre la llei de Conway i el seu impacte en l'estructura organitzativa. Sobretot aquest . Així doncs, aquesta llei ho diu


Qualsevol organització que dissenyi un sistema (definit de manera àmplia) produirà un disseny l'estructura del qual és una còpia de l'estructura de comunicació de l'organització.


Sempre he cregut que aquest concepte és realment molt universal i representa la regla d'or.


Llavors vaig començar a aprendre l'enfocament de disseny impulsat per dominis (DDD) d'Eric Evans per a sistemes de modelització. Eric Evans subratlla la importància de la identificació del context limitat. Aquest concepte implica dividir un model de domini complex en seccions més petites i més manejables, cadascuna amb el seu propi conjunt limitat de coneixements. Aquest enfocament ajuda a una comunicació eficaç en equip, ja que redueix la necessitat d'un coneixement ampli de tot el domini i minimitza el canvi de context, fent que les converses siguin més eficients. El canvi de context és el pitjor i que consumeix més recursos. Fins i tot els ordinadors lluiten. Encara que és poc probable que s'aconsegueixi una absència total de canvi de context, crec que això és el que hauríem d'esforçar-nos.


Fantasy about keeping in mind a lot of bounded contexts

Tornant a la llei de Conway, hi he trobat diversos problemes.


El primer problema que he trobat amb la Llei de Conway, que suggereix que el disseny del sistema reflecteix l'estructura organitzativa, és el potencial per formar Contextos limitats complexos i complets. Aquesta complexitat sorgeix quan l'estructura organitzativa no està alineada amb els límits del domini, donant lloc a Contextos limitats que són molt interdependents i carregats d'informació. Comporta un canvi de context freqüent per a l'equip de desenvolupament.


Un altre problema és que la terminologia organitzativa es filtra al nivell de codi. Quan les estructures organitzatives canvien, calen modificacions de la base de codi, consumint recursos valuosos.


Així, seguir la maniobra de Conway inversa ajuda a construir el sistema i l'organització que fomenten l'arquitectura de programari desitjada. No obstant això, cal destacar que aquest enfocament no funcionarà molt bé en l'arquitectura i les estructures ja formades, ja que els canvis en aquesta etapa es prolonguen, però té un rendiment excepcional a les startups, ja que s'introdueixen ràpidament els canvis.

Gran Bola de Fang

Aquest patró o "anti-patró" impulsa la construcció d'un sistema sense cap arquitectura. No hi ha regles, ni límits, ni estratègia sobre com controlar la inevitable complexitat creixent. La complexitat és l'enemic més formidable en el viatge de la construcció de sistemes de programari.


Entertaining illustration made by ChatGPT

Per evitar construir aquest tipus de sistema, hem de seguir regles i restriccions específiques.

Arquitectura del sistema

Hi ha infinitat de definicions per a l'arquitectura de programari. M'agraden molts d'ells, ja que en cobreixen diferents aspectes. Tanmateix, per poder raonar sobre l'arquitectura, necessitem, naturalment, formar-ne algunes en la nostra ment. I és remarcable dir que aquesta definició pot evolucionar. Així que, almenys de moment, tinc la següent descripció per a mi.


L'arquitectura de programari tracta de decisions i eleccions que feu cada dia que afecten el sistema construït.


Per prendre decisions que necessiteu tenir a la vostra “bossa” principis i patrons per resoldre els problemes que sorgeixen, també és essencial afirmar que entendre els requisits és clau per construir allò que necessita una empresa. Tanmateix, de vegades els requisits no són transparents o fins i tot no estan definits, en aquest cas, és millor esperar per obtenir més aclariments o confiar en la vostra experiència i confiar en la vostra intuïció. Però de totes maneres, no podeu prendre decisions correctament si no teniu principis i patrons en què confiar. És aquí on arribo a la definició de l'estil d'arquitectura de programari.


L'estil d'arquitectura de programari és un conjunt de principis i patrons que designen com crear programari.


Hi ha molts estils arquitectònics diferents centrats en diversos aspectes de l'arquitectura planificada, i aplicar-ne múltiples alhora és una situació normal.


Per exemple, com ara:

  1. Arquitectura monolítica

  2. Disseny basat en dominis

  3. Basat en components

  4. Microserveis

  5. Tubs i filtres

  6. Impulsat per esdeveniments

  7. Microkernel

  8. Orientat al servei


i així successivament…


Per descomptat, tenen els seus avantatges i els seus inconvenients, però el més important que he après és que l'arquitectura evoluciona gradualment depenent dels problemes reals. Començar per l'arquitectura monolítica és una opció fantàstica per reduir les complexitats operatives, és molt probable que aquesta arquitectura s'adapti a les vostres necessitats fins i tot després d'arribar a l'etapa Product-market Fit (PMI) de la creació del producte. A escala, podeu considerar avançar cap a un enfocament basat en esdeveniments i microserveis per aconseguir un desplegament independent, un entorn de pila tecnològic heterogeni i una arquitectura menys acoblada (i menys transparent mentrestant a causa de la naturalesa dels enfocaments basats en esdeveniments i pub-sub si aquests s'adopten). La senzillesa i l'eficiència estan a prop i tenen un gran impacte mútuament. Normalment, les arquitectures complicades afecten la velocitat de desenvolupament de noves característiques, donant suport i mantenint les existents i desafiant l'evolució natural del sistema.


Tanmateix, els sistemes complexos sovint requereixen una arquitectura complexa i completa, la qual cosa és inevitable.


Justament, aquest és un tema molt ampli, i hi ha moltes idees fantàstiques sobre com estructurar i construir sistemes per a l'evolució natural. A partir de la meva experiència, he elaborat el següent enfocament:

  1. Gairebé sempre comença amb l'estil d'arquitectura monolítica ja que elimina la majoria dels problemes que sorgeixen per la naturalesa dels sistemes distribuïts. També té sentit seguir un monòlit modular per centrar-se en la construcció de components amb límits clars. L'aplicació d'un enfocament basat en components podria ajudar-los a comunicar-se entre ells mitjançant l'ús d'esdeveniments, però tenir trucades directes (també conegut com RPC) simplifica les coses al principi. Tanmateix, és important fer un seguiment de les dependències entre components, ja que si el component A sap molt sobre el component B, potser té sentit combinar-los en un.
  2. Quan us acosteu a la situació en què necessiteu escalar el vostre desenvolupament i sistema, podeu considerar seguir el patró de Stangler per extreure gradualment components que s'han de desplegar de manera independent o fins i tot escalar amb requisits específics.
  3. Ara, si tens una visió clara del futur, que és una mica de sort increïble, pots decidir-te per l'arquitectura desitjada. En aquest moment, podeu decidir avançar cap a l'arquitectura de microserveis aplicant també enfocaments d'orquestració i coreografia, incorporant el patró CQRS per a operacions d'escriptura i lectura a escala independent o fins i tot decidint quedar-vos amb l'arquitectura monolítica si s'adapta a les vostres necessitats.


També és vital entendre els números i mètriques com DAU (Usuaris actius diaris), MAU (Usuaris actius mensuals), RPC (Sol·licitud per segon) i TPC (Transacció per segon), ja que us podria ajudar a prendre decisions perquè l'arquitectura per a 100 usuaris actius i 100 milions d'usuaris actius són diferents.


Com a nota final, diria que l'arquitectura té un impacte significatiu en l'èxit del producte. Es requereix una arquitectura mal dissenyada per als productes en l'escala, la qual cosa probablement condueixi a un fracàs, ja que els clients no esperaran mentre escala el sistema, sinó que triaran un competidor, per la qual cosa hem d'anar per davant de l'escalat potencial. Tot i que admeto que de vegades no podria ser un enfocament lleuger, la idea és tenir un sistema escalable però no escalable. D'altra banda, tenir un sistema molt complicat i ja escalat sense clients ni plans per aconseguir-ne molts us costarà diners en el vostre negoci per res.

Selecció de pila de tecnologia

La selecció d'una pila de tecnologia també és una decisió a nivell macro, ja que influeix en la contractació, les perspectives d'evolució natural del sistema, l'escalabilitat i el rendiment del sistema.


Aquesta és la llista de consideracions bàsiques per triar una pila de tecnologia:

  • Requisits i complexitat del projecte. Per exemple, es pot crear una aplicació web senzilla amb el marc Blazor si els vostres desenvolupadors tenen experiència amb ell, però a causa de la manca de maduresa de WebAssembly, escollir React i Typescript per tenir èxit a llarg termini podria ser una millor decisió.
  • Necessitats d'escalabilitat i rendiment. Si preveu rebre una gran quantitat de trànsit, optar per ASP.NET Core sobre Django podria ser una opció sàvia a causa del seu rendiment superior en la gestió de sol·licituds concurrents. Tanmateix, aquesta decisió depèn de l'escala de trànsit que espereu. Si necessiteu gestionar potencialment milers de milions de sol·licituds amb una latència baixa, la presència de Garbage Collection podria ser un repte.
  • Contractació, temps de desenvolupament i cost. En la majoria dels casos, aquests són els factors que hem de tenir en compte. El temps per al mercat, el cost de manteniment i l'estabilitat de la contractació impulsen les necessitats del vostre negoci sense obstacles.
  • Experiència i recursos de l'equip. El conjunt d'habilitats del vostre equip de desenvolupament és un factor crític. En general, és més eficaç utilitzar tecnologies que el vostre equip ja coneix, tret que hi hagi una raó sòlida per invertir en l'aprenentatge d'una pila nova.
  • Maduresa. Una comunitat sòlida i un ecosistema ric de biblioteques i eines poden facilitar molt el procés de desenvolupament. Les tecnologies populars sovint tenen un millor suport de la comunitat, que pot ser inestimable per resoldre problemes i trobar recursos. Així, podríeu estalviar recursos i centrar-vos principalment en el producte.
  • Manteniment i suport a llarg termini. Considereu la viabilitat a llarg termini de la tecnologia. Les tecnologies que s'adopten i s'admeten àmpliament tenen menys probabilitats de quedar obsoletes i, en general, reben actualitzacions i millores periòdiques.


Com pot afectar el creixement empresarial tenir múltiples piles de tecnologia?

Des d'una perspectiva, introduir una pila més podria augmentar la vostra contractació, però d'altra banda, comporta costos de manteniment addicionals, ja que heu de donar suport a les dues piles. Per tant, com he dit anteriorment, des del meu punt de vista, només una necessitat addicional hauria de ser un argument per incorporar més piles de tecnologia.


Però, què passa amb el principi de seleccionar la millor eina per a un problema específic?

De vegades no us queda més remei que aportar noves eines per resoldre un problema concret a partir de les mateixes consideracions esmentades anteriorment, en aquests casos, té sentit seleccionar la millor solució.


La creació de sistemes sense acoblament elevat a una tecnologia específica podria ser un repte. Tot i així, és útil lluitar per una condició en què el sistema no estigui estretament vinculat a la tecnologia i no morirà si demà, un marc o una eina específics esdevenen vulnerables o fins i tot obsolets.


Una altra consideració important està relacionada amb les dependències de codi obert i programari propietari. El programari propietari us ofereix menys flexibilitat i la possibilitat de ser personalitzat. Tot i així, el factor més perillós és el bloqueig del venedor, on es depèn dels productes, preus, condicions i full de ruta d'un venedor. Això pot ser arriscat si el venedor canvia de direcció, augmenta els preus o deixa de fabricar el producte. El programari de codi obert redueix aquest risc, ja que una sola entitat no el controla. Eliminar un únic punt de fallada a tots els nivells és clau per construir sistemes fiables per al creixement.

Punt únic de fallada (SPOF)

Un punt únic d'error (SPOF) fa referència a qualsevol part d'un sistema que, si falla, farà que tot el sistema deixi de funcionar. L'eliminació dels SPOF a tots els nivells és crucial per a qualsevol sistema que requereixi una alta disponibilitat. Tot, inclòs el coneixement, el personal, els components del sistema, els proveïdors de núvol i els cables d'Internet, pot fallar.


Hi ha diverses tècniques bàsiques que podríem aplicar per eliminar punts únics de fallada:

  1. Redundància. Implementar redundància per a components crítics. Això vol dir tenir components de còpia de seguretat que es poden fer càrrec si falla el component principal. La redundància es pot aplicar a diferents capes del sistema, incloent maquinari (servidors, discs), xarxes (enllaços, commutadors) i programari (bases de dades, servidors d'aplicacions). Si ho allotgeu tot en un proveïdor de núvol i fins i tot hi teniu còpies de seguretat, considereu la possibilitat de crear una còpia de seguretat addicional regular en un altre per reduir el cost perdut en cas de desastre.
  2. Centres de dades. Distribuïu el vostre sistema en diverses ubicacions físiques, com ara centres de dades o regions del núvol. Aquest enfocament protegeix el vostre sistema contra fallades específiques de la ubicació, com ara talls de llum o desastres naturals.
  3. Failover. Apliqueu un enfocament de failover per a tots els vostres components (DNS, CDN, equilibradors de càrrega, Kubernetes, passarel·les API i bases de dades). Com que els problemes poden sorgir de manera inesperada, és crucial tenir un pla de còpia de seguretat per substituir qualsevol component pel seu clon amb rapidesa.
  4. Serveis d'alta disponibilitat. Assegureu-vos que els vostres serveis estiguin dissenyats per ser escalables horitzontalment i altament disponibles des del principi, seguint els principis següents:
    • Practiqueu l'apatridia del servei i eviteu emmagatzemar sessions d'usuari en memòria cau a memòria cau. En comptes d'això, utilitzeu un sistema de memòria cau distribuïda, com ara Redis.
    • Eviteu dependre de l'ordre cronològic del consum de missatges a l'hora de desenvolupar la lògica.
    • Minimitzeu els canvis de ruptura per evitar que interrompin els consumidors de l'API. Sempre que sigui possible, opteu per canvis compatibles amb les versions anteriors. A més, tingueu en compte el cost, ja que de vegades, implementar un canvi de ruptura pot ser més rendible.
    • Incorporeu l'execució de la migració al pipeline de desplegament.
    • Establir una estratègia per gestionar les sol·licituds concurrents.
    • Implementeu la descoberta, la supervisió i el registre de serveis per millorar la fiabilitat i l'observabilitat.
    • Desenvolupar una lògica de negoci per ser idempotent, reconeixent que les fallades de la xarxa són inevitables.
  5. Revisió de la dependència. Revisar i minimitzar regularment les dependències externes. Cada dependència externa pot introduir possibles SPOF, per la qual cosa és essencial comprendre i mitigar aquests riscos.
  6. Repartiment regular de coneixements. No oblideu mai la importància de difondre el coneixement dins de la vostra organització. Les persones poden ser imprevisibles i confiar en un sol individu és arriscat. Animar els membres de l'equip a digitalitzar els seus coneixements mitjançant la documentació. Tanmateix, tingueu en compte l'excés de documentació. Utilitzeu diverses eines d'IA per simplificar aquest procés.

Conclusió

En aquest article, vam tractar diversos aspectes clau de macro i com podem fer front a la seva complexitat.


Gràcies per llegir! Ens veiem la propera vegada!