Não há bala de prata
Entender que não há bala de prata mudará sua visão das coisas.
Software é uma coisa complexa - e não há muita escapatória disso.
Acontece que estamos lidando com coisas abstratas e invisíveis. Softwares são junções de conceitos e ideias - inicialmente - imaginárias - que tendem a resolver problemas reais.
Isso torna tudo muito complexo.
E a complexidade é um problema complexo por si só.
Fred Brooks - em No Silver Bullet - separava a natureza de um software em essência e acidentes.
Pois é - todo aquele rolê Aristotélico.
Acontece que - entendendo a diferença entre essas duas coisas - e em como isso se aplica a um software, sua visão de como as coisas se comportam acaba mudando.
Fica mais fácil de lidar com toda essas abstrações se você meio que tem um mapa mental da tendência das coisas.
Para isso é necessário entender essência e acidentes.
1- A Essência
Talvez isso não faça muito sentido inicialmente - mas fique comigo.
Vamos voltar um pouco no tempo.
De forma bem simplificada, Aristóteles costumava classificar as coisas de duas maneiras - essência e acidentes.
Essência é o que faz algo ser algo. A essência de uma pessoa é ser humano, ou a essência de um triângulo é ser um polígono de 3 lados, e a de um relógio é ser um dispositivo que mostra as horas.
A palavra-chave aqui é ser.
Veja que um triângulo deixa de ser um triângulo se ele deixa de ser um polígono de 3 lados.
E a pessoa deixa de ser uma pessoa caso ela pare de ser um ser vivo. E o relógio deixa de ser um relógio caso se despedace, quebre e não mostre mais as horas.
Eles perdem a essência.
Os acidentes são propriedades dessa essência que não as altera.
Por exemplo - um relógio pode ser analógico ou digital. Acidentes.
Uma pessoa por ter 1.80 de altura e cabelo cacheado. Acidentes.
Um triângulo pode ser azul e tridimensional. Acidentes.
Faz sentido? Essências e acidentes.
Voltamos para o presente.
Se aplicarmos isso a um software - temos a essência - que é o problema que está sendo resolvido, e temos os acidentes - que surgem a partir da tentativa de resolução desse problema.
Essência - um sistema que guarda diariamente os valores das principais criptomoedas.
Acidentes - O banco de dados usado para guardar essas informações, o script em python usado para buscar esses dados - e assim por diante.
E acima dos acidentes temos mais acidentes e mais acidentes. Por exemplo - e se o fluxo de informações no seu banco de dados for enorme? Você terá que escalar ou usar alguma estratégia diferente. Isso é um acidente.
Acidente pois não altera a essência do software - ela continua sendo um sistema que guarda os valores das criptomoedas.
E se agora a ideia do sistema é - ao invés de buscar informações de um criptomoedas, buscar informações demográficas sobre o Brasil.
A essência agora é outra, com outras complexidades.
Para Brooks - um software é e sempre será complexo devido a sua essência.
Acontece que um software é uma representação digital de processos e sistemas reais.
...E a realidade é complexa.
Por exemplo, no sistema que guarda um valor das criptomoedas - precisamos considerar como buscar esses valores, de onde buscar, além de outras coisas.
Em que frequência vamos buscar esses dados?
E se nossos usuários precisarem de atualizações em tempo real?
E se a API que usamos falhar? Qual seria o failsafe?
E os dados precisam estar legíveis. Como faremos isso?
Esse tipo de coisa torna o problema em si algo essencialmente complexo.
2- Os Acidentes
"In short, the software product is embedded in a cultural matrix of applications, users, laws, and machine vehicles. These all change continually, and their changes inexorably force change upon the software product."
A natureza de um software faz com que os acidentes naturalmente surjam.
Se após terminarmos o nosso sistema de criptomoedas o tempo congelasse e nada mais mudasse - provavelmente não teríamos tantos acidentes.
Acontece que existem inúmeras variáveis em jogo. Usuários, o tempo em si, e a vida no geral gera entropia.
Você precisa de usuários - e os usuários tem demandas específicas - que caem em um espectro absurdo de diferença.
O João quer os dados de forma estática, sem atualizações.
Já o Alexandre quer os dados em tempo real.
Implementar a melhoria que o Alexandre quer pode adicionar na balança do seu software concorrência - já que teríamos que gerenciar múltiplas conexões para diferentes APIs - dependendo do cenário.
Isso já adiciona um nível totalmente diferente de complexidade do que se você fosse projetar o sistema apenas para o João.
E pior - introduzir as mudanças que o Alexandre quer pode zoar a experiência do João, já que - se implementada de forma errada - a concorrência iria degradar todos seus usuários.
Aí temos a variável dos usuários. Um espectro absurdo de necessidades e visões diferentes.
Existem outras - como citei no meu artigo "O castelo de cartas".
As próprias dependências do seu sistema - adicionadas por consequências pelos acidentes que surgem - também se tornam um ponto de complexidade e entropia.
... E isso vai acontecer. Ainda mais com os ecossistemas atuais - como o npm e afins.
3 - A Complexidade
"From the complexity comes the difficulty of communication among team members, which leads to product flaws, cost overruns, schedule delays. From the complexity comes the difficulty of enumerating, much less understanding, all the possible states of the program, and from that comes the unreliability."
A complexidade seria o início do colapso, por assim dizer.
Acontece que a complexidade é inerente à essência de um software.
Logo - se não houver a consciência e o controle constante dessa complexidade e dos acidentes - o software tende a falhar.
...E o que fazer?
Aí entra o título - não há bala de prata.
A complexidade vai acontecer - acidentes vão surgir. E não existe uma solução definitiva para isso.
O que podemos fazer é usar algumas estratégias para prever e mitigar grande parte dos problemas.
Existem diferentes subdomínios de problema. E níveis diferentes de relação entre eles.
Por exemplo - quando aceitamos fazer a sugestão do Alexandre no nosso software, pode ser que tenhamos que adicionar uma dependência que controlaria a natureza assíncrona das requisições para as APIs.
Um dos subdomínios englobaria a negociação com o Alexandre para achar alguma alternativa melhor sem ter que fazer uma alteração tensa no sistema.
O outro seriam as dependências - consequências tentativa de mitigar a complexidade do desenvolvedor em si ao implementar a alteração requisitada.
Lá no meu artigo "O castelo de cartas" dei algumas dicas de como mitigiar um pouco a questão do risco das dependências - pra recapitular:
- Entenda de 3 a 4 níveis de abstração abaixo do que você está atualmente.
- Faça housekeeping das dependências do projeto - constantemente.
- Desacople as dependências em pontos cruciais da aplicação.
- Cuidado com as transitive dependencies - dependências de dependências.
- Planeje - mapeie quais dependências você acredita que são um risco.
Brooks expande também e adiciona algumas ideias de como segurar um pouco o problema.
No geral - ele cita que é necessário focar na essência - e não nos acidentes:
- Use tecnologias high-level - a abstração gerada por elas te ajuda a focar no problema em si ao invés de complexidades técnicas. Por exemplo, ao invés de usar assembly diretamente, use C.
- Re-use tecnologias - não reinvente a roda (aí entra a questão das dependências). Use "partes" prontas ao invés de criar algo totalmente novo.
- Prefira prototipagem rápida - escreva código para testar soluções relacionadas com a essência do problema, e não foque muito nos detalhes - pelo menos inicialmente.
- No mesmo ponto - incremente. Vá aos poucos resolvendo o problema e validando com os usuários - ao invés de fazer e entregar tudo de uma vez. Isso te dá oportunidade de - caso necessário - fazer mudanças bruscas sem muito impacto.
- Modularize - tente segmentar seu software em pedaços separados e independentes. Hoje em dia usam bastante microserviços. Caí nesse ponto aí.
Dá para perceber que a ideia dele é usar o máximo de sua energia para focar no problema em si - e deixar os acidentes em segundo plano. Isso mitigaria bastante complexidade.
Essas são algumas das soluções citadas por ele que cruzam bem com a ideia do artigo.
... Enfim - existe muito espaço para expandir nesses aspectos - e pretendo fazer isso nos posts futuros.
Saber diferenciar entre essência e acidentes já vai te ajudar bastante em identificar causas raizes de algumas coisas.
Por exemplo - suponha que você tenha um problema nas filas na sua aplicação.
As filas em si - estão tentando resolver um acidente (ou um acidente de um acidente) ou está relacionado com a essência do software em si?
É realmente necessário ter filas ali? Será que não está infringindo a essência original do software?
Dependendo da situação - se infringe muito a essência - será que não valeria desacoplar isso e separar em um módulo diferente?
É nesse tipo de coisa que essas visões mais "abstratas" que misturam filosofia e desenvolvimento ajudam.
Complexo, mas vale a pena.
-Rapozo