Uma das características que eu mais gosto no agile é o conhecimento compartilhado nos times. E eu não falo apenas dos desenvolvedores generalistas, falo também das responsabilidades que em um modelo mais parecido com o waterfall seriam atribuídas a um indivíduo apenas, mas que no ágil são diluídas na equipe.
Como o time geralmente trabalha em um escopo focado, com quem fica a responsabilidade da arquitetura de toda uma solução? Quem pensa no longo prazo? Na comunicação entre serviços e componentes?
Até onde vai a responsabilidade de design e começa a de arquitetura?
Fundamentalmente, há distinção entre as disciplinas de software design e software architecture:
Mesmo assim, não é raro misturarmos as duas responsabilidades e atribuí-las a um papel só. O que não é necessariamente um problema, já que as disciplinas podem ser encaradas como o mesmo problema em escalas diferentes.
Definir arquitetura de software é um desafio. O Wikipedia define o termo da seguinte forma:
(...) consiste na definição dos componentes de software, suas propriedades externas, e seus relacionamentos com outros softwares. O termo também se refere à documentação da arquitetura de software do sistema. A documentação da arquitetura do software facilita: a comunicação entre os stakeholders, registra as decisões iniciais acerca do projeto de alto-nível, e permite o reúso do projeto dos componentes e padrões entre projetos.
Eu me dou conta que estou nos "domínios" da arquitetura de software quando estou debatendo as "ilities" de um projeto. Portanto, a definição do Codeburst casa melhor com a minha compreensão sobre o assunto:
In simple words, software architecture is the process of converting software characteristics such as flexibility, scalability, feasibility, reusability, and security into a structured solution that meets the technical and the business expectations. This definition leads us to ask about the characteristics of a software that can affect a software architecture design. There is a long list of characteristics which mainly represent the business or the operational requirements, in addition to the technical requirements.
Portanto, quando há um requisito de produto que demanda rápida adaptação do modelo de negócios, pois a empresa ainda está procurando o seu market fit, a solução poderia ser extensível, modular e de fácil alteração. Essas qualidades possivelmente não se encaixarão em um projeto de perfil mais conservador, como um sistema bancário, por exemplo, que teria como uma provável ility a segurança.
Confira uma lista completa de system quality attributes.
Esses aspectos são de responsabilidade do arquiteto de software de levantar, debater, e de setar como boundaries do projeto em questão. Sem dúvida elas passam a influenciar o design dos componentes que serão construídos durante o tempo de projeto.
Kostadis Roussos, no breve (mas excelente) "21 architecturalist papers: always be right, right now." define o papel do arquiteto salientando o seguinte atributo:
An architect has visions of the future, and those visions are often years away from delivery, and worse, even more years away from solving any of the immediate problems engineering management has.
Segundo Kostadis, o arquiteto precisa guiar o projeto para a direção correta. Dentro do contexto ágil, sabemos que essa direção pode mudar, mas ainda assim o arquiteto deve ser capaz de se adaptar a essa mudança, mudar o curso, e continuar fazendo com que o projeto siga o caminho certo.
Além de ser "high-level o suficiente" para ter a visão do todo, o arquiteto ainda é responsável por gerenciar expectativas de gerentes, diretores, product owners, e até mesmo dos próprios engenheiros. E em relação à engenharia a balança pode ser ainda mais frágil, uma vez que ele deve ser "distante o suficiente" para que um gap criativo seja formado, e que engenharia tenha a oportunidade de inovar.
Então chegamos ao melhor parágrafo do texto de Roussos:
In short, you need to be right, and high-level enough that you can’t be wrong, but if that’s where you end, you fail.
Chris Richardson, no livro Microservices Patterns, estressa um pouco mais sobre a importância desse papel:
Architecture is important because it enables an application to satisfy the second category of requirements: its quality of service requirements. These are also known as quality attributes and are the so-called -ilities. The quality of service requirements define the runtime qualities such as scalability and reliability. They also define development time qualities including maintainability, testability, and deployability. The architecture you choose for your application determines how well it meets these quality requirements.
Encontramos alguns estilos já estabelecidos e bem conhecidos de arquiteturas que resolvem combinações de qualidades, como o caso do Monolithic Architecture, Event-Driven (Implicit Invocation) Architecture, e talvez o mais "hypado", Microservices Architecture.
Eles podem fazer uso de um ou mais padrões de arquitetura, como por exemplo, a arquitetura monolítica pode ser composta pelos padrões n-tier e model-view-controller.
Lista de estilos e padrões de arquitetura de software.
Algumas ferramentas estão disponíveis para auxiliar o arquiteto na tarefa de modelar a solução, bem como de expor determinados detalhes para diferentes tipos de stakeholders. Talvez a top of mind seja a própria UML. Outra opção é o 4 + 1 architectural view model, que é uma espécie de framework que auxilia na separação de diferentes aspectos do sistema em diferentes visões (que podem inclusive utilizar artefatos da UML para os seus propósitos).
As visões são:
Assista à introdução ao 4 + 1 no Coursera.
Para finalizar, outra prática bem interessante é a escrita de Quality Attribute Scenarios, que são requisitos não funcionais, específicos para mensurar a qualidade da sua solução para problemas específicos.
Veja mais na excelente aula do Coursera sobre Quality Attributes.
O curso Object-Oriented Design, da Universidade de Alberta, define software design da seguinte forma:
The process of planning a software solution, taking the requirements and constraints into account. Divided into higher-level conceptual design and more specific technical design.
O foco está em pensar na solução para um problema específico, projetando detalhes de um determinado componente e suas responsabilidades, e utilizando de artefatos que ajudem no debate com a camada mais próxima de negócios (high-level, mais conceitual) e mais próxima de implementação (low-level, técnica).
Esse passo tem presença constante no início das iterações no modelo iterativo/incremental, e pode ser desempenhado por diferentes papéis dentro de um time (naturalmente, com envolvimento dos desenvolvedores).
Partimos do princípio que tudo origina-se de um requisito:
Quero ver a minha lista de músicas favoritas.
Requisitos podem ser "funcionais" (como o exemplo acima), ou "não funcionais" (como o exemplo de "ilities" da seção anterior). Quando falamos de design conceitual, geralmente nos referimos ao primeiro tipo, e através de discussões mais próximas do problema exploramos soluções.
Nessa etapa é comum lidar com ferramentas, preferencialmente de baixo custo e fácil alteração, que consigam "traduzir" a solução sendo discutida em artefatos visuais, como por exemplo:
Uma outra forma de debatermos requisitos sob uma ótica conceitual é através da construção de user stories. Com elas, podemos tomar algumas liberdades para sermos mais específicos sobre as necessidades e expectativas que precisam ser atendidas:
Eu como um usuário autenticado,
Quero poder visualizar as minhas músicas favoritas,
Para que eu consiga ouví-las com facilidade e maior frequência.
Com o design técnico, estamos enfim discutindo aspectos voltados à "solução prática". Mas nem por isso deixamos de ser expostos a abstrações, como por exemplo, se você estiver utilizando OOP:
Ainda utilizando o contexto de orientação a objetos, outro tópico que pode aparecer nesse momento são os Design Patterns. No caso da construção de APIs, uma possibilidade é a construção do contrato via Swagger file. Enfim, estamos mais próximos de ideias e artefatos que representem de fato o sistema.
Independente de qual estilo de programação você esteja usando, ou de qual região da aplicação você esteja desenvolvendo, é nesse momento que acontecem discussões sobre os trade-offs entre as qualidades (code quality, security, usability, performance, time to market, etc) definidas pelo contexto do seu projeto, bem como outros requisitos não funcionais, e como isso impactará o design (e se o mesmo precisa ser alterado para encontrar o balanço ideal).
Não é difícil imaginar o papel de design sendo exercido no início de cada iteração, ou em plannings e groomings. Além disso, ter essa responsabilidade diluída no time é natural em um contexto multidisciplinar.
Ele pode acontecer também "ahead of time". Por exemplo, participei de projetos dos quais os "UXizes" estavam alguns sprints na frente, em relação aos desenvolvedores. Algumas decisões de design são tomadas com antecedência, e os resultados são apresentados ao longo do tempo de vida do projeto.
Já a arquitetura pode exigir um pouco mais de organização e criatividade. Já tive diferentes experiências com esse dilema "agile x software architecture":
E quando ela deve ser exercida pode ser outro desafio. Miguel Arlandy sugere o seguinte processo no "Software Architecture and Agile. Are they both really compatible?":
(...) As a rule, it would be recommended to do some upfront design at the beginning of the project (Sprint Zero?) and before the first iteration. Besides, we should include an “Architecture review” as part of the Definition of Done (DoD) in each user story. Of course within the Sprint Planning, this fact has to be taken into account. It would be worthwhile if at least one of the team members (if not all of them) will be accountable to ensure both product development and Architecture are aligned.
Uma das possíveis respostas para as perguntas do início desse post é o conceito de Agile Architecture, usado pelo SAFe Framework:
(...) is a set of values, practices, and collaborations that support the active, evolutionary design and architecture of a system. This approach embraces the DevOps mindset, allowing the architecture of a system to evolve continuously over time, while simultaneously supporting the needs of current users. It avoids the overhead and delays associated with the start-stop-start nature and large-scale redesign inherent with phase-gate processes and Big Up Front Design (BUFD).
Onde, resumidamente, inicia-se com um pouco de upfront design que é retroalimentado pelos feedbacks, design e decisões futuras dos times autônomos.
Desse modo, teoricamente, é possível ter uma referência sólida de arquitetura, e ainda assim abrir espaço para inovação e alterações nessa referência. Outro aspecto interessante desse modelo é que é possível imaginá-lo com a proposta de squads do Spotify.
Acredito que o agile e sua comunidade amadureceram o suficiente para compreender que alguns papéis mais "tradicionais" do desenvolvimento de software precisam ser integrados à sua dinâmica. Quando em uma startup, em que ainda é possível se ter a "visão do todo", é completamente natural que engenheiros/desenvolvedores assumam responsabilidades de design e arquitetura. Mas em um contexto mais "enterprise", além de difícil, consome-se muito tempo "tentando tirar a cabeça da areia" e olhar em volta, principalmente se o processo esteja montado em torno de times autônomos.
Independente de quem desempenhe tais papéis, essa característica "iterativa/incremental" que conceitos como o Agile Architecture trazem são bem interessantes, e combinam completamente com os valores que desenvolvedores de software mais se identificam quando adotando ferramentas ágeis.
Até a próxima.