ood – Hélio Costa
Talk: Hanami, Domain-Driven Design e Arquitetura
Falei no The Developers Conference em São Paulo (TDC pros marotos) na trilha de Ruby sobre como o Hanami pode ser um excelente pivô para uma arquitetura evolucionária e dar suporte ao bom design de código em softwares enterprise.
Os slides estão em minha conta no Speaker Deck e os deixo aqui:
hlegius	software-architecture, technologies	Deixe um comentário julho 24, 2017 setembro 24, 2017 1 minuto
Definir classes não é programar com orientação a objetos: Ciclo de vida
Há pouco mais de 2 anos, falei sobre esse tema na PHP Conference Brasil e acho válido revisitá-lo uma vez que muitos desenvolvedores sentem orgulho em dizer que programam orientado a objetos, mas ao fazer uma simples pergunta acabam não sabendo respondê-la:
O que é Orientação a Objetos ?
Alan Kay, criador da linguagem Smalltalk e um dos primeiros defensores da orientação a objetos, a explicou da seguinte forma:
"The big idea is "messaging" (…)
Pronto, fim do post. Obrigado por ler.
De nada adianta falar sobre Test-First, Princípios de Orientação a Objetos, Mocking, AntiPatterns uma vez que não se conhece o núcleo da Orientação a Objetos.
O grande cerne da questão é justamente a troca de mensagem entre objetos através de seus métodos. É assim que Alan Kay defendeu e é assim que o Smalltalk funciona. Recentemente, alguns desenvolvedores, especialmente em Ruby, têm voltado a reforçar o propósito em OO.
A melhor forma de manter seu código desacoplado e "falante" é forçar os objetos a trocarem mensagens. Lembra do Tell Don't Ask? Pois é, aqui isso é parte chave para atingir-se tal objetivo.
http://pragprog.com/articles/tell-dont-ask
Tem a versão do Giovanni Bassi, do .NET Architects também;
Pronto, acho que deu para entender o quão importante é manter no objeto a responsabilidade de manipular os próprios dados (armazenados em vossos atributos).
O Ciclo de Vida de um Objeto
Já parou para pensar em qual seria o ciclo de vida de um objeto?
Bom, inicialmente ele Nasce, depois Cresce, Continua disponível e finalmente Morre.
O nascimento de um objeto
O nascimento do objeto é através de seu construtor. Simples, porém muitas vezes ele acaba ignorado, ainda mais quando vicia-se em utilizar frameworks arquiteturais sem entender o motivos das coisas.
Employee.new(name: "Durval", lastname: "da Silva", cpf: "123.123.123-X")
new Employee("Durval", "da Silva", "123.123.123-X")
durval = Employee.new
durval.name = "durval"
durval.lastname = "da Silva"
durval.cpf = "123.123.123-X"
durval = new Employee();
durval.setName("durval");
durval.setLastname("da Silva");
durval.setCpf("123.123.123-X");
O motivo é simples: o construtor é o contrato que nos diz: "para você obter um novo objeto tipo Employee, você precisa obrigatoriamente me informar: Nome, Sobrenome e CPF, pois caso contrário, você criará um Employee inválido."
E é justamente o que o exemplo incorreto faz: cria um Employee sem dado algum. Quem garante que eu irei chamar setName, setLastname e setCpf depois? Eu posso esquecer. Pode nem ser eu o responsável por utilizá-lo depois. (APIs-like).
Lembre-se o construtor é a certidão de nascimento do objeto. Não tire dele esse direito. Brasil, país rico é país…
Aqui temos outros métodos que mudarão o status de nosso objeto ao longo de sua vida. Nem sempre é com setter – outro erro comum daqueles que programam por coincidência. Veja exemplos:
employee.exame_admissional = arquivo_pdf_do_exame  # snake case r0cks
employee.setExameAdmissional(arquivoPdfDoExame)
employee.definir_credencial_de_rede(username: "new_username", password: "983hJfh78")
objeto_credencial = Credencial.new(username: "new_username", password: "9789237498")
employee.credencial = objeto_credencial
objetoCredencial = new Credencial("new_username", "3798472398478234")
employee.setCredencial(objetoCredencial)
Neste caso, o incorreto viola o encapsulamento da Credencial, deixando a cargo do cliente conhecer como a Credencial é criada. Para entender melhor, desenho:
Cliente é toda classe que utiliza outra. Só para deixarmos as coisas claras por aqui.
O problema aí é que no caso o Controller precisa saber como construir Employee e Credencial, além de precisar conhecer como relacioná-las. Um exemplo mais OOP seria:
Agora, o Controller precisa apenas lidar com Employee e este lidará com a Credencial. Em pseudocódigo, ficaria:
# construtor e outros métodos ocultados
def define_credencial(username: username, password: password)
@credencial = Credencial.new(username: username, password: password, employee: self)
# Java, et al.
public void defineCredencial(String username, String password) {
credencial = new Credencial(username, password, this);
Neste caso, Credencial é um Value Object pertencente ao Employee. Esse tipo de relacionamento é parte do Domain-Driven Design e é chamado de Aggregate Root.
Aggregate root são úteis quando você tem um relacionamento aonde a Parte (Credencial) é totalmente dependente do Todo (Employee). Em outras palavras: a Parte só tem vida quando o Todo tem vida. Não é legal que uma Parte tenha vários Todo(s).
Continuando disponível
Em orientação a objetos, nossa linha de pensamento deveria ser um pouco mais ampla. Ou seja, devemos pensar que uma vez que o objeto é criado (instanciado) ele ficará disponível até que alguém o mate (remova da memória). Enquanto ninguém o remover da memória, ele continuará vivo.
É importante esquecer o meio/tipo de armazenamento aqui. Robert Martin (@unclebob) falou sobre isso na sua must watch palestra na Ruby Midwest 2011 – sério: assista até o fim. Você será outro depois disso 😉
O objeto é removido através do Garbage Collector, Removido com ORM, etc. Aqui não há novidade mesmo.
1 imagem, 1000 palavras
O meio de vida do objeto (aquele dentro do retângulo) é aonde a maior parte dos objetos estarão. Ao buscar um objeto com um Repository por exemplo, devemos pensar que o objeto estava em memória, já construído e do jeito que o deixamos da última vez que trabalhamos com ele. Ou seja: o Repository não dará new novamente, pois o objeto já existe. Pelo que me lembro, o Doctrine 2 seguia isto: ao recuperar um objeto do Repository o construtor não era chamado novamente – o que é excelente, pois o Ciclo de Vida do Objeto não é quebrado!
O tema é extenso assim como Test-First. Conhecer bem o que a Orientação a Objetos reserva e espera de você é pré-requisito para iniciar com Teste de Software em aplicação Orientada a Objeto. Na sequência, continuarei a falar sobre Object Oriented Design para permitir que se veja além ao testar software.
hlegius	post-series	Deixe um comentário maio 19, 2014 setembro 24, 2017 4 minutos
Traits em PHP. Herança Horizontal
Post revisitado em junho/2014. Tudo que está aí funciona na versão atual PHP 5.5.x. Enjoy 😉
Antevejo que no futuro, o PHP como uma linguagem iterativa e incremental que é, adicionará ao seu núcleo um recurso muito valioso na categoria orientação à objetos.Antevejo ele, os Traits. E mais, consigo prever que será algo assim:
ola()} trait !";
$ola = new Mundo();
$ola->world();
// Olá trait !
Ok, não sou bidu. Realmente os Traits estão na lista do possível-futuro PHP 5.4 e eu, baixei a build de 31/03/2011 para testar.
O PHP não suporta herença multipla – amém – e por este motivo, às vezes ficamos limitados em algumas decisões de projeto (design). O maior problema neste ponto é que toda herença até agora (PHP 5.3.x) é vertical, ou seja, se eu precisar de um nível de abstração diferente no meio do processo, ou precisarei adicionar a nova abstração e reescrever tudo abaixo dela, ou ainda, terei que duplicar o código pois não conseguirei satisfazer a herença.
É nesse ponto que os Traits aparecem. Diferentemente da herença (vertical), os Traits possibilitam-nos criar herenças horizontais.
Exemplo, dada a necessidade: haverão Funcionários, Supervisores, Gestores e Diretores no sistema e estes possui em comum o fato de receber salário. (capitalismo). Uma possibilidade seria:
Pessoa > Funcionario
Pessoa > Supervisores
Pessoa > Gestores
Pessoa > Diretores
Tudo perfeito. Porém, chega outra necessidade: Gestores e Diretores tem a capacidade de demitir. Gestores precisam gerenciar cronogramas, assim como os Supervisores fazem.
Pessoa.demitir(pessoa) não faz sentido, pois afetiria todos.
Gestor.demitir(pessoa) e Diretor.demitir(pessoa) atende, mas duplicaria o código.
Pessoa > Supervisor > Gestor
Pessoa > Diretor
Shi, apareceu outro nível hierarquico. Traits auxilia exatamente neste ponto ! Vejamos:
Trait Cronograma
Trait Evil (que contém recursos para demitir uma pessoa)
Pessoa > Supervisor : Cronograma
Pessoa > Gestor : Cronograma : Evil
Pessoa > Diretor : Evil
Note que o Pessoa > Supervisor : Cronograma – os dois pontos para indicar o Trait são de minha autoria – era o Pessoa > Supervisor antigo. Isso porque as atribuições para gerenciar cronogramas foram passadas para o Trait.
Neste pequeno exemplo, o Trait nos auxiliou com um problema de domínio. Acredito que ele também aplique-se e muito bem para problemas onde temos domínios transversais, pois, nele ficariam as atividades do outro domínio pode o domínio principal teria acesso aos recursos sem quebrar a SRP.
Traits em PHP
Como disse no começo, o futuro-provável PHP 5.4 virá com o Trait. Por enquanto essa implementação funcionaria:
definirPressao(self::$ATRASADO);
$this->youTube();
private function youTube() {
class Supervisor extends Pessoa {
use Cronograma;
$colaborador = new Funcionario();
$controlador = new Supervisor();
$controlador->cobrarDe($colaborador);
Os Traits possuem boas capacidades com métodos de instância e estáticos. Vamos explorar um pouco mais:
$view->sayWorld();
// exibe: Olá Mundo
Pegando informações da Classe
eu();
// exibe: Foo
Usando Variáveis de instância da classe:
hello} world";
private $hello = "Hello";
echo $hello->help();
// exibe: Hello world
Modificadores de acesso dos traits na classe
ola();
// Fatal Error....
Modificadores de acesso com alias para nome de método
aloha();
// Olá mundo
Há outros vários recursos como métodos abstratos nos Traits, precedência, métodos estáticos, late static bindings, métodos mágicos, alias para nome de método do Trait ao usá-lo na classe. Para Rubistas ou Scalistas (?) as possibilidades são as mesmas dos Mixins e Traits de Ruby e Scala respectivamente.