Protezione degli invarianti di classi

2

Ho un po 'di tempesta in una tazza da tè al lavoro, e sto cercando di capire se ho ragione, nel torto o forse un po' di entrambi.

Tutto è iniziato in modo abbastanza innocente; uno sviluppatore di un altro team stava commentando durante una revisione del codice del codice della mia squadra. Siamo un [relativamente] nuovo team e tendiamo a scrivere il nostro codice un po 'diverso dagli altri team: cerchiamo di seguire Clean Code, i principi SOLID, fare TDD, ecc. Il resto del codebase tende a più ... classica ... progettazione e implementazione aziendale con strati fissi, enormi interfacce / oggetti divini, modelli di dominio anemici e così via.

Lo stesso codebase è per un'applicazione di punta che elabora molte transazioni business-critical

Storicamente è stato costruito in fretta e solo negli ultimi mesi abbiamo avuto il tempo di provare a rimediare a molte delle scelte progettuali precedenti. Non sono un fan del modo in cui è stato fatto, ma sono disposto a fare dei compromessi dove devo.

Ad ogni modo il codice ha un aspetto simile a questo

public class Something
{
    readonly IFoo _foo;
    public Something(IFoo foo)
    {
        _foo = foo.ThrowIfNull("foo");
    }
}

( ThrowIfNull è un semplice metodo di estensione generico che racchiude il solito "if x == null throw new ArgumentNullException"). Personalmente non ne sono un fan ma agli altri piace così è bello.

Ora, ecco cosa è stato suggerito:

public class Something
{
    readonly IFoo _foo;
    public Something(IFoo foo)
    { 
      #if debug
        _foo = foo.ThrowIfNull("foo");
     #else
        _foo=foo;
    }
}

La logica è che questo potrebbe in qualche modo risparmiare un sovraccarico nel codice di produzione. Ho sottolineato che non era davvero qualcosa di cui preoccuparsi, e che per me è più importante (come in molti altri ordini di grandezza più importanti) che gli invarianti di classe (in questo caso, le sue dipendenze) siano protetti (cioè _foo non può essere null ) perché dobbiamo fallire velocemente se per qualche ragione qualcuno o qualcosa ha provato a costruire un Something con un% co_de nullo %.

Ma poi un architetto anziano intervenne per sostenere che era qualcosa di cui non dovremmo preoccuparci; questi sono più o meno gli argomenti, insieme alle mie confutazioni (tutte parafrasate ovviamente). Sono anche un architetto, ma appena coniato, quindi non ho ancora molto peso:)

  • Siamo strettamente accoppiati alla nostra libreria IOC e si prenderà cura di assicurarci che le dipendenze non siano nulle. Pertanto, questo codice verifica solo indirettamente la libreria IOC e dovrebbe essere eliminato Ciò presuppone che tutte le classi con dipendenze siano gestite dallo IOC, e anche se sono in pratica, credo che non sia il punto - non dovremmo associarci, punto.

  • Il codice che tenta di utilizzare _foo in seguito fallirà comunque Per me, è come giustificare saltare gli assegni pre-volo in aereo perché "hey, se le ali cadono a metà volo, beh allora lo sapremo, giusto?"

(Quest'ultima cosa mi ha reso molto spaventato)

  • Abbiamo tonnellate di classi che non lo fanno già, quindi non vogliamo davvero tornare indietro e interrompere i ( pochissimi ) test che avremo che falliranno quando passare null nella classe contstuctors ( come a volte facciamo ) Non ho davvero niente di buono da dire su questo - per quanto posso dire, se questo non è un approccio terribilmente sbagliato, allora penso che prenderò l'agricoltura per vivere. E 'stato a questo punto che ho deciso di smettere di prendere parte alla conversazione, ma devo sapere se sono pazzo o no:)

Quindi la domanda è questa.

Am I wrong, right or a little bit of both? I was always taught that protecting invariants is basic stuff, something that you just have to do, for the reasons I've listed in my rebuttals. Should I just drop this (not asking in terms of politics or career-wise, just if others feel as I do that's it's really something important and worth fighting for)

    
posta Stephen Byrne 21.09.2016 - 21:54
fonte

1 risposta

5

Sei decisamente nel giusto qui. Questa è una programmazione difensiva piuttosto elementare e non ci sono veri argomenti a sfavore.

Ora per gli argomenti:

L'accoppiamento con IoC e il problema del fail-fast è proprio come hai detto tu.

Per quanto riguarda il terzo argomento, solo perché questa classe ha un argomento null check non significa che devi tornare indietro e cambiare tutte le altre classi. Significa solo che questo pezzo di codice è più bello del resto.

E per quanto riguarda il "sovraccarico in produzione", è semplicemente sciocco. Quel costruttore sarà chiamato poche volte. L'inferno, anche se è stato chiamato milioni di volte durante la vita dell'applicazione, anche questo non giustificherebbe la complicazione del codice con il compilatore condizionale. E se davvero vogliono farlo in questo modo, sarebbe meglio creare due versioni del metodo ThrowIfNull . Si aprirà la modalità di debug e l'altra sarà vuota nella modalità di rilascio. Quindi, il compilatore lo ottimizzerà.

    
risposta data 21.09.2016 - 22:04
fonte

Leggi altre domande sui tag