Como fazer uma Modularização dinâmica em Java com OSGi
O conceito de modularização dinâmica para a tecnologia Java, proposto pela iniciativa OSGi, vem sendo adotado há um bom tempo por soluções de software cuja execução não deve ser interrompida, seja devido à necessidade de instalação de novos módulos, seja para alcançar resiliência quanto à disponibilidade da aplicação. Independentemente disso, existem ótimos benefícios pela escolha de uma arquitetura modular, e o framework OSGi é o caminho para alcançar tais vantagens. Com base nisso, este artigo tem como objetivo apresentar o contexto no qual a especificação OSGi foi concebid, bem como um exemplo prático para o entendimento dos principais conceitos.
Pode-se dizer que os conceitos fundamentais para o desenvolvimento de um software baseiam-se na busca pela flexibilidade, robustez e reutilização. Assim, características como coesão, acoplamento, modularização e extensibilidade costumam estar no topo do checklist de arquitetos que queiram que o código de uma determinada solução de software seja definitivamente de boa qualidade.
Nesse contexto, enquanto as ferramentas que apoiam o desenvolvimento de software, bem como os meios nos quais o mesmo é executado, mudaram significativamente, os princípios básicos para o desenvolvimento de uma boa arquitetura continuam os mesmos. A título de exemplo, observamos todos os novos recursos disponíveis em IDEs e na Java Virtual Machine (JVM), que apoiam o desenvolvimento, e também a evolução proporcionada pelo ecossistema baseado em Cloud Computing, no qual muitos softwares são executados.
No entanto, os conceitos que moldam a qualidade na construção de um sistema não sofrem mudanças significativas há pelo menos vinte e cinco anos. Isso se mostra evidente ao lembrar que, mesmo antes da publicação do livro "Design Patterns: Elements of Reusable Object-Oriented Software", em 1994 — cujos autores ficaram conhecidos como “Gangue dos Quatros” (Gang Of Four, frequentemente abreviado como "GoF") —, os engenheiros Kent Beck e Ward Cunningham iniciaram, em 1987, um experimento para aplicar padrões baseados em ordem, organização e forma nas linguagens de programação. Tal experimento foi baseado na obra do arquiteto e matemático Christopher Alexander, denominada “Notes on the Synthesis of Form”, publicada em 1964. Curiosamente, Alexander também influenciou na criação do famoso jogo “SimCity”, a partir de sua obra “A Pattern Language”, conforme declarado pelo próprio Will Wright, designer do jogo e co-fundador da Electronic Arts. Voltando ao experimento de Beck e Cunningham, eles apresentaram seus resultados no mesmo ano de 1987 em uma conferência anual dedicada à pesquisa e desenvolvimento de linguagens orientadas a objetos, conhecidas como OOPSLA, que naquele ano ocorreu em Orlando (Flórida, EUA). Tais resultados contribuíram para o início de um movimento para a busca por padrões de projetos na área da ciência computacional, que finalmente ganhou popularidade a partir da publicação do livro pelos membros do GoF, em 1994.
Depois disso, poucas publicações alcançaram tamanha popularidade como a obra do GoF. É claro que surgiram novos Design Patterns nos últimos anos, mas os princípios nos quais esses se apoiam continuam os mesmos. Entre os princípios mais conhecidos, é possível citar cinco que atualmente delineiam os parâmetros qualitativos na engenharia de um sistema. São eles: Princípio da Responsabilidade Única (Single Responsibility Principle — SRP); Princípio da Segregação de Interfaces (Interface Segregation Principle — ISP); Princípio da Substituição de Liskov (Liskov Substitution Principle — LSP); Princípio da Inversão de Dependências (Dependency Inversion Principle — DIP) e o Princípio do Aberto Fechado (Open Closed Principle — OCP).
Não está no escopo deste artigo se aprofundar sobre cada um desses conceitos. Contudo, vale dizer que três deles, o SRP, DIP e o ISP, estão diretamente ligados à determinação por um código modular. Não por acaso a modularização oferece excelentes benefícios quando se pretende alcançar uma arquitetura com índices de manutenibilidade e reusabilidade satisfatórios.
Entre os benefícios obtidos pelo desenho de um código modular, observamos a facilidade com que componentes independentes podem ser extraídos a partir dele. Tal vantagem mostrou-se muito importante no ecossistema do desenvolvimento de software. Isso porque a produção de códigos modulares, empacotados em componentes — na forma de bibliotecas do tipo JAR, por exemplo —, promoveu o reuso genuíno além das fronteiras de um ou outro grupo de desenvolvedores. Desse modo, centenas de frameworks foram construídos, compartilhados e combinados, como num lego, com o objetivo de alavancar o desenvolvimento de sistemas complexos com um esforço relativamente reduzido frente ao que seria necessário para construí-los inteiramente do zero. Assim, grande parte da comunidade de desenvolvedores beneficiou-se (e vem se beneficiando) da contribuição mútua de código reutilizável, muitas vezes chamados de frameworks, como o JUnit, SLF4J, Log4j, Google Guava, Apache Commons, Spring, Hibernate e milhares de outros.
Entretanto, não foi por acaso que tal modelo para construção de código modular encaixou-se perfeitamente na tecnologia Java. A forte aderência dessa linguagem de programação aos princípios da Orientação a Objetos tornou a aplicação desse modelo muito efetiva, e, como já foi dito nos parágrafos anteriores, bibliotecas empacotadas em arquivos JAR se proliferaram, permitindo a forte reutilização de seus módulos.
O uso de um software denominado Maven também alavancou a prática de reuso de componentes, que são disponibilizados em centenas de repositórios públicos. Tal comportamento também tem sido observado em outras tecnologias, como o JavaScript, que foi marcado pelo surgimento da plataforma Node.js. Essa plataforma possui um gerenciador de pacotes denominado npm, o qual disponibiliza também repositórios públicos contendo componentes que podem ser reutilizados. Tal gerenciador é mantido pela empresa NPM Inc.
Pode-se dizer que um grande percentual das aplicações construídas em JavaScript atualmente são dependentes desse modelo. Para se ter uma ideia, em março de 2016, o programador Azer Koçulu removeu cerca de 250 módulos que havia compartilhado no npm, isso porque se enfezou quando a equipe da NPM Inc., juntamente com advogados de uma empresa responsável por um aplicativo de mensagens instantâneas, denominado Kik, solicitou que ele alterasse o nome de um de seus componentes, também batizado de Kik, alegando direitos autorais sobre esse nome. O problema é que, entre os módulos removidos, estava o popular “left-pad”, composto somente por onze linhas de código. A remoção desse módulo comprometeu milhares de aplicações na web que o possuíam como dependência, entre elas o Facebook, Netflix, Airbnb e milhares de outras. Assim, tais aplicações ficaram indisponíveis por um curto período de tempo até que a NPM Inc. conseguiu reestabelecer tal dependência. Tal episódio levantou inclusive uma discussão sobre esse tipo de fragilidade dos sistemas web.
No caso da tecnologia Java, o modelo de reutilização baseado em componentes empacotados em JARs possui um detalhe que pode vir a se tornar uma desvantagem dependendo do tipo de sistema a ser construído. Esse detalhe é a necessidade de reinicialização da Máquina Virtual Java (JVM) para os casos de inclusão, remoção ou atualização dos componentes que compreendem a aplicação. Tal fato pode ser um problema para aplicações construídas para servirem outras aplicações, como o WebLogic, JBoss AS, GlassFish, TomEE, etc., e para plataformas para o desenvolvimento de sistemas, onde é preciso gerenciar a instalação de plugins e extensões, como o Eclipse IDE. Para esses tipos de sistemas, é necessário que sejam implantados módulos em tempo de execução e que os mesmos possam ser removidos e atualizados sem a necessidade de reinício da JVM, ou seja, um modelo de modularização dinâmico. "
[...] continue lendo...Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo