Power Types
Power Types es una gema desarrollada por Platanus que promueve el uso de estos poderosos patrones: Services, Commands, Utils y Values.
Estos se basan en el SRP (Single Responsability Principe), que nos dice que cada clase debe tener 1 sola función. Por ejemplo, si tenemos un modelo con operaciones complejas como este:
1
class User
2
def upgrade_membership
3
# ...
4
end
5
6
def notify_external_system
7
# ...
8
end
9
10
def register_payment_card
11
# ...
12
end
13
end
Copied!
Deberíamos llevar cada una de sus funciones a Commands o Services independientes:
1
class UpgradeMembership < Command
2
# ...
3
end
4
5
class ExternalNotifierService < Service
6
# ...
7
end
8
9
class RegisterPaymentCard < Command
10
# ...
11
end
Copied!
Estructurando nuestro código de forma modular y desacoplada tenemos las siguientes ventajas:
  • Menos riesgo: Aislar errores, no pisar variables
  • Más claridad, que hace cada clase
  • DRYness
  • Unit Testing de cada funcionalidad

Patrones

Services - app/services

Los Servicios son clases Ruby que exponen métodos públicos para llevar a cabo tareas relacionadas a un contexto en común. Pueden ser generados con la ayuda del siguiente comando
1
$ rails generate service SomeNameService source
Copied!
Esto generará una clase cuyo nombre termina, por convención en ..Service
1
class SomeNameService < PowerTypes::Service.new(:source)
2
def do_something_now
3
end
4
5
def do_something_later
6
end
7
end
Copied!
Luego pueden ser utilizados fácilmente instanciando la clase y llamando a sus métodos
1
service = SomeNameService.new(source: data)
2
result = service.do_something_now
Copied!

Commands - app/commands

Los Comandos son clases destinadas a realizar operaciones acotadas e independientes. Se implementan a través de un método perform que recibe argumentos y realiza operaciones con ellos entregando un resultado. También poseen un generador para construir su estructura,
1
$ rails generate command DoSomething foo
Copied!
Esto generará una clase que implementa el método perform
1
class DoSomething < PowerTypes::Command.new(:foo, :bar)
2
def perform(args)
3
end
4
end
Copied!
Luego pueden ser llamados y ejecutados de la siguiente forma,
1
result = DoSomething.for(foo: waffle, bar: pancake)
Copied!
Donde :foo, :bar son los argumentos. Están disponibles en el comando como variables de instancia @foo, @bar

Utils - app/utils

Las utils son módulos Ruby que nos permiten agrupar funciones y procedimientos simples e independientes
1
module MagicTricks
2
extend self
3
4
def dissappear(object)
5
#blah blah
6
end
7
8
def shrink(children)
9
#bleh bleeh
10
end
11
12
def shuffle(cards)
13
#blaah
14
end
15
end
Copied!
Luego los métodos podrán ser llamados de la siguiente forma
1
MagicTricks.dissapear(rabbit)
2
3
# Or
4
5
include MagicTricks
6
7
dissapear(rabbit)
Copied!

Values - app/values

Los values corresponden a clases Ruby que pueden ser utilizadas para contener información que no persiste en la base de datos, y por lo tanto solo existe en memoria. Entonces si por ejemplo, generamos dinámicamente un reporte, en vez de retornarlo como Hash:
1
class BuildCleaningReport < PowerTypes::Command.new(:data)
2
def perform
3
# execute report logic, and finally return:
4
{
5
date: @date,
6
area: cleaned_area,
7
duration: cleaning.time,
8
effiency: cleaned_area / cleaning.time
9
}
10
end
11
end
Copied!
Mejor encapsular el resultado en una clase Report:
1
# app/values/report.rb
2
class Report
3
attr_accesor :date, :area, :duration
4
5
def eficciency
6
area / duration
7
end
8
end
Copied!
Estos objetos pueden ser utilizados para mover la información de forma estructurada dentro de las distintas capas de la aplicación.

Referencias

Para mayor información sobre esta gema, visita los siguientes vínculos
Última actualización 1mo ago