Kilderson Sena
Cearense arretado e amante da programação. Full Stack Dev, Pai do Kauan Lucas, viciado em café, futebol e Rock'n Roll
Por: Kilderson Sena
REFLEXÕES
Partes das regras de negócio na View ou no controller? Impedindo assim reuso e potencializando duplicação de código?
Regras de negócio estavam diretamente "casadas" com o banco de dados? Dificultando criação de testes?
É arriscado ou seguro substituir uma biblioteca de sua aplicação sem ter que mexer em milhares de linhas de código?
(Por exemplo do moment.js)
Você já se deparou com as situações abaixo:
Dificuldade na evolução do produto
Aplicação fica engessada e com código rígido.
Se você passa ou já passou por isso, tá na hora de virar esse jogo!
"(...) minimizar os recursos humanos necessários para construir e manter um determinado sistema."
Robert C. Martin
"(...) são decisões que ao mesmo tempo são importantes e difíceis de mudar."
Martin Fowler
"(...) é sobre coisas importantes seja lá elas quais forem.."
Ralph Johnson (Gang of Four)
É uma estratégia arquitetural orientado ao desacoplamento entre as regras de negócio da aplicação, recursos externos como frameworks e bancos de dados.
Separação da aplicação em
camadas lógicas
CAMADAS !== PASTAS
As camadas são LÓGICAS, camadas NÃO SÃO pastas!
"(...) o centro da sua aplicação não é o banco de dados. Não é ele e nem um ou mais frameworks que você pode estar usando. O centro da sua aplicação são os use cases."
Robert C. Martin
"(...) devem definir como as coisas são organizadas, como elas se relacionam e que responsabilidades elas devem ter."
Rodrigo Branas
🤓 Sênior Full Stack Developer
👨🎓 Graduado em Análise e Desenv. Sistemas
🤘 Movido a café e Rockn'roll
👨💻 Programador há mais de 14 anos
👨👩👦 Esposo da Dayanny Pai do Kauan Lucas
fb.com/kilderson.sena
@derson_sena
@derson_sena
dersonsena
youtube.com/yiiacademybr
@yiiacademy
yiiacademy.com.br
yiiacademy.com.br/8-motivos-para-usar-o-yii-2
devtube.com.br/ebook-oo1.html
Vinícius Dias
(PHP Rio)
Junior Grossi
(PHP MG)
Willian Correa
(PHP BR)
Marcel dos Santos
(PHP SP)
Rodrigo Branas
(branas.io)
Erandir Jr.
(PHP com Rapadura)
Minha opinião
DTO • Adapter • SRP • DIP • DDD
São objetos que servem para transferir dados de uma camada para outra.
DTO • Adapter • SRP • DIP • DDD
Eu costumo por os dados primitivos, que não critique nada e seja imutável.
Objetivo dele é: receber os dados e levar para o(s) interessado(s).
DTO • Adapter • SRP • DIP • DDD
São usados mais na "borda" da arquitetura para fazer a entrada de dados de forma desacoplada.
DTO • Adapter • SRP • DIP • DDD
class CreateOrderInputData {
constructor(
private orderId: string,
private clientId: number
){}
getOrderId() {
return this.orderId
}
getClientId() {
return this.clientId
}
}
DTO • Adapter • SRP • DIP • DDD
É um padrão de projeto estrutural que permite objetos com interfaces incompatíveis colaborarem entre si.
DTO • Adapter • SRP • DIP • DDD
DTO • Adapter • SRP • DIP • DDD
(Classe de Negócio)
SalePayment
(API PagSeguro)
DTO • Adapter • SRP • DIP • DDD
// Business Class
class SalePayment {
constructor() {
//... connection stuff
}
async execute() {
// some business logic and validations...
const payload = await this.http.post('http://pagseguro...', {
paymentMode: "default",
paymentMethod: "creditCard",
currency: "BRL",
itemDescription1: "Notebook Prata",
itemAmount1: 10300.00
})
// .. do something
}
}
DTO • Adapter • SRP • DIP • DDD
(Classe de Negócio)
SalePayment
(Classe de Persistência)
PagseguroApi
(API PagSeguro)
DTO • Adapter • SRP • DIP • DDD
type TransactionData = {
paymentMode: string,
paymentMethod: string,
currency: string,
itemDescription1: string,
itemAmount1: number
}
class PagseguroApi {
// ... connection stuff
makeTransaction(data: TransactionData) {
this.http.post(this.url, data)
}
}
DTO • Adapter • SRP • DIP • DDD
// Business Class
class SalePayment {
constructor(
private pagseguroApi: PagseguroApi
) {}
execute() {
// some logic and validations...
this.pagseguroApi.makeTransaction({
paymentMode: "default",
paymentMethod: "creditCard",
currency: "BRL",
itemDescription1: "Notebook Prata",
itemAmount1: 10300.00
})
}
}
DTO • Adapter • SRP • DIP • DDD
(Classe de Negócio)
SalePayment
(Classe de Persistência)
PagseguroApi
(API PagSeguro)
(Interface)
PaymentGateway
DTO • Adapter • SRP • DIP • DDD
type Transaction = {
paymentMethod: string,
currency: string,
items: object[]
}
type TransactionOutput = {
id: string,
createdAt: Date
}
interface PaymentGateway {
makeTransaction(transaction: Transaction): Promise<TransactionOutput>
}
DTO • Adapter • SRP • DIP • DDD
type TransactionData = {
paymentMode: string,
paymentMethod: string,
currency: string,
itemDescription1: string,
itemAmount1: number,
// others fields...
}
class PagseguroApi implements PaymentGateway {
// ... connection stuff
makeTransaction(transaction: Transaction): Promise<TransactionOutput> {
this.http.post(this.url, this.mapTransactionToData(transaction))
}
private mapTransactionToData(transaction: Transaction): TransactionData {
// ... translate `Transaction` to `TransactionData`
}
}
DTO • Adapter • SRP • DIP • DDD
// Business Class
class SalePayment {
constructor(
private paymentGateway: PaymentGateway
) {}
execute() {
// some logic and validations...
this.paymentGateway.makeTransaction({
paymentMethod: "creditCard",
currency: "BRL",
items: [
{...}, {...}, {...}
]
})
}
}
DTO • Adapter • SRP • DIP • DDD
(Classe de Negócio)
SalePayment
(Classe de Persistência)
PagseguroApi
(API PagSeguro)
(Interface)
PaymentGateway
(Classe de Persistência)
GetNetApi
(API GetNet)
(API Cielo)
(Classe de Persistência)
CieloApi
DTO • Adapter • SRP • DIP • DDD
"De todos os princípios, a SRP provavelmente é o menos compreendido.
Em geral, os programadores imaginam que todos os módulos devem fazer apenas uma coisa."
Fonte: Livro Clean Architecture
Robert C. Martin
DTO • Adapter • SRP • DIP • DDD
Fonte: Livro Clean Architecture
Robert C. Martin
"Historicamente, o SRP tem sido descrito como:
Um módulo deve ter uma, e apenas uma, razão para mudar."
(Um módulo deve ser responsável por um, e apenas um, ator.)
DTO • Adapter • SRP • DIP • DDD
A idéia é que você não marrete tudo numa única classe, criando uma classe Deus
Mas como definir responsabilidade?
DTO • Adapter • SRP • DIP • DDD
Como muitas coisas na Engenharia de Software: DEPENDE!!!
É algo muito subjetivo e torna muito difícil dá uma definição concreta
DTO • Adapter • SRP • DIP • DDD
Mas existem alguns "indicadores" como tamanho de classes, tamanho de métodos que vai te dar um norte.
(Object Calisthenics)
DTO • Adapter • SRP • DIP • DDD
Fonte: Livro Clean Architecture
Robert C. Martin
"Os sistemas mais flexíveis são aqueles em que as dependências de código-fonte se referem apenas a abstrações e não a itens concretos."
DTO • Adapter • SRP • DIP • DDD
Fonte: Livro Clean Architecture
Robert C. Martin
"É impraticável tratar essa ideia como uma regra, pois os sistemas de software dependem de muitas facilidades concretas."
DTO • Adapter • SRP • DIP • DDD
Fonte: Livro Clean Architecture
Robert C. Martin
"Por exemplo, a classe String no Java , DOMDocument e Array Object do PHP são concretas e não seria prático forçá-la a ser abstrata"
DTO • Adapter • SRP • DIP • DDD
(Classe de Negócio)
SalePayment
(Classe de Persistência)
PagseguroApi
(API PagSeguro)
(Classe de Negócio)
SalePayment
(Classe de Persistência)
PagseguroApi
(API PagSeguro)
(Interface)
PaymentGateway
DTO • Adapter • SRP • DIP • DDD
DTO • Adapter • SRP • DIP • DDD
É uma abordagem focada na comunicação com especialistas do negócio
(Domain Experts)
DTO • Adapter • SRP • DIP • DDD
"Uma coisa é entender a Essência do Negócio e outra coisa é codar esta mesma essência de forma adequada"
Rodrigo Branas
DTO • Adapter • SRP • DIP • DDD
"Domain Model: é o entendimento a respeito do domínio. Há um passado não tão distante onde muitas pessoas associavam Modelagem de domínio com criar um D.E.R. e ligar diretamente com estrutura de tabelas de um banco de dados relacional, e não é isso."
Rodrigo Branas
DTO • Adapter • SRP • DIP • DDD
Modelar domínio é sobre a linguagem ubíqua
DTO • Adapter • SRP • DIP • DDD
~> São artefatos que possuem identidade e estado, podendo ser construídas por outras Entidades ou Value Objects (Objetos de Valor).
~> O estado desses artefatos podem e vão mudar de acordo com seu ciclo de vida
Entities (Entidades)
DTO • Adapter • SRP • DIP • DDD
Entities (Entidades) Exemplos:
DTO • Adapter • SRP • DIP • DDD
enum PaymentStatus {
OPENED,
PAID,
CANCELED
}
class Payment {
private status: PaymentStatus
private code: string
constructor(
private amount: number,
private dueDate: Date
) {
if (amount <= 0) {
throw new Error('Amount must be greater than zero')
}
this.status = PaymentStatus.OPENED
this.code = 'aa-bb-cc'
}
pay () {
this.status = PaymentStatus.PAID
}
}
DTO • Adapter • SRP • DIP • DDD
Entidades não tem absolutamente NADA a ver com mapeamento de um ORM.
Entities (Entidades)
DTO • Adapter • SRP • DIP • DDD
Esse termo foi "patenteado" pelos ORM's, mas lá nada mais é do que um Mapper ou um espelho de uma classe para uma tabela do banco de dados.
Entities (Entidades)
DTO • Adapter • SRP • DIP • DDD
Geralmente são objetos auto validaveis e imutáveis porque a sua identidade está no seu valor, ou seja, se por caso eu mudar o valor de um V.O. eu estou mudando ela inteira.
Value Objects (Objetos de Valor)
DTO • Adapter • SRP • DIP • DDD
Geralmente são usados para compor as Entities, por exemplo:
Value Objects (Objetos de Valor)
DTO • Adapter • SRP • DIP • DDD
enum PaymentStatus {
OPENED,
PAID,
CANCELED
}
class Payment {
private status: PaymentStatus
private code: Code
constructor(
private amount: number,
private dueDate: Date
) {
if (amount <= 0) {
throw new Error('Amount must be greater than zero')
}
this.status = PaymentStatus.OPENED
this.code = new Code('aa-bb-cc')
}
pay () {
this.status = PaymentStatus.PAID
}
}
class Code {
private code: string
construct(code: string) {
if (code.length < 3 && code.length > 10) {
throw new Error('Invalid Payment Code')
}
this.code = code
}
value(): string {
return this.code
}
toString(): string {
return this.value()
}
}
DTO • Adapter • SRP • DIP • DDD
Aggregates (Agregados)
De forma resumida é um conjunto de Entidades que colaboram entre si podendo até ser tratados como uma unidade.
Formam um contexto transacional.
DTO • Adapter • SRP • DIP • DDD
Aggregates (Agregados)
Se nós tempos um Pedido, muito provavelmente teremos um Item do Pedido, Desconto, Frete e etc, porém a Raiz do Agregado (Aggregate Root) é o Pedido.
(Entidade)
Pedido
(Entidade)
ItemPedido
(Entidade)
Desconto
(Entidade)
Frete
DTO • Adapter • SRP • DIP • DDD
Aggregates (Agregados)
A tendência natural é que quando essa entidade for abastecida lá no repositório eu estarei lidando com Agregados, ou seja, com o "Lider da Tribo"
(Aggregate Root)
Pedido
(Entidade)
ItemPedido
(Entidade)
Desconto
(Entidade)
Frete
DTO • Adapter • SRP • DIP • DDD
Repositories (Repositórios)
É uma abstração de persistência de dados. Nesse ponto não sabemos como ou onde isso vai ser persistido, você só estará dizendo que haverá uma persistência
DTO • Adapter • SRP • DIP • DDD
Repositories (Repositórios)
O objetivo dessa abstração é desacoplar o seu domínio da sua camada de infraestrutura.
DTO • Adapter • SRP • DIP • DDD
Application Services
São objetos que vão executar operações que não estão na entidade.
DTO • Adapter • SRP • DIP • DDD
Application Service
Também chamadas de use case, aqui você terá um objeto que irá fazer a famosa "Dança das entidades" para algum fim, por exemplo: fazer matrícula, efetuar login, cancelar venda e etc;
DTO • Adapter • SRP • DIP • DDD
Anti-Corruption Layer (ACL)
ACL na Clean Architecture é o papel feito pela camada Interface Adapters, onde teremos adaptadores ou tradutores de uma camada para outra.
(Classe de Negócio)
SalePayment
(Classe de Persistência)
PagseguroApi
(API PagSeguro)
(Interface)
PaymentGateway
Fonte: Livro Clean Architecture
Robert C. Martin
Fonte: Livro Clean Architecture
Robert C. Martin
São regras corporativas que valem independente da aplicação em que ela esteja.
Supondo que estamos num domínio de vendas e temos cálculos de multa e juros. Se eu for calcular isso numa ação de venda, de NF, de estoque a regra continuaria a mesma. A aplicação muda mas a regra de juros e multa não muda.
~> Não deve saber quem o está utilizando, se está consumindo JSON, XML, CSV, Texto puro
~> Não sabe que formato de dados será retornado, só retorna um DTO de Saída (Output Data) quando requerido
~> Lançam Exceções de Negócio
~> Fazem a "tradução" entre o mundo externo e as regras de negócio
~> Convertem dados para mecanismos de I/O
~> Análogo a ACL do DDD
~> Essa é a camada mais Low Level;
~> São frameworks e outras estruturas externas que fazem o I/O com aplicação;
Entities + Use Cases
Interface Adapters
Framewors and Drivers
Main Layer
Deck: para criar um deck é preciso ter: capacidade, cards, dono e possibilidade de mostrar a média de elixir com 1 casa decimal.
Card: um card representa um personagem com os atributos: nome, nível (nível máx: 13) e elixir (nível máx: 9)
Player: todo deck pertence a um player com os atributos: nome, qtd. troféus e o clã que ele pertence
Deck Player 01
Deck Player 02
Player 01
Player 02
Caso de Uso Batalha
fb.com/kilderson.sena
@derson_sena
@derson_sena
dersonsena
By Kilderson Sena
Cearense arretado e amante da programação. Full Stack Dev, Pai do Kauan Lucas, viciado em café, futebol e Rock'n Roll