Memoizando en Ruby (o qué es ese "||=" que usamos tanto)
Es una de las magias 🧙♀️ más antiguas en el monolito de Fintual.
La idea es evitar calcular un valor que vamos a usar en una clase más de una vez, junto con encapsular cualquier lógica innecesaria para que a la siguiente desarrolladora le sea más fácil entender el contexto.
Para memoizar en Ruby es necesario usar el operador "lazy initialization" ||=
. Además, el nombre de la nueva variable debe tener el mismo nombre que el método que la va a encapsular.
def perform
return if find_user.blank?
register_user_deposit(find_user, @capital)
return unless deposit_status_service.verified_user?(find_user)
@distribution = Goal::DepositDistribution.for(find_user)
end
private
def find_user
Mx::MatchStatementLineToUser.for(line: @line, user_id: @user_id)
end
def perform
return if user.blank?
register_user_deposit(user, @capital)
return unless deposit_status_service.verified_user?(user)
@distribution = Goal::DepositDistribution.for(user)
end
private
def user
@user ||= Mx::MatchStatementLineToUser.for(line: @line, user_id: @user_id)
end
Esta estrategia es muy estándar. Si intentamos definir el método con nombre distinto al de la variable, RuboCop, nuestra gema de análisis de código estático para Ruby, se va a quejar.
def find_user
@user ||= Mx::MatchStatementLineToUser.for(line: @line, user_id: @user_id)
end
La mayor ventaja de esto es la evaluación lazy. La variable se va a inicializar la primera vez que se pida, se guarda y al siguiente llamado va a retornar inmediatamente el valor ya calculado.
Su gran desventaja es que, como todo método de caché, es susceptible a la invalidación de éste, por lo que hay que tener presente que el valor ya calculado no va a cambiar.