Traits combina com sexta-feira 13

Vamos lembrar dos princípios S.O.L.I.D. de desenvolvimento ? Single responsibility; open closed; liskov (o incompreendido) substitution; interface segregation e dependency invertion.

texto de busão de hoje vai falar de interface segregation. Se você lembra da série de Hangouts onde discutimos os princípios, vai lembrar que interface segregation é a divisão das características/comportamentos suportados por uma classe em interfaces que devem ser implementadas (implements) por uma class interesada em ser caracterizada como uma classe que suporta aquela característica.

Esse princípio garante um contrato melhor para as classes, afinal, um contrato deve ter somente o imprescindível para atingir seu objetivo, algo que na pratica, é facil de ver desenvolvedores esquecendo.

Se começarmos a fuçar pelos códigos da github sphere vamos encontrar interfaces que representam muitos comportamentos. E vamos encontrar classes que implementam essas interfaces e resolvem o problema do suporte a métodos do contrato que não lhe interessam fazendo implementações vazias. Um crime, um history-crime, um crime a ser julgado pelo seldon. Um caso para o pré-crime, a ser tratado pela divisão de crimes futuros ou ainda, um crime-pensamento!

Se você implementar uma interface e notar esse comportamento, de que parte do contrato não te interessa, segregue!

Segregue fazendo isso de uma maneira incrementalmente e como hoje é sexta-feira 13 vou correr o risco e sugerir um procedimento real e preguiçoso para realizar essa tarefa.

1. descubra a separação das intenções da interface.
2. crie uma segunda classe com um nome que sugira “a capacidade de”, “Able To” dar suporte a característica que vc resolveu separar.
3. copie as declarações do comportamento que você deseja extrair e cole no arquivo da nova interface.
4. apague o comportamento extraído da interface original.
5. renomeie a interface original para um nome que se adeque ao novo objetivo.
6. procure por todo o projeto por “implements [nome interface original]” e substitua por “implements [novo nome],[nova interface]”
7. rode os testes
8. pegue um cerveja, olhe no espelho e repita 10 vezes o exercício “sensual e erótico” do Homer Simpson.

Certo, após tudo isso haverão menos filhotes focas mortos nos pólos do mundo e poderemos continuar com nossas vidas sem dar show/piti gritando!

Agora, se você tem uma interface é por que notou que certo comportamento seria compartilhado por uma classe de implementações, afinal, qual outra prerrogativa poderia existir? (pergunta retórica, ok)

Digamos que você notou que esse comportamento deveria chamar smokeable, implementando dando suporte as seguintes ações:

interface smokeable{
   public function acenda();
   public function puxa();
   public function prende();
   public function passa();
   public function apaga();
}

E você vai feliz adicionar o comportamento nas classes.

Você implementa o contrato smokeable em class Person, programa os métodos, depois faz o mesmo com class Gods e nota que vai ter de escrever os mesmos métodos. Como é a segunda vez você aceita o pênalti, mas ai eis que surge a class Batman e você vai fazer class Batman implements smokeable e percebe que não está disposto a copiar aquele código da implementação de suporte a smokeable novamente. O que fazer?

Alguém lá do fundão da classe grita: abstract class smoker implements smokeable!!!

Não, porra!!! Batman, Gods e Person não extends smoker, nem que fosse fumantes inveterados. Essa não é a característica sobre a qual eles surgiram.

Não dá para declarar:
“Isso” fuma, logo ou ele é person, ou Gods ou o Batman!

Extends significa isso. E se você extends a coisa errada você esta chamando urubu de meu loro. Não faça isso, em nome dos bebês foca.

Mas os deuses do php, (aka Stefan Marr, Sara Golemon, Felipe Pena, Derick Rethans e outros responsáveis pelo PHP, alguns deles ligados diretamente a Traits)  foram bons (ou maus) e roubaram o raio de zeus, que o programador pode usar como isqueiro ou como fio de alta tensão caindo na banheira durante o banho com sais durante uma brincadeira de crossdressing(já pensou?).

Traits senhores, traits. O raio de Zeus, aquele piadista, sentado no seu trono vestido com a toalha da mesa de jantar.

Traits são perfeitas para suportar interface segregation. Vejamos:

Você não consegue dizer traits implements [interface], aliás vc não consegue dizer traits 11 vezes seguidas, bem rápido.

Você não consegue fazer uma trait implements uma interface, mas ela suporta propriedades, métodos e escopos, então é perfeitamente possível e desejavel que…

Trait smoker{

private whathastosmoke;

public function acende()
{
}

public function puxa()
{
}

public function prende()
{
}

public function passa()
{
}

public function apaga()
{
}

Class Batman implements smokeable
{
Use smoker;

}

Dessa maneira o contrato tem uma implementação padrão do comportamento na Trait Smoker, mas se uma classe for implementar o comportamento mas o codigo da implementação(não a interface: input, output) for diferente, você pode implementar smokeable e desenvolver o código especial.

De uma hora para outra podemos levar a sério interface segregation e com isso passamos a ter um controle muito melhor dos nossos softwares, afinal, nunca devemos esquecer o mantra:

Programe para uma interface e não para uma implementação!

Mas lembre-se, se você usar traits de maneira correta

Screenshot 2015-02-13 10.38.56 senão Screenshot 2015-02-13 10.39.03

E ja que falamos da má aplicação de Traits, acho melhor, aconselhado pelo @alganet expor aqui o que seria uma má prática de uso de Traits.

Pense traits como ele é, um recurso do PHP para ser utilizada em conjunto com o paradigma de Orientação a Objetos(ta, podemos discutir depois). Se você extrapolar esse pensamento vai resultar em:

Pensar em Traits é também pensar em Orientação a Objeto. Então o que esta errado em O.O. esta errado com ou sem Traits.

Por exemplo, você implementaria o método log(Message $message) na classe Batman? Melhor, você implementaria log(Message $message) em qualquer classe que não uma classe especializada em Log?

A resposta correta é NÃO!

Logar não é uma característica de uma classe de negócio, mas uma necessidade que ela tem para que seja possível fazer o trace dos eventos e entender erros e processos. A prática diz que o recurso de logar é usado pelas classes e não, repito, não é uma característica dela, mais ou menos como a diferença entre pensar que um ser humano precisa de ar para viver é diferente de pensar que ele faz fotossíntese para produzir ar para poder viver, entende?!

Então a seguinte prática é errada, ruim e faz bebês focas morrerem:

Trait Log{
 public function logar(Message $message)
{
  //escrever log no arquivo....
}

Class Batman {
 use Smoker;
 use Log;
}

$fuckingFodaGuy = new batman();
$batman->log("Corre Bino, é uma cilada!");

Uffa, chega por hoje… bjunda no ombro!!!

2 thoughts on “Traits combina com sexta-feira 13

  1. A forma que você explorou o use de traits foi fantástico, principalmente ao vincular ao princípio de segregação de interfaces. Mostrar que muitas vezes SE COMPORTAR como algo é mais relevante do que SER algo.

    A única coisa que gostaria de trazer a atenção é que nem sempre colocar o sufixo “able” vai significar aquilo que queremos. Smokable, por exemplo, significa “fumável” e dizer que uma pessoa é fumável é bizarro.

    Um cigarro é fumável, um cachimbo é fumável, agora uma pessoa?

    Sem contar que quando falamos das ações de acender, puxar, prender, passar e apagar falta um complemento (o que está sendo aceso, puxado, prendido, etc).

    Interfaces podem ser substantivos também, assim alteraria a parada para o seguinte:

    interface Smokeable
    {
         // use a imaginação aqui, estou preguiçoso neste momento hahaha
    }
    
    interface Smoker
    {
       public function acenda(Smokeable $barato);
       public function puxa(Smokeable $barato);
       public function prende(Smokeable $barato);
       public function passa(Smokeable $barato);
       public function apaga(Smokeable $barato);
    }
    

    Assim é possível tirar o atributo da trait (para Person, Gods ou Batman isso é apenas um detalhe irrelevante…).

Leave a Reply to lcobucci Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s