Rimuovendo valori hard-coded e design difensivo vs YAGNI

9

Prima un po 'di background. Sto codificando una ricerca su Age - > Vota. Ci sono 7 classi di età, quindi la tabella di ricerca è di 3 colonne (Da | A | Tasso) con 7 righe. I valori cambiano raramente: sono tariffe legiferate (prima e terza colonna) che sono rimasti gli stessi per 3 anni. Ho capito che il modo più semplice per memorizzare questa tabella senza hard-coding è nel database in una tabella di configurazione globale, come un valore di testo singolo contenente un CSV (quindi "65,69,0.05,70,74,0.06" è come i livelli 65-69 e 70-74 verrebbero memorizzati). Relativamente facile da analizzare quindi utilizzare.

Poi mi sono reso conto che per implementarlo avrei dovuto creare una nuova tabella, un repository per aggirarlo, test del livello dati per il repository, test unitari attorno al codice che disattenta il CSV nella tabella e test intorno al ricerca stessa L'unico vantaggio di tutto questo lavoro è evitare l'hard-coding della tabella di ricerca.

Quando parli con gli utenti (che attualmente usano direttamente la tabella di ricerca - guardando una copia cartacea) l'opinione è che "i tassi non cambiano mai". Ovviamente non è corretto: le tariffe sono state create solo tre anni fa e in passato le cose che "non cambiano mai" hanno avuto l'abitudine di cambiare - quindi per me programmare questo in modo difensivo non devo assolutamente memorizzare la tabella di ricerca in l'applicazione.

Tranne quando penso YAGNI . La funzione che sto implementando non specifica che le tariffe cambieranno. Se le tariffe cambiano, cambieranno ancora così raramente che la manutenzione non è nemmeno una considerazione, e la funzionalità non è in realtà abbastanza critica da mettere in pericolo qualcosa se ci fosse un ritardo tra la modifica della velocità e l'applicazione aggiornata. / p>

Ho praticamente deciso che nulla di valore andrebbe perso se indurizzo la ricerca e non sono troppo preoccupato per il mio approccio a questa particolare funzionalità. La mia domanda è, come professionista, ho giustamente giustificato tale decisione? I valori di codifica hard sono un cattivo design, ma il problema di rimuovere i valori dall'applicazione sembra violare il principio YAGNI.

EDIT Per chiarire la domanda, non sono preoccupato per l'effettiva implementazione. Sono preoccupato di poter fare una cosa brutta e cattiva, e giustificarlo dicendo YAGNI, o posso adottare un approccio più difensivo e ad alto sforzo, che anche nel migliore dei casi ha dei bassi benefici. Come programmatore professionista, la mia decisione di implementare un design che conosco è imperfetta si riduce a un'analisi costi / benefici?

EDIT Mentre tutte le risposte erano molto interessanti perché penso che questo dipenda dalle scelte progettuali di un individuo, penso che le risposte migliori siano state @ Corbin's e @ EZ Hart's che presenta cose che non avevo considerato nella domanda:

  • la falsa dicotomia di "rimozione corretta dei valori codificati" spostandola nel database rispetto a "applicare in modo efficiente YAGNI" utilizzando l'hard-coding. C'era una terza possibilità di mettere la tabella di ricerca nella configurazione dell'app, che non comporta il sovraccarico del modo corretto e senza l'efficienza di YAGNI. Generalmente non siamo limitati a nessuna delle due / o decisioni, e quindi si riduce a una decisione in termini di costi / benefici.
  • La generazione di codice
  • può ridurre il sovraccarico di spostamento dei valori codificati nel database e in un modo che rimuove anche la mia decisione eccessivamente ingegnerizzata di elaborare un CSV nella tabella. Potenzialmente questo aggiunge anche un problema di manutenzione a lungo termine con il codice generato se i requisiti di base cambiano per il metodo di ricerca. Tutto ciò influisce solo sull'analisi costi / benefici, ed è probabile che se avessi avuto quell'automazione a disposizione non avrei nemmeno preso in considerazione l'hard-coding qualcosa del genere.

Sto marcando la risposta di @ Corbin come corretta perché cambia le mie ipotesi sui costi di sviluppo, e probabilmente aggiungerò alcuni strumenti di generazione del codice al mio arsenale nel prossimo futuro.

    
posta Ben Scott 09.03.2011 - 14:19
fonte

9 risposte

6

Hai trovato un difetto nel tuo processo di sviluppo. Quando è un dolore fare la cosa giusta (creare la tabella, i repo, i test repo, i test flatten ...), gli sviluppatori troveranno un modo per aggirarlo. Questo di solito implica fare la cosa sbagliata. In questo caso, si sta tentando di trattare i dati dell'applicazione come logica dell'applicazione. Non farlo Invece, aggiungi automazioni utili al tuo processo di sviluppo. Usiamo CodeSmith per generare il codice noioso, boilerplate che nessuno vuole scrivere. Dopo aver creato una tabella, eseguiamo CodeSmith e genera DAO, DTO e stub per test di unità per ciascuno.

A seconda delle tecnologie che stai utilizzando, dovresti avere opzioni simili. Molti strumenti ORM genereranno modelli da uno schema esistente. Le migrazioni dei binari funzionano nella direzione opposta: le tabelle dei modelli. La meta-programmazione nei linguaggi dinamici è particolarmente strong nell'eliminare il codice di stam- pa. Dovrai lavorare un po 'più difficile per generare tutto ciò di cui hai bisogno se hai un'applicazione complessa a più livelli, ma ne vale la pena. Non lasciare che la sensazione, "wow, questo è un dolore al collo" ti impedisce di fare la cosa giusta.

Oh, e non memorizzare i tuoi dati in un formato che richiede un'ulteriore elaborazione (CSV). Questo aggiunge solo ulteriori passaggi che richiedono attenzione e test.

    
risposta data 09.03.2011 - 17:31
fonte
10

Per estrapolare ed estendere @ Thorbjørn Ravn Andersen's answer: Mantenere il calcolo / ricerca in un posto è un buon inizio.

Il tuo processo di pensiero di difensivo contro YAGNI è un problema comune. In questo caso, suggerirei di essere informato da altre due cose.

In primo luogo - come è stata presentata la richiesta dell'utente? Hanno specificato la modificabilità delle tariffe? In caso contrario, la parte di complessità aggiunta di qualcosa che è possibile fatturare o meno? (o se sei in staff, che puoi passare il tuo tempo a fare altro lavoro?) Se è così, allora sicuramente andare avanti e fornire ciò che è stato ragionevolmente chiesto.

In secondo luogo, e forse ancora più importante, è improbabile che la semplice modificabilità soddisfi un requisito reale di fronte a una modifica legislativa. Se e quando cambieranno le tariffe, è probabile che ci sia una data di scadenza e un po 'di elaborazione precedente e successiva che deve avvenire. Inoltre, se la stessa interfaccia deve quindi eseguire qualsiasi tipo di elaborazione dei reclami retroattivi, potrebbe essere necessario cercare la tariffa corretta in base alla data effettiva della voce, anziché alla data effettiva.

In breve, sto notando che un requisito modificabile effettivo potrebbe essere piuttosto complesso, quindi a meno che o fino a quando non sia completato, il semplice è probabilmente migliore.

Good Luck

    
risposta data 09.03.2011 - 14:49
fonte
7

Rendi la ricerca effettiva una funzione di libreria. Puoi quindi vedere tutto il codice che usa quella ricerca nel tuo repository sorgente, in modo da sapere quali programmi devono essere aggiornati quando cambiano le tariffe.

    
risposta data 09.03.2011 - 14:23
fonte
2

Fammi vedere se ho risposto correttamente alla tua domanda. Hai 2 opzioni per implementare una funzione: o hai hardcode un valore e la tua funzione è facile da implementare (non ti piace la parte hardcode) o hai un grande sforzo per "rifare" un sacco di cose che sono fatte quindi sei in grado di sviluppare funzionalità in modo pulito. È corretto?

La prima cosa che mi viene in mente è "La cosa più importante nel conoscere le buone pratiche è sapere quando stai meglio senza di loro".

In questo caso, lo sforzo è molto alto in modo da poterlo fare in modo pulito, le probabilità di effetto collaterale di questo cambiamento sono grandi e il rendimento che otterresti è piccolo (come hai spiegato, sembra probabile che sia non cambierà).

Vorrei utilizzare l'approccio basato su hardcode (ma prepararlo per essere flessibile in futuro) e, in caso di modifica di questo tasso in futuro, utilizzare l'opportunità di rifattorizzare tutta questa sezione di progettazione errata del codice. Quindi il tempo e il costo potrebbero essere stimati correttamente e il costo di modifica del valore di hardcoded sarebbe minimo.

Questo sarebbe il mio approccio:)

    
risposta data 09.03.2011 - 14:41
fonte
2

Questo è un oggetto che "non cambierà" finché non lo fa. È inevitabile che cambierà, ma quel tempo potrebbe essere un po 'lontano.

La tua giustificazione è corretta. In questo momento, il cliente non ha chiesto la possibilità di modificare facilmente tali tariffe. In quanto tale, YAGNI.

Tuttavia, ciò che non vuoi è il codice che accede alle tue tariffe e interpreta i risultati sparsi nella base di codice. Un buon design OO ti consente di incapsulare la rappresentazione interna delle tue tariffe in una classe e di esporre solo uno o due metodi necessari per utilizzare i dati.

Avrai bisogno di tale incapsulamento per prevenire errori di copia e incolla o dover eseguire un refactoring su tutto il codice che utilizza le tariffe quando è necessario apportare una modifica alla rappresentazione interna. Quando prendi questa precauzione iniziale, l'approccio più complicato può essere un semplice scambio e sostituirlo con la versione più dettagliata.

Inoltre, richiama la limitazione del design attuale al client. Di 'loro che nell'interesse di mantenere il programma hai codificato i valori in modo rigido, il che richiede una modifica del codice per aggiornarli. In questo modo, quando vengono a conoscenza delle variazioni dei tassi in sospeso a causa della nuova legislazione, possono scegliere di aggiornare semplicemente la tabella di ricerca o eseguire il cambiamento più complicato in quel momento. Ma metti quella decisione sulle ginocchia.

    
risposta data 09.03.2011 - 14:59
fonte
2

Dividere la differenza e inserire i dati di velocità in un'impostazione di configurazione. Puoi utilizzare il formato CSV che hai già ottenuto, evitare l'inutile sovraccarico del database e, se la modifica è necessaria, sarà una modifica che il cliente dovrebbe essere in grado di fare senza dover ricompilare / reinstallare e senza problemi nel database - possono semplicemente modificare il file di configurazione.

Di solito quando si osserva una scelta tra due estremi (violare YAGNI rispetto a dati dinamici hard-coding), la risposta migliore è da qualche parte nel mezzo. Attenti alle false dicotomie.

Ciò presuppone che tutta la configurazione sia nei file; se è difficile da trovare nel registro, dovresti probabilmente ignorare questo consiglio:)

    
risposta data 09.03.2011 - 16:00
fonte
2

I figured that the easiest way to store this table without hard-coding it is in the database in a global configuration table, as a single text value containing a CSV (so "65,69,0.05,70,74,0.06" is how the 65-69 and 70-74 tiers would be stored.

Ho appena creato una tabella DB. (Tu dove pensi di riporre un intero tavolo in un solo archivio, sei impazzito?)

La tabella ha bisogno di 2 campi NOT 3. Età e tasso. Questa riga successiva contiene il valore superiore! Stai de-normalizzando senza nemmeno saperlo!

Ecco lo Sql per ottenere la tariffa per qualcuno di età che ha 67 anni.

Select * from RateTable where Age in (Select max(age) from RateTable where age <=67) 

Non preoccuparti di creare una schermata di manutenzione poiché è fuori portata. Se lo chiedono più tardi, invia una richiesta di modifica e fallo.

EDIT: Come altri hanno detto di mantenere il codice, la frequenza viene centralizzata, nel caso in cui l'intera struttura Rate Structure .

    
risposta data 09.03.2011 - 14:59
fonte
1

Sono d'accordo con la maggior parte delle risposte fornite. Vorrei anche aggiungere che la coerenza con il resto dell'applicazione è importante. Se questo è il posto solo nel codice che ha valori hardcoded probabilmente sorprenderà i maintainer. Questo è particolarmente vero se si tratta di una base di codice ampia e stabile. Se si tratta di un piccolo programma gestito da te, la decisione è meno importante.

Ho un lontano ricordo della lettura di un noto ragazzo agile / OOP (come Dave Thomas o Kent Beck o qualcuno) che dice che la loro regola empirica per la duplicazione del codice era due volte e solo due volte: non refactoring la prima volta duplicare qualcosa poiché potresti sempre scriverlo solo due volte nella tua vita. Ma la terza volta ...

Questo non risolve esattamente la domanda, dal momento che stai mettendo in discussione YAGNI, ma penso che parli della flessibilità generale delle regole agili. Il punto di agilità è adattarsi alla situazione e andare avanti.

    
risposta data 10.03.2011 - 01:36
fonte
0

Codice duro in una funzione.

  • Quando i valori cambiano, puoi fatturare nuovamente il cliente
  • Quando i valori cambiano, è probabile che il formato della tabella cambierà, facendo CSV perderà tempo
  • Più facile da implementare, maggiori possibilità di essere sul budget con il contratto corrente
  • Può trovare facilmente quando dovrà essere aggiornato
risposta data 09.03.2011 - 17:44
fonte

Leggi altre domande sui tag