como lidar com mutações do controlador

5

Durante o processo de desenvolvimento, as coisas estão mudando constantemente (especialmente nas fases iniciais). Mudança de requisitos, mudanças na interface do usuário, tudo muda. Páginas que claramente pertenciam a um controlador específico, transformadas em algo completamente diferente no futuro.

Por exemplo. Vamos dizer que temos site para gerenciar projetos. Uma página do site foi dedicada à gestão existente e convidando novos membros de um projeto específico. Naturalmente, criei o controlador de membros aninhado em projetos que tinham a devida responsabilidade.

Mais tarde, no desenvolvimento, descobriu-se que era a única página que "configurava o projeto" de alguma forma, então funcionalidades adicionais foram adicionadas a ele:

  • editando a descrição do projeto
  • definindo o projeto como padrão
  • ...

Em outras palavras, esta página mudou sua principal responsabilidade de gerenciar membros do projeto para gerenciar o próprio projeto. Idealmente, essa página deve ser movida para a ação "editar" do controlador "projetos". Isso significaria que todas as especificações de solicitação e controlador também precisam ser refatoradas. Vale a pena o esforço? Deve ser feito?

Pessoalmente, estou realmente começando a não gostar da relação 1-1 entre visualizações e controladores. Sua situação comum é que temos 1 página (view) que lida com 2 ou mais recursos diferentes. Acho que devemos ter visões completamente dissociadas dos controladores, mas os rails estão nos atrapalhando para conseguir isso.

Eu sei que o AJAX pode ser usado para resolver esse problema, mas considero isso uma improvisação. Existe algum outro tipo de arquitetura (além do MVC) que desacople as visões dos controladores?

    
por Milovan Zogovic 17.11.2011 / 08:53
fonte

3 respostas

1

Aplicar a composição sobre herança aos controladores é uma das abordagens com as quais você não pode errar.

A idéia é ter o menor controle possível. O controlador deve apenas definir os processos de solicitação / resposta, mas qualquer coisa substancial acontecendo entre os dois será definida fora da classe.

Por exemplo, se você tivesse um controlador que filtrasse uma coleção de Product instâncias por um determinado critério, aplicasse o IVA ao preço base e produzisse uma representação tabular, CSV ou resposta JSON, você acabaria com as seguintes classes:

  1. Uma classe que recebe o objeto de solicitação e retorna uma coleção apropriada de Product instances; essa classe se preocupa em saber como construir uma consulta apropriada com base na solicitação recebida (como a consulta de produtos com base em uma mistura de valores de atributos).
  2. Uma classe que usa uma coleção Product , processa cada entrada e retorna a coleção resultante; essa classe está preocupada em obter o IVA especificado de um produto e aplicá-lo ao preço base.
  3. Uma classe que recebe o objeto de solicitação de entrada e uma coleção Product e produz uma resposta apropriada; essa classe está preocupada em descobrir se deve produzir uma resposta HTML, CSV ou JSON da coleção.
  4. Seu controlador real que simplesmente cria uma rede de comunicação entre as três classes; Essa classe finalmente especifica a noção de coletar, processar e exibir o modelo Product apropriadamente.

A questão é que os controladores muitas vezes acabam exibindo muito comportamento complexo, mas dessa forma esse comportamento é fatorado em vários componentes diferentes que são definidos e testados independentemente. Simplesmente misturando classes diferentes e alterando algumas linhas de código, o comportamento do seu controlador muda drasticamente. Eu realmente não tenho nenhuma experiência com Ruby, mas pelo que eu sei isso pode ser alcançado incluindo e misturando diferentes módulos e talvez até mesmo uma macro ou duas para temperar.

Um bom exemplo dessa abordagem são os controladores genéricos do Django. Eles são apenas tipos compostos de mixins diferentes, onde cada mixin define determinado comportamento e expõe atributos de classe e métodos de instância que podem ser especificados / substituídos para configurar seu comportamento. Os controladores genéricos fornecidos são apenas uma combinação particular de mixins existentes que são adequados para um problema específico.

Outro bom exemplo é o Android com seus controladores. Um Acitivty é chamado pela estrutura de instrumentação sempre que a atividade precisa responder a um determinado tipo de solicitação (crie você mesmo, inicie-se, destrua você mesmo) com determinada entrada, mas tudo está acontecendo em um thread da interface do usuário que espera que esses métodos sejam mal-humorado. Qualquer coisa substancial, como compactação de número, recuperação de dados por HTTP, coleta de dados do banco de dados, etc., é gerenciada por objetos de alguns tipos externos que comunicam alguns dados de volta ao controlador de chamada. Às vezes, essa comunicação é genérica o suficiente para que possa ser estruturada implementando interfaces e o comportamento pertencente a cada uma delas seja especificado em uma classe anônima. Novamente, você acaba com um controlador simples que conecta apenas uma rede de comunicação entre objetos diferentes para definir um comportamento complexo, mas o comportamento é definido de uma forma compacta a partir da qual você pode facilmente descobrir o que está acontecendo.

Esta é a reutilização de código prometida pelo princípio de composição: se o comportamento do seu controlador precisa ser migrado para um controlador diferente ou se um determinado tipo de comportamento precisa ser compartilhado entre vários controladores, a composição sobre herança fornece a capacidade de faça isso. E o melhor, aplicando o Princípio da substituição de Liskov , as possibilidades tornam-se infinitas!

    
por 16.03.2012 / 21:05
fonte
1

Bem, para manter meu código organizado, muitas vezes:

  • decida extrair alguma lógica do controlador para uma superclasse e fazer o controlador herdar dela. Desta forma, os controladores acabam chamando o método e permanecem limpos, evitando duplicação

  • A mesma coisa pode ser feita incluindo módulos nos seus controladores

  • uma solução alternativa seria usar um componente de terceira parte como Cells .

por 17.11.2011 / 13:45
fonte
0

Eu também acho esse problema com frequência. Eu faço algumas coisas para consertar;

Eu coloco tudo o que posso nos modelos para não confundir meus controladores e geralmente faço isso quando você clica em um projeto em / projects (projetos # index) e vai direto para / projects /: project_id / membros (membros # index) em vez do padrão / projects /: id (projects # show). Motivo para isso é que os membros são o recurso principal na página.

    
por 17.11.2011 / 12:08
fonte