/me
William Correa
@wilcorrea
Primeira coisa que a gente pensa sobre quando falam de código limpo
Clean Architecture
Robert C. Martin
Uncle Bob
SOLID
Clean Arch
Clean Code
Onion model
Bereshit bará Elohim et hashamaim veét haárets
toda história tem um começo
STRUCTURED PROGRAMMING
OBJECT-ORIENTED PROGRAMMING
FUNCTIONAL PROGRAMMING
CONCLUSÃO
Os paradigmas nos dizem o que não fazer, mais do que eles nos dizem o que fazer
SOLID
1980
Início do debate dos princípios
com outros engenheiros de software.
2000
Depois de adicionar, mesclar e remover princípios, aqui foi estabilizado só que numa ordem aleatória.
2004
Michael Feathers ajudou a organizar os princípios como é apresentado hoje em dia.
SINGLE RESPONSIBILITY PRINCIPLE
class Customer:
def __init__(self, name: str):
self.name = name
def get_name(self) -> str:
pass
def save(self, customer: Customer):
pass
Muita Responsa
class Customer:
def __init__(self, name: str):
self.name = name
def get_name(self) -> str:
pass
Stonks
class CustomerModel:
def save(self, customer: Customer):
pass
OPEN-CLOSED PRINCIPLE
class Discount:
def __init__(self, customer, price):
self.customer = customer
self.price = price
def give_discount(self):
if self.customer == 'fav':
return self.price * 0.2
if self.customer == 'vip':
return self.price * 0.4
Se mudar já era
class Discount:
def __init__(self, customer, price):
self.customer = customer
self.price = price
def get_discount(self):
return self.price * 0.2
Stonks
class VIPDiscount(Discount):
def get_discount(self):
return super().get_discount() * 2
LISKOV SUBSTITUTION PRINCIPLE
class Order:
def __init__(self, output: Output, amount):
self.output = output
self.amount = amount
def save(self):
self.output.export()
Jogo é jogo
class Output:
def save(self):
return self
class PDF (Output):
def save(self):
return self
def export(self):
return self
class Printer (Output):
def save(self):
return self
Stonks
class Order:
def __init__(self, output: Output, amount):
self.output = output
self.amount = amount
def save(self):
self.output.export()
class Output:
def save(self):
return self
def export(self):
return self
class PDF (Output):
def save(self):
return self
def export(self):
return self
class Printer (Output):
def save(self):
return self
INTERFACE SEGREGATION PRINCIPLE
class Order:
def __init__(self, output: Output, amount):
self.output = output
self.amount = amount
def save(self):
self.output.export()
Cada um no seu quadrado
class Output:
def save(self):
return self
class PDF (Output):
def save(self):
return self
def export(self):
return self
class Printer (Output):
def save(self):
return self
class Order:
def __init__(self, output: OutputExporter, amount):
self.output = output
self.amount = amount
def save(self):
self.output.export()
Stonks
class Output:
def save(self):
return self
class PDF (OutputExporter):
def save(self):
return self
def export(self):
return self
class Printer (Output):
def save(self):
return self
class OutputExporter (Output):
def save(self):
return self
def export(self):
return self
DEPENDENCY INVERSION PRINCIPLE
class Order:
def __init__(self):
return self
def save(self, amount):
customer = new Customer()
customer.sync(amount)
return self
Escondido é mais gostoso
class Order:
def __init__(self):
return self
def save(self, customer: Customer, amount):
customer.sync(amount)
return self
Stonks
THE CLEAN ARCHITECTURE
E o MVC?
E a Web?
E o que mais?
- Hexagonal Architecture (Alistair Cockburn)
- DCI (James Coplien and Trygve Reenskaug )
- BCE (Ivar Jacobson)
- Domain Driven Design (Eric Evans)
CAMADAS e + CAMADAS
Tá, e cumé que é isso?!
O DESENHO
-
Fácil de testar ou pelo menos testável
-
Regras de negócio manuteníveis
-
Independência de agentes externos
-
Melhoria de percepção na leitura
AS VANTAGENS
REGRAS DE NEGÓCIO
from rentomatic.response_objects import response_objects as res
class RoomListUseCase(object):
def __init__(self, repo):
self.repo = repo
def execute(self, request_object):
if not request_object:
return res.ResponseFailure.build_from_invalid_request_object(
request_object)
try:
rooms = self.repo.list(filters=request_object.filters)
return res.ResponseSuccess(rooms)
except Exception as exc:
return res.ResponseFailure.build_system_error(
"{}: {}".format(exc.__class__.__name__, "{}".format(exc)))
ORGANIZAR INTERESSES
from typing import Optional, List
from pydantic import BaseModel
class Room(BaseModel):
...
class RoomFilter(BaseModel):
code: Optional[str] = None
...
class RoomStorage:
def get_rooms(self, filters: RoomFilter) -> List[Room]: ...
class RoomListUseCase:
def __init__(self, repo: RoomStorage):
self.repo = repo
def show_rooms(self, filters: RoomFilter) -> List[Room]:
rooms = self.repo.get_rooms(filters=filters)
return rooms
REFERÊNCIA
O DESENHO
Componentes
<template>
<Appform>
<AppInput
name="name"
width="6"
v-model="record.name"
:error="error.name"
/>
<AppInput
name="email"
width="6"
v-model="record.email"
:error="error.email"
/>
<AppTextarea
name="description"
width="6"
v-model="record.description"
:error="error.description"
/>
</AppForm>
</template>
<script>
...
</script>
<template>
<div
class="form-group"
:class="[`col-sm-${width}`]"
>
<label>{{ label }}</label>
<input
class="form-control"
:value="value"
@input="$emit('input', ...)"
/>
</div>
</template>
<script>
export default {
name: 'AppInput',
props: {
value: {
default: () => (undefined)
},
...
}
...
}
</script>
Componentes
Componentes
REFERÊNCIA
ARQUITETURA LIMPA
+
TESTES
<template>
<div class="PontoVendaComandaConsumacao">
<PontoVendaComandaBarra
:comanda="comanda"
@fechar="confirmarConsumo"
/>
<template v-if="status === 'C'">
<PontoVendaComandaAbertura
:comanda="comanda"
@fechar="fechar"
@abrir="abrir"
/>
</template>
<template v-else>
<div class="flex row">
<div class="col-sm-8 col-md-9">
<template v-if="status === 'P'">
<PontoVendaComandaConta />
</template>
<template v-else-if="status === 'A'">
<PontoVendaComandaCardapio
ref="cardapio"
:categorias="categorias"
@selecionado="selecionarProduto"
/>
</template>
</div>
....
</template>
</div>
</template>
<QItemSection avatar>
<template v-if="complemento.qtdemax === 1">
<!-- radio: { qtdemax === 1 } -->
<QRadio
v-model="selecao[complemento.id]"
:val="item.id"
@input="atualizarValorComplemento(complemento.id)"
/>
</template>
<!-- numeric: { qtdemax > 1 } -->
<template v-else>
<div class="flex">
<QBtn
icon="remove"
:disable="naoPodeDecrementar(complemento, item)"
@click="decrementar(complemento, item)"
/>
<div class="PontoVendaComandaComplemento__valor q-pa-sm">
{{ $util.get(selecao, `${complemento.id}.${item.id}`) }}
<!-- force update -->
<input
type="hidden"
:value="placebo"
>
</div>
<QBtn
icon="add"
disable="naoPodeIncrementar(complemento)"
@click="incrementar(complemento, item)"
/>
</div>
</template>
</QItemSection>
hora das palmas
Clean Architecture
By William Correa
Clean Architecture
- 686