Quando leggo il codice con molti metodi molto brevi, scopro che spesso ci vuole più tempo di quanto dovrebbe per capire come tutto combaci. Alcune delle ragioni sono illustrate bene nel codice di esempio.Proviamo romperlo in metodi molto piccoli:
def cart
if user_signed_in?
process_current_user
else
setup_cart
end
end
private
def process_current_user
@user = current_user
if @user.cart.present?
assign_cart_when_user_present
else
assign_cart_when_user_not_present
end
end
def assign_cart_when_user_present
@cart = @user.cart
end
def assign_cart_when_user_not_present
@cart = false
end
def setup_cart
cart_id = session[:cart_id]
if cart_id.present?
assign_cart_when_id_present
else
assign_cart_when_id_present
end
end
def assign_cart_when_id_present
@cart = Cart.find(cart_id.to_i)
end
def assign_cart_when_id_not_present
@cart = false
end
Destra fuori del blocco ci sono un paio di grossi problemi:
- Dopo aver letto il metodo
cart
Non ho idea di che cosa lo fa. Ciò è in parte dovuto al fatto che i valori vengono assegnati alle variabili di istanza anziché restituire valori al metodo che ha chiamato cart
.
- Vorrei i nomi dei metodi
process_current_user
e setup_cart
per dire al lettore cosa fanno. Quei nomi non lo fanno. Probabilmente potrebbero essere migliorati, ma erano i migliori che potessi inventare. Il punto è che non è sempre possibile escogitare nomi di metodi informativi.
Vorrei rendere privati tutti i metodi diversi da cart
. Questo introduce un altro problema. Metto insieme tutti i metodi privati alla fine - nel qual caso potrei dover scorrere diversi metodi non collegati per trovarli - o alternare metodi pubblici e privati attraverso tutto il codice? (Naturalmente, questo problema può essere alleviato un po 'mantenendo i file di codice piccoli e usando i mixin, assumendo che io possa ricordare quale file di codice fa cosa.)
Considera anche cosa è successo al numero di righe di codice. Con più linee di codice ci sono più opportunità di errori. (Ho intenzionalmente commesso un errore comune per illustrare questo punto: l'hai notato?) Potrebbe essere più semplice testare i singoli metodi, ma ora dobbiamo verificare che i molti metodi separati funzionino correttamente insieme.
Ora confrontiamo che per il metodo di tweaked solo un po ':
def cart
if user_signed_in?
@user = current_user
@cart = case @user.cart.present?
when true then @user.cart
else false
end
else
cart_id = session[:cart_id]
@cart = case cart_id.present?
when true then Cart.find(cart_id.to_i)
else false
end
end
end
Questo dice al lettore a colpo d'occhio quello che sta accadendo:
@user
è impostato su current_user
se l'utente è firmato in; e
@cart
viene assegnato a un valore che dipende dal fatto che l'utente sia connesso e, in ciascun caso, sia presente un ID.
Non credo che testare un metodo di queste dimensioni sia più difficile che testare la mia precedente suddivisione del codice in metodi più piccoli. In effetti, potrebbe essere più facile garantire che i test siano completi.
Potremmo anche tornare cart
anziché assegnare ad una variabile di istanza, ed evitare di assegnare un valore ad @user
se è solo necessario determinare cart
se l'utente ha eseguito l'accesso:
def cart
if user_signed_in?
cart = current_user.cart
case cart.present?
when true then cart
else false
end
else
cart_id = session[:cart_id]
case cart_id.present?
when true then Cart.find(cart_id.to_i)
else false
end
end
end
Purtroppo, questo è stato messo in attesa come basata-opinione. Ma sicuramente non lo è. I metodi più brevi sono sempre migliori. I concreti motivi pratici sono forniti qui: https://www.cqse.eu/en/blog/the-real-benefits-of-short-methods/ –