Indo além do ActiveModel

Mantendo a simplicidade em seus projetos

Uma das coisas que mais gosto no Ruby on Rails é a simplicidade. Com ele é possível escrever e manter bons códigos. Uma prática muito comum em aplicações Ruby on Rails é extrair regras de negócio para Plain Old Ruby Object ou (POROs). Ex:

Fotografia de Jupiter

👉🏻 Fiz essa foto com meu celular durante minhas férias em Viçosa-CE.

class PersonForm
  attr_accessor :age, :name, :birthday, :favorit_color

  def initialize(params = {})
    @age = params[:age]
    @name = params[:name]
    @birthday = params[:birthday]
    @favorit_color = params[:favorit_color]
  end

  def call!
    # Do some cool stuff
  end
end

person = PersonForm.new(age: "92", name: "Buzz Aldrin", birthday: "20-01-1930")

person.age
# => "92"

person.birthday
# => "20-01-2930"

person.favorit_color
# => nil

Com isso, já seria possível isolar coisas como: validações personalizadas; definir atributos padrões; normalizar parâmetros e etc.

Agora, perceba que o atributo age e birthday retornam strings. Uma forma de melhorar isso seria fazer algo como:

require 'date'

class PersonForm
  attr_accessor :age, :name, :birthday, :favorit_color

  def initialize(params = {})
    @age = params[:age].to_i
    @name = params[:name]
    @birthday = Date.parse(params[:birthday])
    @favorit_color = params[:favorit_color]&.strip || 'red'
  end

  def call!
    # Do some cool stuff
  end
end

person = PersonForm.new(age: '92', name: ' Buzz Aldrin ', birthday: '20-01-1930')

person.age
# => 92

person.birthday
# => <Date: 1930-01-20 ((2425997j,0s,0n),+0s,2299161j)>

person.favorit_color
# => "red"

Muito bom! Agora, se você estiver usando Rails, pode ficar ainda melhor.

ActiveModel::Attributes

Se você usa Ruby on Rails, então você usa o AvtiveModel::Attributes a todo momento. Isso, porque toda vez que você usa o ActiveRecord ele, internamente, faz uso do módulo Attributes para fazer cast de dados como Date, Float, DateTime.

Um exemplo do outro código seria algo como:

class PersonForm
  include ActiveModel::Model
  include ActiveModel::Attributes

  validates :name, presence: true

  attribute :age, :integer
  attribute :name, :string
  attribute :birthday, :date, default: -> { Date.new }
  attribute :favorit_color, :string, default: 'red'

  def call!
    # Do some cool stuff
  end
end

person = PersonForm.new(age: '92', name: 'Buzz Aldrin', birthday: '20-01-1930')

person.age
# => 92

person.birthday
# => <Date: 1930-01-20 ((2425997j,0s,0n),+0s,2299161j)>

person.favorit_color
# => "red"

person = PersonForm.new(age: '92', name: nil, birthday: '20-01-1930')

person.valid?
# => false

person.errors.full_messages
# => ["Name can't be blank"]

Como disse antes, simples e elegante.

A cereja do bolo 🍒

Eu diria que, uma tendência, principalmente em desenvolvedores com poucas horas de voo, é cair na armadilha de criar abstrações muito prematuramente, e isso não é nenhum segredo. Há, só pra lemnbrar o ActiveModel::Attributes não é algo "novo".

  • Cuidados com Gemas(libs) externas

    Tem um framework no meu framework

    Amarrar toda sua codebase em bibliotecas externas também é algo perigoso. O Ruby on Rails já entrega uma gama extraordinária de implementações de alto nível e mantido por desenvolvedores muito bons/experientes.

  • Evite soluções ouver enginer

    Fique atento para não criar uma sobrecarga desnecessária e transformar algo simples em algo complexo.

    Overengineering (ou over-engineering),[1] é o ato de projetar um produto ou fornecer uma solução para um problema de maneira elaborada ou complicada, onde uma solução mais simples pode ser demonstrada com a mesma eficiência e eficácia que a de o projeto original.[2]

  • Faça funcionar primeiro

    Foque no simples, faça funcionar primeiro. Algo importante, e que é necessário ficar atento, é que não há problemas em, inicialmente, manter duplicicidade de código. Lembre-se de que abstrações prematuras, ou mal elaboradas, podem acabar se transformando em armadilhas.

Conclusão

Muito possivelmente, você não precisará iniciar seus projetos em estrutura de micro-serviços e muito provavelmente não precisa adicionar mais frameworks ao seu framework. Se você estiver desenvolvendo algo procure sempre se inteirar do todo, aqui falo do negócio em si, não se prenda somente ao código. Para pequenos projetos com um chat simples, para no máximo uma dúzia de pessoas, certamente você não precisará usar o Erlang logo de cara. O mesmo vale para as implementações. Pense simples.

Referências

Comentários