Image from akashicreading.com
Why Joomla! needs both a Framework and a Platform
Hugo Azevedo 308

J4 - Porque o Joomla! precisa duma Framework e duma Plataforma

Nota: Este documento faz parte duma série de documentos que constituem um ensaio sobre o que o Joomla! é, e poderá ser no futuro. Estes documentos não representam o estado actual de desenvolvimento do Joomla!, nem são apenas "despejos de memória". Eles listam um conjunto de ideias estruturadas sobre o que o Joomla! poderá ser, e apresentam algumas soluções para lá chegar. O seu maior propósito é gerar discussão na comunidade do Joomla!.

Se tens sido um Utilizador, Programador, Implementador ou Contribuidor do Joomla! há algum tempo, e souberes um pouco da história do Joomla!, então certamente saberás que, já ocorreram algumas tentativas de separar a camada mecânica do Joomla!, do seu produto final, o CMS. Estas tentativas tiveram o nome de Framework Joomla! e Plataforma Joomla!.

Há uns tempos atrás, tentei descobrir o a sua história e propósito, com um muito relativo sucesso. Descobri que a Framework foi a primeira a ser criada, e a tornar-se num produto distinto. A ideia principal por trás disto, seria permitir que os programadores pudessem desenvolver outras aplicações web, não relacionadas com o CMS, usando a mesma base de código. Passado algum tempo, a Framework e o CMS foram-se separando, tornando-se (provavelmente) em dois produtos menos relacionados, o que levou à criação da Plataforma para o propósito inicial, apenas para ser cancelada apenas dois anos depois.

A ideia principal, seria criar uma Framework multi-funções, como tantas outras por aí, que pudesse ser usada como um "esqueleto" e/ou "motor" para o CMS, que por sua vez, assentaria no seu topo.

Neste momento, parece que o projecto da Framework renasceu, com a mesma intenção de ser a base para o CMS, no entanto, tendo visto recentemente um vídeo dum membro do núcleo duro da equipa de produção, afirmar que o CMS iria retornar (se é que alguma vez partiu) à sua abordagem monolítica/holística. Para mim, isto é seguir na direcção errada.

Hoje em dia, o Joomla! parece estar demasiadamente focado do utilizador final, independentemente de quem seja, descartando desta forma uma grande fatia do mercado.

Ao focarem-se apenas no CMS, e ao tentarem agradar todo e qualquer utilizador final que anda por aí, que é uma tarefa impossível e a PLT sabe disso, o Joomla! acaba por se tornar pouco apelativo para toda a gente.

Para além duma preferência pessoal, como que se argumentaria/vendia a ideia de que o Joomla! seria a melhor opção para o mundo empresarial, ou a outro programador ou designer, em vez de outra solução qualquer? Isso não seria uma tarefa fácil.

Então, qual é a necessidade duma Framework e/ou Plataforma?

Bem, na realidade a necessidade vem do mercado. Existe alguma demanda no mercado para programadores em Zend, Symphony, Laravel ou Rails (entre outras), mas a demanda para CMS's (além do WP), parece estar em declínio. Este facto sozinho, é o suficiente para ser objecto de reflexão na comunidade do Joomla!.

Programadores procuram Frameworks, para poderem acelerar e sua produtividade. Eles usam-nas para poderem evitar ter que re-desenvolver aquelas tarefas rotineiras e/ou reconfigurar um novo projecto no seu início. Se ouvirem o David Heinemeier Hansson falara da razão que o levou a criar o Rails, irão ouvi-lo dizer isso mesmo. Ao mesmo tempo, os programadores querem manter controlo sobre o que desenvolvem, e manter escalar/expandir o seu trabalho o máximo que conseguirem, e da forma que quiserem.

O back end do Joomla! é muito bom, e o Joomla! é bastante extensível, usa standards de padrões de desenvolvimento usados no mercado, e é bastante estável, mas porque é que não consegue competir com as Frameworks disponíveis no mercado? A resposta poderá ser bastante simples. O Joomla! nem é peixe, nem é carne! É algo, algures a meio. Não consegue competir em sites simples, como o seu arqui-inimigo (todos sabes quem é), nem consegue ser a melhor solução "corporativa", mesmo que consiga comportar-se bastante bem nos dois ambientes.

O que vou dizer de seguida poderá escandalizar algumas pessoas, mas na minha opinião, acho que o Joomla! deverá de deixar de ser um CMS de uma vez por todas. Passo a explicar.

Imaginemos que o Joomla! é na realidade um conjunto de apenas dois produtos, um no topo do outro, em sem finalidade inicial específica. Poderá ser um CMS, ou ser qualquer outra coisa. Vamos chamar a estes produtos uma Framework e uma Plataforma por agora. A finalidade destes dois produtos seria bem diferente, mesmo que um destes dependesse a 100% do outro. A Framework iria funcionar como a estrutura em madeira típica duma casa americana, e a Plataforma iria funcionar como o chão em madeira que assenta em cima. Eles não iriam definir a forma e/ou formato da casa, mas iriam funcionar como as fundações da mesma.

Isto iria representar uma mudança drástica na filosofia actual do Joomla! (baseada num CMS), e o maior argumento contra esta abordagem poderia ser que o Joomla! teria de ser completamente re-escrito, sendo necessário demasiado tempo e trabalho para o fazer. O mais engraçado neste argumento, é que não é verdadeiro. Esta abordagem não implicaria uma re-escrita completa do Joomla! (até um certo ponto). A maioria das bibliotecas e classes do Joomla! poderiam ser re-utilizadas (apenas de forma diferente), e as pequenas alterações que necessitariam, (ex:. Namespaces) já estão agendadas para o J!4.

Framework Joomla!

Na base, teríamos a Framework. A Framework não necessita chamar-se mesmo Framework, e para poder evitar confusão desnecessária a pessoas que venham de outras frameworks, deveria chamar-se outra coisa. Poderíamos chamar-lhe "Engine" (motor), ou algo como o "Construtor" (Construct como no Matrix). Se se lembrarem do The Matrix, o Construct era o programa base no qual o Matrix corria. O Morpheus também o usava para carregar programas de treino de luta com o Neo, e do que me lembro, também seria usado para carregar armamento. Para manter esta conversa séria, chamarei à camada inferior do Joomla!, o Engine.

Matrix Construct

 

Como o próprio nome diz, o Engine funcionaria como o motor do Joomla!. Isto quer dizer que, o Engine seria responsável por toda a mecânica do Joomla!, e permaneceria leve (recursos) e agnóstico em relação ao output gerado. Apesar não limitado a isto, as suas responsabilidades principais seriam:

De forma a manter o Engine extensível, o objecto principal da aplicação deverá ser event driven (accionada por eventos), e funcionar como  and work as a dispatcher (expedidor) de outros objectos/funcionalidades.

Temos que admitir. Existe uma sequência/ordem pela qual o pedido Web é processado, e esta sequência evolve um conjunto de etapas despoletadas pelo pedido do utilizador, e acabam, com uma resposta do servidor. Ao abrir esta mesma sequência, e ao fazer com que seja possível adicionar novos passos a essa mesma sequência, o Engine poderá ser facilmente estendido, por exemplo por, uma Plataforma assente no seu topo.

Imaginemos a seguinte sequência de execução simplificada:

Agora, imaginemos uma simples definição de classe (interface), para o motor da aplicação, que poderá ser parecida com isto:

<?php

final class Engine
{
    public function addEvent($name, $after = null);
    public function addEventHandler($event, $handler);
    public function execute();

    private function callEventHandler($eventHandler);
}

Uma definição mais completa da classe poderá ser algo do género:

Nota: Lembrar que o seguinte código não foi convenientemente testado nem acabado, e deverá ser visto meramente como exemplo.

<?php

/**
 * Engine processing class.
 *
 * @author    Hugo Rafael Azevedo
 * @version   1.0.0
 * @since     1.0.0
 */
final class Engine
{
    /**
     * @var  array  $events  List of available events for the execution's cicle.
     */
    private $events = null;

    /**
     * @var  array  $eventHandlers  List of event handling functions for each of the available events.
     */
    private $eventHandlers = null;

    /**
     * Initializes Engine object.
     * Adds all initial Engine's events, and corresponding initial event handlers.
     */
    public function __construct()
    {
        // Creates event related lists.
        $events        = array();
        $eventHandlers = array();

        /**
         * Starts loading initial event list, and corresponding event handlers.
         * This will be an initial list, that can be expanded during the application's execution.
         * 
         * The actual task, is the first event handler on the corresponding onAfter event.
         * This way, any onBefore event handler will always execute before the actual task,
         * and every onAfter event handler will always execute after the actual task.
         */
        $this->addEvent("onAfterRequest");
        $this->addEventHandler("onAfterRequest", "first.initial.after.request.task");

        $this->addEvent("onBeforeSessionLoad");
        $this->addEvent("onAfterSessionLoad");
        $this->addEventHandler("onAfterSessionLoad", "first.task.that.actually.loads.session");

        $this->addEvent("onBeforeDatabaseConnection");
        $this->addEvent("onAfterDatabaseConnection");
        $this->addEventHandler("onAfterDatabaseConnection", "first.task.that.actually.connects.to.database");

        $this->addEvent("onBeforeUserProfileLoad");
        $this->addEvent("onAfterUserProfileLoad");
        $this->addEventHandler("onAfterUserProfileLoad", "first.task.that.actually.loads.user.profile");

        $this->addEvent("onBeforeExecuteContent");
        $this->addEvent("onAfterExecuteContent");
        $this->addEventHandler("onAfterExecuteContent", "first.task.that.actually.executes.content");

        $this->addEvent("onBeforeResponse");
        $this->addEvent("onAfterResponse");
        $this->addEventHandler("onAfterResponse", "first.task.that.actually.returns.content");

        $this->addEvent("onBeforeClearResources");
        $this->addEvent("onAfterClearResources");
        $this->addEventHandler("onAfterClearResources", "first.task.that.actually.clears.resources");
    }

    /**
     * Adds a new event to the event list.
     * 
     * @param  string    $name   Name of the event to add to the list
     * @param  string    $after  Name of an event, after which the new event will be added. If NULL, will add new event to end of list.
     * @throws Exception
     * @return void
     */
    public function addEvent($name, $after = null)
    {
        // Checks if event's name is filled.
        if ($name == null || strlen(trim($name)) == 0)
            throw new Exception("Invalid parameters. Event name can't be empty.");

        // Standardize event's name.
        $name = strtolower(trim($name));

        // Check if event is to be added at the end of the execution cicle.
        if ($after == null || strlen(trim($after)) == 0)
            array_push($this->events, $name);
        else
        {
            // Standardize previous event's name, and checks if it is filled. 
            $after = strtolower(trim($after));
            if (($key = array_search($after, $this->events)) !== false)
            {
                // Inserts new event after previously found event.
                array_splice($this->events, $key, 0, $name);
            } else {
                throw new Exception("Invalid parameter. No event found.");
            }
        }

        // Adds an empty array to the event's eventHandler list.
        $this->eventHandler[$name] = array();
    }

    /**
     * Adds a new event handler to an already created event.
     * 
     * @param  string    $event    Name of the event for which a new event handler will be added.
     * @param  string    $handler  Name of the event handler to be added. 
     * @throws Exception
     * @return void
     */
    public function addEventHandler($event, $handler)
    {
        // Checks if parameters are filled.
        if ($event == null  ||
            $handler == null ||
            strlen(trim($event)) == 0 ||
            strlen(trim($handler)) == 0)
            throw new Exception("Invalid parameters. Event and Eventhandler names can't be empty.");

        // Checks if provided event exists.
        if (array_search($event, $this->events) === false)
            throw new Exception("Invalid parameter. No event found.");

        // Inserts new event handler in list.
        // New event handlers will always be added to the end of the event handlers list, for the specified event.
        array_push($this->eventHandlers[$event], $handler);
    }

    /**
     * Executes all Engine's events.
     * 
     * @return void
     */
    public function execute()
    {
        // Initializes control variable.
        $step = 0;

        // Loops until the execution step is out of the array's scope.
        // During event execution, new events might be added to the list, so this count needs to be updated for each iteration.
        // If the step exits the list boundaries, execution exits the loop.
        while ($step <= count($this->events))
        {
            // Collect current event for execution.
            $event = $this->events[$step];
			
            // Loop through all the event handlers associated with current event.
            foreach ($this->eventHandler[$name] AS $eventHandler)
                $this->callEventHandler($eventHandler);

            // Event processing is finished. Update execution step.
            $step++;
        }
    }

    /**
     * Does all the processing necessary to reflect call the specified method.
     * Implementation not needed for example.
     * 
     * @param  string  $eventHandler  Path to eventHandler method
     */
    private function callEventHandler($eventHandler)
    {
        // TODO: Verify path to, and include eventHandler's file.
        // TODO: Initialize necessary object(s).
        // TODO: Execute method using reflection.
    }
}

O objecto do Engine poderá ser executado apenas com duas linhas de código, e poderá também ser facilmente estendido:

<?php
// Engine's simple execution.
$engine = new Engine();
$engine->execute();

/**
 * Could also be extended, even in executing events.
 * Here, similar Joomla!'s syntax was used.
* * First, we'll declare a class that will be executed before the content gets processed.
* In the middle of that event's execution, we will add a new eventHandler to another class,
* therefore extending the application's functionality. */ class exampleClass { public function testMethod() { // Get Application object, and add a new Handler in the middle of the execution. $app = \Path\To\Joomla\Application\Object\JApplication::getEngine(); $app->addEventHandler("onAfterExecuteContent", "\Namespace\Path\To\Another\Class\secondClass.anotherMethod"); // Outputs a string. echo "exampleClass.testMethod(); \n"; } } // Adds a second class to be executed. class secondClass { public function anotherMethod() { // Outputs a string. echo "secondClass.anotherMethod(); \n"; } } // Initializes the engine, and executes it. $engine = \Path\To\Joomla\Application\Object\JApplication::getEngine(); // Add a Handler "exampleClass->testMethod()" to be executed before the main content. $engine->addEventHandler("onBeforeExecuteContent", "\Path\To\First\Class\exampleClass.testMethod"); $engine->execute();

O código anterior irá gerar o seguinte output:

// (Enters the onBeforeExecuteContent event)
outputs: exampleClass.testMethod();
// (Enters the onAfterExecuteContent event)
// Processes main content.
outputs: secondClass.anotherMethod();

O Engine também deverá incluir uma directoria para carregamento automático, onde blocos (grandes) de código que não encaixam na definição de extensão, poderão ser incluídos/ligados (ex:. Plataforma).

O maior benefício desta abordagem, é que o programador deverá assim ter acesso a um produto muito leve (lightweight), despojado de extras, que poderá ser usado num webservice e/ou tarefas automáticas (CLI), ou por exemplo, uma implementação base dum servidor de updates para o Joomla!, sem ter que ter o exagero de ter todo o Joomla! (CMS) instalado.

Todos os eventos iniciais do Engine seriam publicados no site do Joomla!, para que os programadores pudessem saber de antemão o fluxo de informação da aplicação. Não só um sistema accionado por eventos é facilmente entendido, mas poderá também fornecer aos programadores um muito bom ponto de arranque para o produto que desejem desenvolver. Sendo tudo accionado por eventos, e em conjunto com funcionalidades de auto-carregamento, o Engine poderá facilmente ser estendido a a qualquer tipo de tarefas.

O próprio Engine, utilizaria o seu próprio conjunto de eventos para carregar outras classes que necessitaria para executar uma tarefa. Por exemplo, o Engine poderia usar o evento onAfterRequest (que seria o primeiro evento a ser executado), e anexar um event handler que iria inicializar o object actual JFactory. Há altura da execução do segundo evento do Engine (onBeforeSessionLoad), já teria o JFactory à sua disposição.

Plataforma Joomla!

Como foi dito anteriormente, o Engine seria agnóstico em relação ao formato do output, e a sua principal funcionalidade seria criar um ambiente capaz de processar/executar uma tarefa apenas (request/response), retornando o seu conteúdo. Sendo assim, não iria ter que lidar com a inúmeras funcionalidade inerentes a uma aplicação Web. É aqui que a Plataforma entraria.

A Plataforma Joomla! poderá ser vista como uma Framework em cima de outra Framework, mas com um propósito específico, desenvolvimento Web Aplicacional. Estaria dependente do Engine, iria introduzir funcionalidades específicas de UI (html), e deveria permitir o desenvolvimento dum número infinito de aplicações (simultâneas), que partilhariam os mesmos recursos (ex:. sistema de ficheiros, base de dados, js files, ficheiros css, imagens, documentos, etc.). A Plataforma Joomla! teria de ser a responsável por introduzir funcionalidades inerentes a Templates, Módulos ou snippets de código na solução ( ou qualquer outra funcionalidade inerente ao UI).

A Plataforma deveria usar a funcionalidade de auto-carregamento, e adicionava o seu próprio conjunto de eventos à volta dos já existentes no Engine, e no processo, estendendo as suas funcionalidades desde o seu interior. Programadores de Componentes também poderiam usar o mecanismo accionado por eventos, e anexar novas tarefas necessárias, como por exemplo, logging, alterar o buffer da aplicação, etc... Em vez ter plugins externos, os programadores poderiam ligar directamente a um Método num Controlador (MVC), mas isso terá de ficar para outra discussão.

Ao permitir que inúmeras aplicação simultâneas possam correr em cima da Plataforma, o programador/implementador poderia ter apenas uma aplicação (edição front-end), ou ter diversas aplicação na mesma solução , cada uma identificada pelo seu próprio ID, como hoje em dia já faz (ex:. site e admin).

O ponto de entrada para cada aplicação também não deveria ser pertinente. O que isto quer dizer é que, o implementador poderia ter o painel de administração (admin) num sub-domínio do front-end, ou num domínio completamente diferente, desde que, partilhassem o mesmo sistema de ficheiros, base de dados e recursos (media). Sendo assim, a localização da aplicação de administração poderia ser ofuscada, que permitira desde logo a separação do log de acessos do servidor web.

A verdade é que, isto já poderia ser feito hoje em dia, alterando 2 ou 3 extensões, e alterando os ficheiros de entrada das aplicações, no entanto, outras extensões (principais incluídas) iriam quebrar e deixar de funcionar convenientemente.

A Plataforma Joomla! teria também de produzir uma solução completa em termos de SEO, multi-linguagem, integração com redes sociais, e produzir markup semântico completamente em conformidade com os standards web actuais ao utilizador. Também deveria facilitar a integração de bibliotecas e frameworks para o front-end. Uma coisa que nunca fez muito sentido para mim, ao começar a usar o Joomla!, foi o facto de ter de o estender com plugins, apenas para poder ter URLs SEF, que no final, apenas iriam garantir uma boa implementação nas extensões principais, não nas de terceiros. Se eu quiser meta-tags standard, terei de fazer o override a tudo que é extensão, e incluir o seu código de processamento em Views, e não nos Models (assumindo que isso faz parte da lógica de negócio).

E então o CMS?

Essa é a melhor parte. Ao fazer com que a Plataforma Joomla! corra em cima de um motor (Engine), o CMS passa a ser apenas uma implementação possível para o Joomla!, e não o próprio Joomla!. Funcionaria como uma Distro funciona no universo do Linux, que traria inúmeros benefícios aos seus utilizadores.

Primeiro, não haveriam extensões principais, e todas a extensões principais de sistema (ao contrario das principais de conteúdo) só funcionariam como UIs para as funcionalidades já existentes, quer do lado do Engine ou da Plataforma. Todas as extensões seriam dissociadas do Joomla!, o que quer dizer que mesmo que viessem numa implementação do Joomla!, o utilizador/implementador ainda as poderia desinstalar, e reinstalar conforme necessário, incluindo as extensões principais de conteúdo. Isto iria permitir a substituição de toda e qualquer extensão que viesse numa implementação do CMS Joomla!, e isto faria com que se tornasse literalmente, uma solução para todos.

Poderia have uma distro do Joomla!, com um componente de gestão de artigos simplificada, que seria perfeito para bloggers, mas poderia haver outra distro com uma gestão integral de artigos para um tipo de utilizadores mais exigentes (ex:.um jornal).

Benefícios deste sistema

Existem vários benefícios que poderão emergir deste tipo de abordagem, alguns directos, outros indirectos, mas os principais estarão relacionados com a separação de interesses.

Ao separar tudo, estamos a criar produtos diferentes, que poderão ser mantidos separadamente, em com diferentes ciclos de produção. Não seria necessário actualizar todo os sistema CMS, e incrementar a sua versão apenas devido a melhoramentos/correcções no Engine. Poderia ser possível apenas actualizar o Engine, e possivelmente, tudo no seu topo permaneceria igual. O Engine e a Plataforma teriam ciclos de produção diferentes, e poderiam ser suportados por muito mais tempo (LTS), porque na realidade, ambos nunca deixariam de ser suportados.

Ao serem dissociadas, as extensões de conteúdo (artigos, categorias, menus, etc...) também seriam desenvolvidas separadamente. Disponibilizar um upgrade para a Plataforma, não iria forçosamente implicar uma alteração numa extensão de conteúdo, e vice-versa.

Em conclusão, seria tudo muito mais sustentável.

E então, o que é que acontece aos números das versões actuais, or exemplo, do CMS? Bom, na realidade desapareceriam. A implementação do CMS passaria a ser disponibilizada apenas uma vez por ano, e iria apenas conter uma instalação limpa dum conjunto pré-definido de extensões. A Equipa de Produção poderia disponibilizar todos os anos na JWC uma versão nova, apenas com o número do ano à frente (ex:. Joomla!16 CMS, Joomla!17 CMS, etc…).

A comunidade também poderia envolver-se mais na escolha das extensões que iriam fazer parte de cada disponibilização/versão, extensões estas,m que estivesses disponíveis no JED. Talvez um novo componente de gestão de artigos poderia ser incluído num ano, ou até mesmo um novo Template, dependendo da distro escolhida.

SmarterQueue - A forma mais inteligente de criar em redes sociais

SmarterQueue - A forma mais inteligente de criar em redes sociais

LRTT - Limited Resource Teacher Training

LRTT - Limited Resource Teacher Training

shareOptic - Solução de monitorização de cyber segurança

shareOptic - Solução de monitorização de cyber segurança

Blockz RAD framework web em Php

Blockz RAD framework web em Php