Engenharia interna de um framework RAD... como desenvolvedor PHP com Nooku
Publicados: 2022-03-11Todo mundo tem seu próprio conjunto de ferramentas. Como desenvolvedor PHP, um dos meus favoritos é um framework de Desenvolvimento Rápido de Aplicativos chamado “Nooku”. Nas palavras do grupo de desenvolvimento: “O Nooku é mais um kit de ferramentas de desenvolvimento web do que um framework”.
Caso você não conheça, dê uma olhada. É um projeto de código aberto que faz uso pesado de padrões de design aceitos pela indústria para produzir aplicativos altamente componentizados que são facilmente extensíveis e reutilizáveis (inicialmente criados por um dos principais desenvolvedores do Joomla!). Pronto para uso, o Nooku oferece muitas ferramentas de desenvolvimento rápido de aplicativos para ajudar a tirar os projetos do papel mais rapidamente. Uma amostra pequena, mas forte:
- Uma implementação padrão do MVC onde tudo que você precisa fazer é escrever o layout (isso é o que me fisgou)
- Disponibilidade HMVC imediatamente
- Suporte para diferentes formatos de saída como JSON e XML para todos os seus dados (ou seja, exponha sua API em minutos)
- Implementações administrativas e front-end padrão
No coração do Nooku está o princípio de design "Composição sobre Herança" (na verdade, é o primeiro conceito na página introdutória do Nooku. Em uma linha: você deve tentar compor (ou somar) a funcionalidade de vários objetos para criar alguns tipo de objeto composto, em vez de depender de subclasses.
Esse princípio permite que você escreva menos código e geralmente leva a algumas soluções bastante elegantes. Então, como exatamente é promovido? Bem, no nível do código, os melhores exemplos vêm do uso de Mixins e Identificadores de Recurso/Serviço. Vamos dar uma olhada.
O Mixin
Antes do PHP 5.4, a linguagem não tinha o conceito de Traits . Estas são estruturas semelhantes a classes que, quando 'usadas' por um objeto, fornecem algum tipo de funcionalidade (semelhante à Herança Múltipla). O Nooku vem resolvendo esse problema há anos (desde o PHP 5.2) com o Mixin .
O Mixin não apenas permite compor objetos juntos, mas também adiciona os métodos de cada objeto misto à interface do objeto composto. O objeto usando o mixin parece 'herdar' os métodos do objeto misturado.
/** * Mixin an object * * When using mixin(), the calling object inherits the methods of the mixed * in objects, in a LIFO order. * * @param KMixinInterface $object An object that implements KMinxInterface * @return KObject */ public function mixin(KMixinInterface $object) { $methods = $object->getMixableMethods($this); foreach($methods as $method) { $this->_mixed_methods[$method] = $object; } // Set the mixer $object->setMixer($this); return $this; }
Quase todos os objetos no Nooku têm essa capacidade porque estendem a classe base KObject que definiu o método mixin .
As principais classes na arquitetura do controlador do Nooku também são descendentes do KObject. O controlador abstrato é a classe KControllerAbstract e por inspeção você pode ver que ele tira vantagem da habilidade Mixing imediatamente. Sempre que uma instância dessa classe é construída, as funcionalidades KMixinCommand e KMixinBehavior são adicionadas imediatamente à sua interface. Consequentemente, cada controlador no Nooku é composto com a funcionalidade de gerenciamento de Cadeia de Comando e Comportamento por meio dos respectivos objetos.
Por que o K na frente de todos os nomes de classe? A biblioteca principal do Nooku tem o codinome “Koowa”.
Voltando ao controlador Nooku: a classe KMixinBehavior contém todas as peças para dar ao KControllerAbstract a capacidade de carregar comportamentos específicos em tempo de execução. Estratégias comportamentais são classes que descrevem um processo ou lógica que pode ser separada e usada por outras classes (por exemplo, editável, ordenável). O KMixinBehavior é bastante simples e possui apenas quatro métodos: getBehavior, hasBehavior, addBehavior e getBehaviors. E isso é tudo o que precisamos para dar a um objeto a capacidade de manipular e encapsular diferentes estratégias comportamentais.
Da mesma forma, KMixinCommand tem apenas três métodos: getCommandContext, getCommandChain, setCommandChain. Caso não tenha adivinhado, estes três métodos fornecem ao KControllerAbstract a capacidade de implementar uma cadeia de comandos, mas permite que o faça em tempo de execução.
Você pode pensar nessa mistura como uma simples adição aritmética:
Nos dá uma interface que se parece com isso:
Por definição, as classes abstratas devem ser estendidas e, portanto, pela mágica da herança, todos os objetos que são filhos ou instâncias do KControllerAbstract também ganham a capacidade de adicionar comportamentos e uma cadeia de comandos em tempo de execução.
Parece legal. Mas o que isso realmente significa? Resumindo, o Nooku fornece funcionalidade em componentes; ou seja, o Nooku permite modularizar sua funcionalidade e compor funcionalidades em módulos em tempo de execução.

Esses dois exemplos servem para demonstrar a composição. Eles também servem para demonstrar o suporte da estrutura Nooku RAD para composição adicional em seu núcleo. Esta é uma vantagem importante. Os métodos adicionados ao KControllerAbstract acima suportam o “Padrão de Design de Estratégia” dando aos desenvolvedores as ferramentas para encapsular o que varia antes que uma linha de código seja escrita. O fato do método mixin() fazer parte de cada extensão do KObject significa que você pode definir e adicionar prontamente outras interfaces de gerenciamento comportamental à maioria dos objetos em tempo de execução.
Identificadores e localizadores de serviços e recursos: dissociar meu nome de classe de meu objeto
Os identificadores e localizadores de serviços e recursos no Nooku também fornecem suporte poderoso para a separação de interesses.
Novamente, vamos olhar novamente para o KObject, mas também para o KService. Podemos tratar a maioria das coisas no Nooku como um serviço ou recurso e, como tal, instanciar e interrogá-las exatamente da mesma maneira.
Pense em um serviço como algo do qual você obtém um recurso. Todos os serviços são recursos, mas nem todos os recursos são serviços
Quando você for ao supermercado e comprar um produto, pense na loja como o Serviço, ou seja, uma coleção de itens que você pode pesquisar ; e o produto como Recurso, ou seja, uma única lógica de item/solução que pode ser:
- olhou especificamente ( Ler ) (por exemplo, olhando para uma lata de sopa de tomate)
- movido pela loja ( editado ) (por exemplo, mova a sopa para o corredor de produtos)
- adicionado ou removido do inventário da loja ( A dd e D elete) (por exemplo, adicione um novo tipo de sopa e se livre do tomate)
Levando este exemplo ainda mais longe, imagine que a mercearia tem um departamento de franquia e você quer estar no negócio. Nessa situação, o Serviço é o departamento de franquia e o recurso é a mercearia que você compra. É muito mais uma classificação contextual. Como um todo, isso é conhecido como o padrão de ação BREAD (você verá cada um deles representado entre KControllerService e KControllerResource prefixado com '_action', ou seja, _actionRead()).
Um modelo pode ser um serviço, um objeto de tabela pode ser pensado como um serviço, uma tríade MVC específica é instanciada como um recurso ou serviço, enquanto um registro específico resultante da interrogação do serviço pode ser considerado um recurso.
Cada objeto no Nooku é uma composição de objetos em que cada um deles contém uma referência aos serviços instanciados do aplicativo inteiro em um 'contêiner de serviço' e um método para acessar os serviços chamado getService(). Tudo o que o método KObject::getService() exige é que passemos um identificador de recurso válido e ele retornará um serviço instanciado pronto para uso.
No desenvolvimento rápido de aplicativos PHP, os Identificadores de Recursos nos dão uma maneira poderosa de desacoplar a instanciação de um objeto de seu nome de classe e, assim, fornecer aliases para essa identificação. Isso tem implicações importantes na manutenibilidade de um aplicativo. Através do alias, um desenvolvedor pode alterar a classe usada por cada objeto que é instanciado com um determinado identificador adicionando uma linha de código com KService::addAlias().
Um exemplo de identificador de recurso com o qual estamos familiarizados é o URI ou Uniform Resource Identifier:
Esta é toda a informação necessária para o KService localizar e carregar a classe apropriada. Essas peças combinam com as convenções de nomeação e posicionamento de classe do Nooku, que fornecem previsibilidade de posicionamento e instanciação. O exemplo de identificador acima (com://site/user.database.table.user) tenta carregar o arquivo /components/com_user/databases/tables/user.php, que tem o nome de classe ComUserDatabaseTableUser. Aliás, se o arquivo não existir, a estrutura fornecerá um objeto de tabela padrão e o construirá com base na nomenclatura do banco de dados e nas convenções de esquema de identificação (isso me fisgou um pouco mais). Como mencionado anteriormente, o KService também permite definir aliases para seus identificadores. Usando KService::setAlias('maindbaseadapter','com://admin/default.database.adapter.mysqli')
; nos permite carregar um objeto db com KService::getService('maindbaseadapter')
.
Isso nos dá a dissociação de que falamos e oferece uma vantagem marcante na manutenção e extensão de nossas aplicações. Somos livres para criar aplicativos diferentes de 'site' e 'admin' se necessário e através dos identificadores descritos aqui podemos usar serviços localizados em outros aplicativos prontamente para ajudar nossas soluções a atender seus requisitos. Novamente, este é outro exemplo de como o Nooku fornece aos desenvolvedores e equipes PHP e RAD suporte para a composição não apenas de objetos de classe única, mas de serviços e aplicativos inteiros… de graça.
Resumindo
Com composição sobre herança em seu coração; as composições e estruturas inteligentes e pré-existentes que existem para suportar novas amálgamas; e a arquitetura orientada a serviços gratuitos com os identificadores descritos aqui, o Nooku fornece uma poderosa estrutura RAD com uma vantagem significativa sobre qualquer uma de suas ferramentas de desenvolvimento PHP pares.