paint-brush
Como xestionar a complexidade ao deseñar sistemas de softwarepor@fairday
64,464 lecturas
64,464 lecturas

Como xestionar a complexidade ao deseñar sistemas de software

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

Demasiado longo; Ler

A complexidade é o inimigo! Imos aprender a tratar con iso!
featured image - Como xestionar a complexidade ao deseñar sistemas de software
Aleksei HackerNoon profile picture

De que se trata?

Todos os días, en cada momento da nosa carreira de enxeñeiro, atopamos moitos problemas diferentes de complexidade variada e situacións nas que necesitamos tomar unha decisión ou aprazala por falta de datos. Sempre que construímos novos servizos, construímos infraestruturas ou mesmo formamos procesos de desenvolvemento, tocamos un mundo enorme de varios desafíos.


É un reto, e quizais mesmo imposible, enumerar todos os problemas. Atoparás algúns destes problemas só se traballas nun nicho específico. Por outra banda, hai moitos que todos debemos entender como resolver, xa que son fundamentais para construír sistemas informáticos. Cunha alta probabilidade, atoparase con eles en todos os proxectos.


Neste artigo, compartirei as miñas experiencias con algúns dos problemas que atopei ao crear programas de software.

Que é a preocupación transversal?

Se miramos na Wikipedia, atoparemos a seguinte definición


No desenvolvemento de software orientado a aspectos, as preocupacións transversais son aspectos dun programa que afectan a varios módulos, sen posibilidade de estar encapsulados en ningún deles. Moitas veces, estas preocupacións non poden descompoñerse limpamente do resto do sistema tanto no deseño como na implementación, e poden producir dispersión (duplicación de código), enredos (dependencias significativas entre sistemas) ou ambos.


Describe moi ben o que é, pero quero amplialo e simplificalo un pouco:

Unha preocupación transversal é un concepto ou compoñente do sistema/organización que afecta (ou atravesa) moitas outras partes.


Os mellores exemplos de tales problemas son a arquitectura do sistema, o rexistro, a seguridade, a xestión de transaccións, a telemetría, o deseño de bases de datos e hai moitos outros. Imos elaborar moitos deles máis adiante neste artigo.


A nivel de código, as preocupacións transversais adoitan implementarse mediante técnicas como a Programación Orientada a Aspectos (AOP) , onde estas preocupacións se modularizan en compoñentes separados que se poden aplicar en toda a aplicación. Isto mantén a lóxica empresarial illada destas preocupacións, facendo que o código sexa máis lexible e mantible.

Clasificación de aspectos

Hai moitas formas posibles de clasificar os aspectos segmentándoos con diferentes propiedades como alcance, tamaño, funcionalidade, importancia, destino e outras, pero neste artigo vou usar unha clasificación de ámbito sinxela. Con isto, quero dicir cara a onde se dirixe este aspecto específico, xa sexa a organización enteira, un sistema particular ou un elemento específico dese sistema.


Entón, vou dividir os aspectos en Macro e Micro .


Por aspecto macro refírome principalmente a consideracións que seguimos para todo o sistema, como a arquitectura do sistema escollida e o seu deseño (monolítico, microservizos, arquitectura orientada a servizos), pila tecnolóxica, estrutura organizativa, etc. Os aspectos macro están relacionados principalmente con aspectos estratéxicos e de alto nivel. decisións.


Mentres tanto, o aspecto Micro está moito máis próximo ao nivel de código e desenvolvemento. Por exemplo, que marco se usa para interactuar coa base de datos, a estrutura do proxecto de cartafoles e clases, ou mesmo patróns específicos de deseño de obxectos.


Aínda que esta clasificación non é ideal, axuda a estruturar unha comprensión dos posibles problemas e da importancia e impacto das solucións que lles aplicamos.


Neste artigo, o meu foco principal centrarase nos aspectos macro.

Aspectos Macro

Estrutura organizativa

Cando comecei a aprender sobre a arquitectura do software, lin moitos artigos interesantes sobre a lei de Conway e o seu impacto na estrutura organizativa. Especialmente este . Entón, esta lei establece que


Calquera organización que deseña un sistema (definido en liñas xerais) producirá un deseño cuxa estrutura sexa unha copia da estrutura de comunicación da organización.


Sempre crin que este concepto é moi universal e representa a Regra de Ouro.


Entón comecei a aprender o enfoque de deseño impulsado por dominios (DDD) de Eric Evans para modelar sistemas. Eric Evans subliña a importancia da identificación do contexto limitado. Este concepto implica dividir un modelo de dominio complexo en seccións máis pequenas e máis manexables, cada unha co seu propio conxunto limitado de coñecementos. Este enfoque axuda a unha comunicación eficaz do equipo, xa que reduce a necesidade dun coñecemento amplo de todo o dominio e minimiza o cambio de contexto, facendo así as conversacións máis eficientes. O cambio de contexto é a cousa peor e que consume máis recursos. Incluso os ordenadores están loitando con iso. Aínda que é pouco probable que consiga unha ausencia total de cambio de contexto, creo que é o que debemos esforzarnos.


Fantasy about keeping in mind a lot of bounded contexts

Volvendo á Lei de Conway, atopei varios problemas con ela.


O primeiro problema que atopei coa Lei de Conway, que suxire que o deseño do sistema reflicte a estrutura organizativa, é o potencial para formar contextos limitados complexos e completos. Esta complexidade xorde cando a estrutura organizativa non está aliñada cos límites do dominio, o que leva a contextos limitados que son moi interdependentes e cargados de información. Leva a frecuentes cambios de contexto para o equipo de desenvolvemento.


Outra cuestión é que a terminoloxía organizativa se filtra ao nivel do código. Cando as estruturas organizativas cambian, é necesario modificar o código base, consumindo recursos valiosos.


Así, seguir a Inverse Conway Maneuver axuda a construír o sistema e a organización que fomenten a arquitectura de software desexada. Non obstante, cabe destacar que este enfoque non funcionará moi ben en arquitecturas e estruturas xa formadas, xa que os cambios nesta fase son prolongados, pero ten un rendemento excepcional nas startups xa que son rápidos para introducir cambios.

Gran Bola de Barro

Este patrón ou "antipatrón" impulsa a construción dun sistema sen arquitectura. Non hai regras, límites e estratexias sobre como controlar a inevitable complexidade crecente. A complexidade é o inimigo máis formidable na viaxe de construír sistemas de software.


Entertaining illustration made by ChatGPT

Para evitar a construción deste tipo de sistema, debemos seguir regras e restricións específicas.

Arquitectura do sistema

Hai infinidade de definicións para a arquitectura de software. Gústanme moitos deles xa que abarcan diferentes aspectos da mesma. Porén, para poder razoar sobre a arquitectura, necesitamos naturalmente formar algúns deles na nosa mente. E é salientable dicir que esta definición pode evolucionar. Entón, polo menos polo momento, teño a seguinte descrición para min.


A arquitectura de software trata de decisións e eleccións que tomas todos os días que afectan ao sistema construído.


Para tomar decisións que cómpre ter na súa "bolsa" principios e patróns para resolver os problemas que xurdan, tamén é fundamental afirmar que comprender os requisitos é fundamental para construír o que necesita unha empresa. Non obstante, ás veces os requisitos non son transparentes ou mesmo non están definidos, neste caso, é mellor esperar para obter máis aclaracións ou confiar na túa experiencia e confiar na túa intuición. Pero de todos os xeitos, non podes tomar decisións correctamente se non tes principios e patróns nos que confiar. Aí é onde estou chegando á definición de estilo de arquitectura de software.


O estilo de arquitectura de software é un conxunto de principios e patróns que designan como construír o software.


Hai moitos estilos arquitectónicos diferentes centrados en varios lados da arquitectura planificada, e aplicar varios deles á vez é unha situación normal.


Por exemplo, como:

  1. Arquitectura monolítica

  2. Deseño dirixido por dominios

  3. Baseado en compoñentes

  4. Microservizos

  5. Tubería e filtros

  6. Impulsado por eventos

  7. Micronúcleo

  8. Orientado ao servizo


e así por diante…


Por suposto, teñen as súas vantaxes e inconvenientes, pero o máis importante que aprendín é que a arquitectura evoluciona paulatinamente mentres depende dos problemas reais. Comezar coa arquitectura monolítica é unha excelente opción para reducir as complexidades operativas, é moi probable que esta arquitectura se adapte ás túas necesidades mesmo despois de chegar á fase de axuste ao mercado de produtos (PMI) de construción do produto. A escala, pode considerar avanzar cara a un enfoque impulsado por eventos e microservizos para lograr unha implantación independente, un ambiente de pila tecnolóxico heteroxéneo e unha arquitectura menos acoplada (e menos transparente mentres tanto debido á natureza dos enfoques impulsados por eventos e pub-sub se estes son adoptados). A simplicidade e a eficiencia están próximas e teñen un gran impacto entre si. Normalmente, as arquitecturas complicadas afectan a velocidade de desenvolvemento de novas funcións, apoiando e mantendo as existentes e desafiando a evolución natural do sistema.


Non obstante, os sistemas complexos requiren a miúdo unha arquitectura complexa e completa, o que é inevitable.


Xusto, este é un tema moi amplo, e hai moitas ideas xeniais sobre como estruturar e construír sistemas para a evolución natural. En base á miña experiencia, traballei o seguinte enfoque:

  1. Case sempre comeza co estilo de arquitectura monolítica xa que elimina a maioría dos problemas que xorden debido á natureza dos sistemas distribuídos. Tamén ten sentido seguir monolitos modulares para centrarse en construír compoñentes con límites claros. Aplicar un enfoque baseado en compoñentes podería axudalos a comunicarse entre si mediante o uso de eventos, pero ter chamadas directas (tamén coñecido como RPC) simplifica as cousas ao principio. Non obstante, é importante facer un seguimento das dependencias entre compoñentes xa que se o compoñente A sabe moito sobre o compoñente B, quizais teña sentido combinalos nun só.
  2. Cando te achegues á situación na que necesites escalar o teu desenvolvemento e o teu sistema, podes considerar seguir o patrón de Stangler para extraer gradualmente os compoñentes que hai que implementar de forma independente ou incluso escalar con requisitos específicos.
  3. Agora, se tes unha visión clara do futuro, que é un pouco de sorte incrible, podes decidir a arquitectura desexada. Neste momento, pode decidir avanzar cara á arquitectura de microservizos aplicando tamén enfoques de orquestración e coreografía, incorporando o patrón CQRS para operacións de lectura e escritura a escala independente ou mesmo decidir seguir coa arquitectura monolítica se se adapta ás súas necesidades.


Tamén é vital comprender os números e métricas como DAU (Usuarios activos diarios), MAU (Usuarios activos mensuales), RPC (Solicitud por segundo) e TPC (Transacción por segundo), xa que podería axudarche a tomar decisións porque a arquitectura para 100 usuarios activos e 100 millóns de usuarios activos son diferentes.


Como nota final, diría que a arquitectura ten un impacto significativo no éxito do produto. No escalado requírese unha arquitectura mal deseñada para os produtos, o que é moi probable que leve a un fracaso xa que os clientes non esperarán mentres escala o sistema, senón que escollerán un competidor, polo que debemos estar por diante do posible escalado. Aínda que admito que ás veces non podería ser un enfoque lean, a idea é ter un sistema escalable pero non xa escalado. Por outra banda, ter un sistema moi complicado e xa escalado sen clientes nin plans para conseguir moitos deles custaráche cartos no teu negocio de balde.

Selección de pilas tecnolóxicas

A selección dunha pila de tecnoloxía tamén é unha decisión a nivel macro xa que inflúe na contratación, nas perspectivas de evolución natural do sistema, na escalabilidade e no rendemento do sistema.


Esta é a lista de consideracións básicas para escoller unha pila de tecnoloxía:

  • Requisitos e complexidade do proxecto. Por exemplo, pódese crear unha aplicación web sinxela co marco Blazor se os seus desenvolvedores teñen experiencia con el, pero debido á falta de madurez de WebAssembly, escoller React e Typescript para o éxito a longo prazo podería ser unha mellor decisión.
  • Necesidades de escalabilidade e rendemento. Se prevé recibir unha gran cantidade de tráfico, optar por ASP.NET Core sobre Django podería ser unha opción acertada debido ao seu rendemento superior na xestión de solicitudes simultáneas. Non obstante, esta decisión depende da escala de tráfico que esperas. Se necesitas xestionar potencialmente miles de millóns de solicitudes con baixa latencia, a presenza de Garbage Collection pode ser un reto.
  • Contratación, tempo de desenvolvemento e custo. Na maioría dos casos, estes son os factores que debemos preocuparnos. O tempo de comercialización, o custo de mantemento e a estabilidade da contratación impulsan as necesidades da túa empresa sen obstáculos.
  • Recursos e experiencia do equipo. O conxunto de habilidades do teu equipo de desenvolvemento é un factor crítico. En xeral, é máis eficaz utilizar tecnoloxías coas que o teu equipo xa está familiarizado a menos que exista unha razón sólida para investir en aprender unha pila nova.
  • Madurez. Unha comunidade forte e un ecosistema rico de bibliotecas e ferramentas poden facilitar moito o proceso de desenvolvemento. As tecnoloxías populares adoitan ter un mellor apoio da comunidade, o que pode ser inestimable para resolver problemas e atopar recursos. Así, podería aforrar recursos e centrarse principalmente no produto.
  • Mantemento e apoio a longo prazo. Considere a viabilidade a longo prazo da tecnoloxía. As tecnoloxías que se adoptan e admiten amplamente teñen menos probabilidades de quedar obsoletas e, polo xeral, reciben actualizacións e melloras periódicas.


Como pode afectar o crecemento empresarial ter varias pilas de tecnoloxía?

Desde unha perspectiva, a introdución dunha pila máis podería escalar a súa contratación, pero, por outra banda, trae custos de mantemento adicionais xa que cómpre soportar ambas pilas. Entón, como dixen anteriormente, ao meu punto de vista, só unha necesidade extra debería ser un argumento para incorporar máis pilas de tecnoloxía.


Pero que é o principio de seleccionar a mellor ferramenta para un problema específico?

Ás veces non tes máis remedio que traer novas ferramentas para resolver un problema específico en función das mesmas consideracións mencionadas anteriormente, nestes casos, ten sentido seleccionar a mellor solución.


A creación de sistemas sen un alto acoplamento a unha tecnoloxía específica podería ser un reto. Aínda así, é útil esforzarse por unha condición na que o sistema non estea estreitamente acoplado á tecnoloxía, e non morrerá se mañá, un marco ou ferramenta específicos se volve vulnerable ou mesmo obsoleto.


Outra consideración importante está relacionada coas dependencias de software propietario e de código aberto. O software propietario ofrécelle menos flexibilidade e a posibilidade de ser personalizado. Aínda así, o factor máis perigoso é o bloqueo do provedor, no que dependes dos produtos, prezos, condicións e folla de ruta dun provedor. Isto pode ser arriscado se o vendedor cambia de dirección, aumenta os prezos ou descontinua o produto. O software de código aberto reduce este risco, xa que unha única entidade non o controla. Eliminar un único punto de falla en todos os niveis é unha clave para construír sistemas fiables para o crecemento.

Punto único de falla (SPOF)

Un único punto de falla (SPOF) refírese a calquera parte dun sistema que, se falla, fará que todo o sistema deixe de funcionar. Eliminar os SPOF a todos os niveis é crucial para calquera sistema que requira alta dispoñibilidade. Todo, incluído o coñecemento, o persoal, os compoñentes do sistema, os provedores de nube e os cables de internet, pode fallar.


Existen varias técnicas básicas que podemos aplicar para eliminar puntos únicos de falla:

  1. Redundancia. Implementar redundancia para compoñentes críticos. Isto significa ter compoñentes de copia de seguridade que poden facerse cargo se falla o compoñente principal. A redundancia pódese aplicar en diferentes capas do sistema, incluíndo hardware (servidores, discos), redes (ligazóns, conmutadores) e software (bases de datos, servidores de aplicacións). Se estás aloxando todo nun provedor de nube e mesmo tes copias de seguranza alí, considera crear unha copia de seguridade adicional regular noutro para reducir o custo perdido en caso de desastre.
  2. Centros de datos. Distribuya o seu sistema en varias localizacións físicas, como centros de datos ou rexións na nube. Este enfoque protexe o teu sistema contra fallos específicos da localización, como cortes de enerxía ou desastres naturais.
  3. Failover. Aplique un enfoque de conmutación por fallo para todos os seus compoñentes (DNS, CDN, equilibradores de carga, Kubernetes, pasarelas de API e bases de datos). Dado que os problemas poden xurdir de forma inesperada, é fundamental ter un plan de copia de seguridade para substituír rapidamente calquera compoñente polo seu clon segundo sexa necesario.
  4. Servizos de alta dispoñibilidade. Asegúrate de que os teus servizos estean deseñados para ser escalables horizontalmente e altamente dispoñibles desde o principio, cumprindo os seguintes principios:
    • Practica a apatridia do servizo e evita almacenar sesións de usuario en cachés na memoria. En vez diso, use un sistema de caché distribuído, como Redis.
    • Evitar depender da orde cronolóxica do consumo de mensaxes ao desenvolver a lóxica.
    • Minimiza os cambios de ruptura para evitar que se interrompan os consumidores da API. Sempre que sexa posible, opte por cambios compatibles con versións anteriores. Ademais, considere o custo xa que ás veces, implementar un cambio de ruptura pode ser máis rendible.
    • Incorporar a execución da migración na canalización de implantación.
    • Establecer unha estratexia para xestionar as solicitudes concorrentes.
    • Implementa o descubrimento, o seguimento e o rexistro de servizos para mellorar a fiabilidade e a observabilidade.
    • Desenvolver a lóxica empresarial para ser idempotente, recoñecendo que os fallos da rede son inevitables.
  5. Revisión da dependencia. Revisar e minimizar regularmente as dependencias externas. Cada dependencia externa pode introducir potenciais SPOF, polo que é esencial comprender e mitigar estes riscos.
  6. Reparto de coñecementos regularmente. Non esquezas nunca a importancia de difundir o coñecemento dentro da túa organización. As persoas poden ser imprevisibles e depender dun só individuo é arriscado. Animar aos membros do equipo a dixitalizar os seus coñecementos a través da documentación. Non obstante, teña en conta a documentación excesiva. Utiliza varias ferramentas de IA para simplificar este proceso.

Conclusión

Neste artigo, cubrimos varios aspectos clave de Macro e como podemos xestionar a súa complexidade.


Grazas por ler! Vémonos a próxima!