/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

  • 669