Coding best practices
Una nota sul linguaggio utilizzato:
- “Non fare X” significa che non esiste motivo valido per violare la regola.
- “Evita X” significa non farlo a meno di un valido motivo.
- “Prediligi X ad Y” descrive una pratica sconsigliata, ed una alternativa da favorire a meno di un valido motivo.
Linee guida ad alto livello
- Sii coerente.
- Non riscrivere codice già esistente per seguire questa guida.
- Non violare le linee guida senza un valido motivo. Se riesci a convincere un altro membro del tuo team, allora il motivo può considerarsi valido.
Generali
- Non duplicare funzionalità già presenti in librerie di sistema.
- Non fallire silenziosamente ingoiando eccezioni. →
- Non scrivere codice cercando di predire future necessità. →
- Evita di usare eccezioni per gestire control flow ordinario. →
- Mantieni il codice semplice, chiaro ed esplicito. →
- Evita di ottimizzare il codice. Non farlo mai senza profiling. →
Principi di object-oriented design
- Evita variabili globali e singletons. →
- Evita un numero di parametri superiore a 4. →
- Limita il numero di collaboratori di un oggetto (le entità da cui dipende l'oggetto).
- Limita il numero di dipendenze di un oggetto (le entitità che dipendono dall'oggetto).
- Prediligi la composizione rispetto all'ereditarietà. →
- Prediligi metodi brevi. Ottimo rimanere tra 1 e 5 righe. →
- Prediligi piccoli oggetti, con una singola responsabilità ben definita. Quando un oggetto supera le 100 righe, è probabile stia facendo troppe cose. →
- Tell, don’t ask. →
- Evita metodi che uniscono responsabilità query e command. →
Ruby
- Evita parametri opzionali. Il metodo forse sta facendo più del dovuto?
- Evita inutile metaprogramming.
- Evita il monkey-patching.
- Prediligi la creazione di classi all'inclusione di moduli per condividere funzionalità tra più oggetti.
- Prediligi lo scope
private
aprotected
. Usaprotected
solo per i metodi di comparazione comedef ==(other)
,def <(other)
, edef >(other)
. - Effettua
rescue
diStandardError
, nonException
. → - Configurazione Rubocop →
Rails
- Evita di bypassare le validazioni con metodi quali
save(validate: false)
o <code>update_attribute. → - Non modificare una migrazione dopo che è stata mergiata su master se il cambiamento voluto può essere introdotto con una seconda migrazione.
- Non richiamare le classi dei modelli
ActiveRecord
all'interno dalle viste. - Non usare variabili d'istanza nei partials.
- Non usare SQL o frammenti SQL (
where('inviter_id IS NOT NULL')
) al di fuori dei modelli. - Valida la presenza dell'associazione
belongs_to
(<code>user), non della foreign key (user_id
). - Aggiungi un indice DB per ogni foreign key. →
- Imposta valori di default, validazioni di presenza o unicità nei modelli anche a livello di migrazione DB.
- Mantieni
db/schema.rb
sotto version control. - Non fare riferimento a modelli
ActiveRecord
a livello di migrazione. - Nelle viste mailer usa named routes con suffissi
_url
. In tutti gli altri casi, usa il suffisso <code>_path. → - Evita di instanziare più di un oggetto per azione nei controller.
- Sfrutta solo una variabile di istanza per vista.
- Assicurati che le migrazioni down funzionino. →
- Evita l'introduzione di nuovi metodi helper. Prediligi un'approccio ad oggetti tramite l'uso di presenters. →
- A livello di model
ActiveRecord
specifica unicamente validazioni, relazioni e scopes/query. - Non specificare a livello model
ActiveRecord
validazioni che necessitino il lookup di relazioni.
Testing
- Mantieni un code coverage superiore al 90%.
- Evita test ridondanti (uno e un solo test per funzionalità).
- Evita
its
, <code>let!,specify
e <code>subject in RSpec. Prediligi approcci espliciti e coerenti. - Specifica una sola expectation per test.
- Separa le fasi di setup ed exercise dalla fase verify del test tramite blocchi
before
. - Evita
.any_instance
, sfrutta il dependency injection. → - Evita l'utilizzo di variabili di istanza.
- Disabilita richieste HTTP verso servizi esterni tramite WebMock o FakeWeb.
Unit testing
- Non testare i metodi privati (non stubbare il SUT). →
- Testa metodi di tipo query con expectations sul valore di ritorno.
- Testa metodi di tipo command con expectations su diretti cambiamenti di stato provocati sull'interfaccia pubblica dell'oggetto.
- Non testare chiamate di tipo query verso oggetti collaboratori.
- Testa chiamate di tipo command verso oggetti collaboratori tramite stubs e spies (non mocks). →
- Mantieni gli stub in sync con l'API che vanno a simulare. Nel farlo prediligi approcci unit rispetto a test di integrazione. →
Gemfile
- Dichiara la versione ruby da utilizzare per un progetto. →
- Specifica la versione con
~>
per le gemme che seguono il semantic versioning (<code>rspec,factory_girl
, <code>capybara). → - Specifica la versione esatta per gemme fragili (
rails
). - Non specificare una versione per gemme stabili e sicure (
pg
, <code>thin).
Background Jobs
- Non persistere oggetti
ActiveRecord
serializzati nel job. Passa gli ID ed esegui la.find
all'interno del metodo.perform
.