Cos'è veramente il "Soft Coding"?


87

In questo articolo di Alex Papadimoulis, puoi vedere questo frammento:

private void attachSupplementalDocuments()
{
  if (stateCode == "AZ" || stateCode == "TX") {

    //SR008-04X/I are always required in these states
    attachDocument("SR008-04X");
    attachDocument("SR008-04XI");
  }

  if (ledgerAmnt >= 500000) {
    //Ledger of 500K or more requires AUTHLDG-1A
    attachDocument("AUTHLDG-1A");
  }

  if (coInsuredCount >= 5  && orgStatusCode != "CORP") {
    //Non-CORP orgs with 5 or more co-ins require AUTHCNS-1A
    attachDocument("AUTHCNS-1A");
  }
}

Davvero non capisco questo articolo.

Quoto:

Se ogni costante delle regole di business fosse memorizzata in un file di configurazione, la vita sarebbe molto [più ( sic )] difficile per tutti coloro che gestiscono il software: ci sarebbero molti file di codice che condividessero uno, un file grande (o, il contrario, molti piccoli file di configurazione); l'implementazione delle modifiche alle regole aziendali non richiede un nuovo codice, ma modifica manuale dei file di configurazione; e il debug è molto più difficile.

Questo è un argomento contro la presenza del numero intero costante "500000" in un file di configurazione, o "AUTHCNS-1A" e altre costanti di stringa.

Come può essere una cattiva pratica?

In questo frammento, "500000" non è un numero. Ad esempio, non è lo stesso di:

int doubleMe(int a) { return a * 2;}

dove 2, è un numero che non deve essere sottratto. Il suo uso è ovvio e non rappresenta qualcosa che può essere riutilizzato in seguito.

Al contrario, "500000" non è semplicemente un numero. È un valore significativo, che rappresenta l'idea di un punto di interruzione nella funzionalità. Questo numero può essere utilizzato in più di un posto, ma non è il numero che stai utilizzando; è l'idea del limite / limite, al di sotto della quale si applica una regola e al di sopra della quale si applica un'altra.

In che modo fare riferimento ad esso da un file di configurazione, o persino da #define, consto qualunque sia la tua lingua, è peggio che includerne il valore? Se in seguito il programma, o qualche altro programmatore, richiede anche quel limite, in modo che il software faccia un'altra scelta, sei fregato (perché quando cambia, nulla ti garantisce che cambierà in entrambi i file). Questo è chiaramente peggio per il debug.

Inoltre, se domani il governo richiede "Dal 3/5/250, è necessario aggiungere AUTHLDG-122B invece di AUTHLDG-1A", questa costante di stringa non è una costante di stringa semplice. È uno che rappresenta un'idea; è solo il valore corrente di quell'idea (che è "la cosa che aggiungi se il libro mastro è superiore a 500k").

Vorrei chiarire. Non sto dicendo che l'articolo sia sbagliato; Semplicemente non capisco; forse non è troppo ben spiegato (almeno per il mio pensiero).

Capisco che sostituire ogni possibile valore letterale o numerico di stringa con una variabile costante, di definizione o di configurazione, non solo non è necessario, ma complica troppo le cose, ma questo particolare esempio non sembra rientrare in questa categoria. Come fai a sapere che non ti servirà più tardi? O qualcun altro per quella materia?


21
Gioca al puzzle: quale sarebbe un buon nome per quei numeri? Penso che scoprirai che o il nome non aggiunge alcun valore, o descrive tutto ciò che il codice sta già descrivendo e spesso aggiungendo ambiguità ("LedgerLimitForAuthDlg1A"?). Ho trovato l'articolo brillante proprio per quanto sia rilevante. Ho gestito sistemi che hanno utilizzato entrambi gli approcci e posso dirti che le regole di business appartengono al codice, il che li rende molto più facili da tracciare, mantenere e comprendere. Quando usi la configurazione, è meglio farla contare: è molto più costosa.
Luaan,

2
La configurazione dovrebbe essere riservata alle cose che devono essere configurate. Se le regole aziendali non sono configurabili in generale, inserirne alcune parti nella configurazione non ti consente di acquistare nulla.
biziclop,

Per linguaggi adeguatamente avanzati, la configurazione assume la forma di subroutine effettive e non di stringhe.
Thorbjørn Ravn Andersen,

Risposte:


100

L'autore mette in guardia contro l'astrazione prematura.

La linea if (ledgerAmt > 500000)assomiglia al tipo di regola aziendale che ti aspetteresti di vedere per grandi sistemi aziendali complessi i cui requisiti sono incredibilmente complessi ma precisi e ben documentati.

In genere questi tipi di requisiti sono casi eccezionali / limite piuttosto che logiche riutilizzabili. Tali requisiti sono in genere di proprietà e gestiti da analisti aziendali ed esperti in materia, piuttosto che da ingegneri

(Si noti che la "proprietà" dei requisiti da parte di analisti / esperti in questi casi si verifica in genere laddove gli sviluppatori che lavorano in campi specialistici non dispongono di competenze di dominio sufficienti, anche se mi aspetterei comunque che la piena comunicazione / cooperazione tra gli sviluppatori e gli esperti di dominio protegga da requisiti ambigui o scritti male.)

Quando si mantengono sistemi i cui requisiti sono pieni di casi limite e logica altamente complessa, di solito non c'è modo di astrarre utilmente quella logica o renderla più mantenibile; i tentativi di provare a costruire astrazioni possono facilmente ritorcersi contro, non solo con conseguente perdita di tempo, ma anche con meno codice gestibile.

In che modo fare riferimento ad esso da un file di configurazione, o anche da una #define, const o qualunque cosa la tua lingua fornisca, peggio che includerne il valore? Se in seguito il programma, o qualche altro programmatore, richiede anche quel limite, in modo che il software faccia un'altra scelta, sei fregato (perché quando cambia, nulla ti garantisce che cambierà in entrambi i file). Questo è chiaramente peggio per il debug.

Questo tipo di codice tende a essere protetto dal fatto che il codice stesso probabilmente ha una mappatura uno-a-uno ai requisiti; vale a dire quando uno sviluppatore sa che la 500000figura appare due volte nei requisiti, tale sviluppatore sa anche che appare due volte nel codice.

Considerare l'altro (altrettanto probabile) scenario in cui 500000appare in più punti nel documento dei requisiti, ma gli esperti in materia decidono di cambiarne solo uno; lì hai un rischio ancora peggiore che qualcuno che modifica il constvalore potrebbe non rendersi conto che 500000viene utilizzato per significare cose diverse - quindi lo sviluppatore lo cambia in quello e solo lo trova nel codice e finisce per rompere qualcosa che loro non avevo capito che erano cambiati.

Questo scenario si verifica molto nel software legale / finanziario su misura (ad es. Logica di preventivo assicurativo) - le persone che scrivono tali documenti non sono ingegneri e non hanno problemi a copiare + incollare interi pezzi delle specifiche, modificando alcune parole / numeri, ma lasciando la maggior parte lo stesso.

In questi scenari, il modo migliore per gestire i requisiti di copia-incolla è scrivere il codice di copia-incolla e rendere il codice il più simile possibile ai requisiti (incluso l'hard-coding di tutti i dati).

La realtà di tali requisiti è che di solito non rimangono a lungo copia + incolla e i valori a volte cambiano su base regolare, ma spesso non cambiano in tandem, quindi cercando di razionalizzare o astrarre quei requisiti o semplificarli in ogni caso finiscono per creare più mal di testa di manutenzione che semplicemente tradurre i requisiti testualmente in codice.


28
Un linguaggio specifico di dominio (DSL) può essere un buon modo per rendere il codice più simile al documento dei requisiti.
Ian

13
Un altro vantaggio di una DSL è che rende anche più difficile mescolare accidentalmente la logica di applicazione, presentazione o persistenza con le regole aziendali.
Erik Eidt,

16
Pensare che la tua applicazione sia abbastanza speciale da giustificare il proprio DSL è di solito arroganza.
brian_o,

8
Those requirements are typically owned and maintained by business analysts and subject matter experts, rather than by engineersche non è sempre una buona idea. A volte l'atto di trasformare tali requisiti in codice rivelerà casi angolari in cui i requisiti non sono ben definiti o sono definiti in modo tale da andare contro l'interesse commerciale. Se gli analisti aziendali e gli sviluppatori possono cooperare per raggiungere un obiettivo comune, è possibile evitare molti problemi.
Kasperd,

4
@BenCottrell Non stavo suggerendo di cambiare le regole per rendere più semplice la scrittura del software. Ma quando hai un sacco di condizionali nelle regole è del tutto possibile che alcune interazioni tra quelle siano state mancate durante la definizione delle regole in primo luogo. Ma quando si trasforma la specifica in codice, lo sviluppatore è tenuto a notare che esiste una possibile interazione tra tali condizioni. A questo punto è possibile che lo sviluppatore ritenga che un'interpretazione rigorosa delle specifiche porti a un prezzo involontario che consentirebbe ai clienti di giocare con il sistema.
Kasperd,

44

L'articolo ha un buon punto. Come può essere una cattiva pratica estrarre costanti in un file di configurazione? Può essere una cattiva pratica se complica inutilmente il codice. Avere un valore direttamente nel codice è molto più semplice che doverlo leggere da un file di configurazione e il codice scritto è facile da seguire.

Inoltre, domani, il governo recita "Dal 03/05/250, è necessario aggiungere AUTHLDG-122B invece di AUTHLDG-1A".

Sì, allora cambi il codice. Il punto dell'articolo è che non è più complicato cambiare il codice che cambiare un file di configurazione.

L'approccio descritto nell'articolo non si ridimensiona se si ottiene una logica più complessa, ma il punto è che è necessario effettuare un giudizio, e talvolta la soluzione più semplice è semplicemente la migliore.

Come fai a sapere che non ti servirà più tardi? O qualcun altro per quella materia?

Questo è il punto del principio YAGNI. Non progettare per un futuro sconosciuto che può risultare completamente diverso, progettare per il presente. Hai ragione nel dire che se il valore 500000 viene utilizzato in più posizioni nel programma, ovviamente dovrebbe essere estratto in una costante. Ma questo non è il caso nel codice in questione.

Il softcoding è davvero una questione di separazione delle preoccupazioni . Le informazioni sul softcode che conosci potrebbero cambiare indipendentemente dalla logica dell'applicazione principale. Non codificheresti mai una stringa di connessione a un database, perché sai che potrebbe cambiare indipendentemente dalla logica dell'applicazione e dovrai differenziarla per ambienti diversi. In un'app Web ci piace separare la logica aziendale dai modelli html e dai fogli di stile, perché potrebbero cambiare in modo indipendente e persino essere modificati da persone diverse.

Ma nel caso dell'esempio di codice, le stringhe e i numeri codificati sono parte integrante della logica dell'applicazione. È concepibile che un file possa cambiare il suo nome a causa di un cambiamento di politica al di fuori del tuo controllo, ma è altrettanto ipotizzabile che sia necessario aggiungere un nuovo if-branch per verificare una condizione diversa. In questo caso, l'estrazione di nomi e numeri di file interrompe effettivamente la coesione.


4
Spesso è molto più complicato cambiare il codice di un file di configurazione. Potrebbe essere necessario uno sviluppatore e un sistema di generazione / ciclo di rilascio per il primo, mentre il secondo richiede solo la modifica di un numero in una casella in un'interfaccia utente di configurazione intuitiva.
OrangeDog

6
@OrangeDog Sì, è così che sembra inizialmente. Ma se fai cose del genere, l'interfaccia utente della configurazione sarà tutt'altro che amichevole, con centinaia di caselle di testo totalmente prive di significato che ti chiedono chi sa cosa. E ora devi creare l'interfaccia utente e documentarla. Intendiamoci, ciò non significa che la configurazione non sia mai una buona strada da percorrere - ci sono casi in cui è assolutamente la scelta giusta. Ma non in nessuno degli esempi nell'articolo. E quando è stata l'ultima volta che una legislazione ha cambiato solo il numero? L'ultima volta che le regole IVA sono cambiate qui, abbiamo dovuto rifare tutti i calcoli comunque.
Luaan,

2
@OrangeDog: in questo caso stai assumendo che la configurazione del software ti fornisca i ganci necessari per il controllo che devi effettuare. Nota come nell'OP ogni singolo ifsi basa su una variabile diversa! Se la variabile richiesta non è accessibile dalla configurazione, è comunque necessario modificare il software.
Matthieu M.

2
@OrangeDog quindi stai suggerendo che dovrebbero esserci cambiamenti significativi alla logica di un'applicazione software, senza un ciclo dev / qa / release e test appropriati?
NPSF3000,

3
@OrangeDog: OK, usi YAML per configurare la logica nell'esempio. Poiché la logica include regole condizionali, trovi un modo per rappresentare questi condizionali in YAML. Congratulazioni, hai reinventato Python. Perché non scrivere l'intera app in Python allora?
JacquesB,

26

L'articolo continua parlando dell '"Enterprise Rule Engine", che probabilmente è un esempio migliore di ciò su cui sta litigando.

La logica è che puoi generalizzare al punto in cui la tua configurazione diventa così complicata da contenere un suo linguaggio di programmazione.

Ad esempio, il codice di stato per documentare la mappatura nell'esempio potrebbe essere spostato in un file di configurazione. Ma dovresti quindi esprimere una relazione complessa.

<statecode id="AZ">
    <document id="SR008-04X"/>
    <document id="SR008-04XI"/>
</statecode>

Magari inseriresti anche l'importo del libro mastro?

<statecode id="ALL">
    <document id="AUTHLDG-1A" rule="ledgerAmt >= 50000"/>
</statecode>

Presto scoprirai che stai programmando in una nuova lingua che hai inventato e salvando quel codice in file di configurazione che non hanno controllo di origine o modifica.

Va notato che questo articolo è del 2007 quando questo genere di cose era un approccio comune.

Oggi probabilmente risolveremmo il problema con l' iniezione di dipendenza (DI). Cioè, avresti un 'hard coded'

InvoiceRules_America2007 : InvoiceRules

che sostituiresti con un hard coded o più configurabile

InvoiceRules_America2008 : InvoiceRules

quando sono cambiati i requisiti di legge o aziendali.


4
Forse dovresti definire "DI". E forse spiegare un po 'di più.
Basil Bourque,

9
Perché quel file non dovrebbe trovarsi nel sistema di controllo del codice sorgente?
JDługosz,

2
Se è specifico per il client, la versione codificata ha un enorme casino di ifistruzioni per fornire valori diversi per ciascun client? Sembra qualcosa che dovrebbe essere in un file di configurazione. Essere in un tipo di file o in un altro, a parità di tutti gli altri, non è un motivo per non controllare / tracciare / eseguire il backup del file. Sembra che @ewan stia dicendo che il file di un DSL non può essere salvato come parte del progetto per qualche motivo, quando certamente lo sono anche risorse non in codice come immagini, file audio e documentazione .
JDługosz,

2
Dovresti davvero rielaborare il valore "50000" dal tuo XML e inserirlo in un file di configurazione separato, non credi? ... e dovrebbe essere 500000, comunque.
Wildcard il

1
@jdlugosz il concetto di un ERE è che si acquista il sistema e lo si configura per le proprie esigenze. forse perché gli sviluppatori interni erano in competizione con questi sistemi "flessibili" avrebbero cercato di emularli. cambiare il controllo della configurazione, anche nei sistemi di grandi aziende come IBM era spesso un ripensamento. Il punto di forza è stato il cambio rapido
Ewan il

17

Al contrario, "500000" non è semplicemente un numero. È un valore significativo, che rappresenta l'idea di un punto di interruzione nella funzionalità. Questo numero può essere utilizzato in più di un posto, ma non è il numero che stai utilizzando, è l'idea del limite / limite, al di sotto della quale si applica una regola e al di sopra della quale ne esiste un'altra.

E questo si esprime avendo (e potrei sostenere che anche il commento è ridondante):

 if (ledgerAmnt >= 500000) {
    //Ledger of 500K or more requires AUTHLDG-1A
    attachDocument("AUTHLDG-1A");
  }

Questo è solo ripetere ciò che sta facendo il codice:

LEDGER_AMOUNT_REQUIRING_AUTHLDG1A=500000
if (ledgerAmnt >= LEDGER_AMOUNT_REQUIRING_AUTHLDG1A) {
    //Ledger of 500K or more requires AUTHLDG-1A
    attachDocument("AUTHLDG-1A");
}

Si noti che l'autore assume che il significato di 500000 sia legato a questa regola; non è un valore che è o è probabile che venga riutilizzato altrove:

L'unica modifica della regola aziendale che questa precedente codifica software potrebbe mai giustificare è una modifica dell'importo del libro mastro che ha richiesto un modulo AUTHLDG-1A. Qualsiasi altra modifica delle regole aziendali richiederebbe ancora più lavoro: configurazione, documentazione, codice, ecc

Il punto principale dell'articolo, a mio avviso, è che a volte un numero è solo un numero: non ha alcun significato aggiuntivo se non quello che viene trasmesso nel codice e non è probabile che venga utilizzato altrove. Pertanto, riassumendo goffamente ciò che il codice sta facendo (ora) in un nome di variabile solo per evitare valori codificati è al massimo una ripetizione inutile.


2
Se avessi introdotto la costante LEDGER_AMOUNT_REQUIRING_AUTHLDG1A, non avresti più scritto il commento nel codice. I commenti non sono mantenuti bene dai programmatori. Se l'importo fosse mai cambiato, la ifcondizione e il commento sarebbero fuori sincrono. Al contrario, la costante LEDGER_AMOUNT_REQUIRING_AUTHLDG1Anon si sincronizza mai con se stessa e spiega il suo scopo senza il commento inutile.
ZeroOne,

2
@ZeroOne: Tranne il fatto che se la regola aziendale cambia in "Libro mastro di 500K o più richiede AUTHLDG-1A e AUTHLDG-2B", è molto probabile che la persona che aggiunge la attachDocument("AUTHLDG-2B");riga non riesca ad aggiornare il nome costante contemporaneamente. In questo caso, penso che il codice sia abbastanza chiaro senza un commento una variabile esplicativa. (Anche se potrebbe avere senso avere una convenzione per indicare la sezione appropriata del documento sui requisiti aziendali tramite commenti sul codice. In base a tale convenzione, un commento sul codice che fa ciò sarebbe appropriato qui.)
ruakh

@ruakh, OK, quindi rifarrei la costante da chiamare LEDGER_AMOUNT_REQUIRING_ADDITIONAL_DOCUMENTS(cosa che probabilmente avrei dovuto fare in primo luogo). Ho anche l'abitudine di inserire gli ID dei requisiti aziendali nei messaggi di commit di Git, non nel codice sorgente.
ZeroOne,

1
@ZeroOne: Ma per AUTHLDG-3C l'importo del libro mastro è in realtà un massimo . E per AUTHLDG-4D l'importo del libro mastro appropriato dipende dallo stato. (Hai ancora capito il punto? Per questo tipo di codice, vuoi che il tuo codice rifletta le regole aziendali, non un tentativo di astrazione delle regole aziendali, perché non c'è motivo di aspettarsi che l'evoluzione delle regole aziendali si allinei con astrazioni che hai adottato.)
ruakh

2
Personalmente, non mi oppongo a mettere il numero magico nel codice, mi oppongo alla strutturazione del codice, quindi ha bisogno di questi commenti. Se fossi in me, trasformerei ogni documento in un'istanza enum con il suo attachIfNecessary()metodo e li ripasserei tutti.
David Moles,

8

Le altre risposte sono corrette e ponderate. Ma ecco la mia breve e dolce risposta.

  Rule/value          |      At Runtime, rule/value…
  appears in code:    |   …Is fixed          …Changes
----------------------|------------------------------------
                      |                 |
  Once                |   Hard-code     |   Externalize
                      |                 |   (soft-code)
                      |                 |
                      |------------------------------------
                      |                 |
  More than once      |   Soft-code     |   Externalize
                      |   (internal)    |   (soft-code)
                      |                 |
                      |------------------------------------

Se le regole e i valori speciali compaiono in un punto del codice e non cambiano durante il runtime, allora hard-code come mostrato nella domanda.

Se le regole o i valori speciali compaiono in più di una posizione nel codice e non cambiano durante il runtime, allora il soft-code. Il soft-coding per una regola potrebbe definire un metodo / classe specifico o utilizzare il modello Builder . Per i valori, il soft-coding può significare la definizione di una singola costante o enum per il valore da utilizzare nel codice.

Se le regole o i valori speciali possono cambiare durante il runtime, è necessario esternalizzarli. Viene comunemente eseguito aggiornando i valori in un database. Oppure aggiorna manualmente i valori in memoria da parte di un utente che inserisce i dati. Viene inoltre eseguito memorizzando i valori in un file di testo (XML, JSON, testo normale, qualunque cosa) che viene ripetutamente sottoposto a scansione per la modifica della data e dell'ora di modifica del file.


1
Mi piace la tua risposta, ma penso che dovresti anche considerare se cambia durante l'implementazione. Ciò è rilevante soprattutto se si tratta di un prodotto che verrà utilizzato in molte organizzazioni che potrebbero, ad esempio, avere regole diverse sul fatto che un supervisore debba approvare un rimborso su X, ecc. Ecc.
Bloke Down The Pub

Concordato sia con questa risposta che con il commento sull'attuazione. Le cose su cui lavoro sono implementate da molte organizzazioni e molte di esse hanno valori sottilmente diversi. Tendiamo a memorizzare queste 'impostazioni' in un database piuttosto che in un file di configurazione, ma il principio è che non vogliamo creare build diverse del nostro software per ogni azienda che lo implementa (quindi ripetere quelle build diverse ogni volta che si aggiornano) .
RosieC,

7

Questa è la trappola in cui cadiamo quando usiamo un problema giocattolo e quindi poniamo solo soluzioni di paglia , quando stiamo cercando di illustrare un problema reale.

Nell'esempio fornito, non fa differenza se i valori indicati sono codificati come valori in linea o definiti come cons.

È il codice circostante che renderebbe l'esempio un horror di manutenzione e codifica. Se non esiste un codice circostante, lo snippet va bene, almeno in un ambiente di refactoring costante. In un ambiente in cui il refactoring tende a non verificarsi, i manutentori di quel codice sono già morti, per ragioni che presto diventeranno ovvie.

Vedi, se c'è del codice che lo circonda, allora accadono chiaramente cose cattive.

La prima cosa negativa è che il valore 50000 viene utilizzato per un altro valore da qualche parte, diciamo, l'importo del libro mastro su cui cambia l'aliquota fiscale in alcuni stati ... quindi quando si verifica un cambiamento, il manutentore non ha modo di sapere, quando trova quelli due istanze di 50000 nel codice, che significino lo stesso 50k o 50k completamente non correlati. E dovresti anche cercare 49999 e 50001, nel caso qualcuno li usasse anche come costanti? Non si tratta di una chiamata per inserire quelle variabili in un file di configurazione di un servizio separato: ma codificarle in linea è chiaramente anche sbagliato. Invece, dovrebbero essere costanti, definite e con ambito all'interno della classe o del file in cui vengono utilizzate. Se le due istanze di 50k usano la stessa costante, probabilmente rappresentano la stessa restrizione legislativa; in caso contrario, probabilmente non lo fanno; e in entrambi i casi, avranno un nome,

I nomi dei file vengono passati a una funzione - attachDocument () - che accetta i nomi di file di base come stringa, senza percorso o estensione. I nomi dei file sono essenzialmente chiavi esterne di alcuni filesystem o database, o da qualunque luogo attachDocument () ottenga i file. Ma le stringhe non ti dicono nulla al riguardo: quanti file ci sono? Quali tipi di file sono? Come fai a sapere quando apri un nuovo mercato se devi aggiornare questa funzione? A quali tipi di cose possono essere collegati? Il manutentore viene lasciato completamente al buio, e tutto ciò che ha è una stringa, che può apparire più volte nel codice e significare cose diverse ogni volta che appare. In un punto, "SR008-04X" è un cheat code. In un altro, è un comando per ordinare quattro razzi booster SR008. Ecco qui' un nome di file? Sono collegati? Qualcuno ha appena cambiato quella funzione per menzionare un altro file, "CLIENT". Quindi, povero manutentore, è stato informato che il file "CLIENT" deve essere rinominato in "CLIENTE". Ma la stringa "CLIENT" appare 937 volte nel codice ... da dove inizi a cercare?

Il problema del giocattolo è che i valori sono tutti insoliti e si può ragionevolmente garantire che siano univoci nel codice. Non "1" o "10" ma "50.000". Non "client" o "report" ma "SR008-04X".

L' uomo di paglia è che l'unico altro modo per affrontare il problema delle costanti impenetrabilmente opachi è di scorporare loro fuori nel file di configurazione di qualche servizio non correlato.

Insieme, puoi usare questi due errori per dimostrare qualsiasi argomento vero.


2
Non è un problema di giocattoli, non un pagliaccio. Questo è qualcosa che vedrai continuamente in questo tipo di applicazioni aziendali. Non c'è "apertura in un nuovo mercato", non c'è riutilizzo dello stesso numero (dopotutto, ciò darebbe comunque un altro significato) e in ogni caso, l'articolo non dice nulla contro DRY - se ci sono due dipendenze dal valore, esso sarà spostato in un metodo o una costante. Mostra esempi di come dovrebbero essere nominate quelle costanti (delle impostazioni di configurazione, non importa) e dove dovrebbero essere memorizzate in un modo che sia a prova di futuro e più chiaro del codice.
Luaan,

4
L'esempio non si scompone perché è un problema con i giocattoli. Il codice circostante sarà sempre orribile perché le regole aziendali che il software deve eseguire sono horror . Tenta di affiancare questa sfida fondamentale con i motori delle regole e le DSL e ciò che spesso è la procrastinazione del programmatore , perché risolvere i problemi di CS è più divertente che risolvere la complessità dei moduli fiscali. I tentativi di raggiungere "l'eleganza" sono spesso commissioni folli perché il compito finale del software è quello di modellare un disastro complicato.
whatsisname

Le regole aziendali possono essere horror, ma non è di per sé una scusa per scrivere questo tipo di codice procedurale mediocre. (Tendo a concordare con Papadimoulis che è più facile modellare e mantenere le regole nel codice che nella configurazione, penso solo che dovrebbe essere un codice migliore.) Il problema DRY che vedo non sono i numeri magici, è il ripetuto if (...) { attachDocument(...); }.
David Moles,

2

Ci sono diversi problemi in questo.

Un problema è se un motore di regole dovrebbe essere creato per rendere tutte le regole facilmente configurabili al di fuori del programma stesso. La risposta in casi simili a questo è spesso no. Le regole cambieranno in modi strani che sono difficili da prevedere, il che significa che il motore delle regole deve essere esteso ogni volta che c'è un cambiamento.

Un altro problema è come gestire queste regole e le loro modifiche nel controllo della versione. La soluzione migliore qui è quella di dividere le regole in una classe per ogni regola.

Ciò consente a ciascuna regola di avere la propria validità, alcune regole cambiano ogni anno, alcune modifiche dipendono da quando è stata concessa un'autorizzazione o quando viene emessa una fattura. La stessa regola che contiene il controllo per quale versione deve applicare.

Inoltre, poiché la costante è privata, non può essere utilizzata in modo improprio in nessun altro punto del codice.

Quindi avere un elenco di tutte le regole e applicare l'elenco.

Un ulteriore problema è come gestire le costanti. 500000 potrebbe sembrare poco appariscente, ma bisogna fare molta attenzione per assicurarsi che venga convertito correttamente. Se viene applicata un'aritmetica in virgola mobile, questa potrebbe essere convertita in 500.000,00001, pertanto un confronto con 500.000,00000 potrebbe non riuscire. O peggio ancora 500000 funziona sempre come previsto, ma in qualche modo 565000 fallisce quando viene convertito. Assicurati che la conversione sia esplicita e fatta da te non indovinando il compilatore. Spesso questo viene fatto convertendolo in alcuni BigInteger o BigDecimal prima che venga utilizzato.


2

Sebbene non sia menzionato direttamente nella domanda, vorrei sottolineare che l'importante è non seppellire la logica aziendale nel codice.

Il codice, come nell'esempio sopra riportato, che codifica per i requisiti aziendali specificati esternamente, dovrebbe realmente risiedere in una parte distinta dell'albero dei sorgenti, forse denominata businesslogico qualcosa di simile, e fare attenzione a garantire che codifichi solo i requisiti aziendali in modo semplice, leggibile e il più conciso possibile, con un minimo di boilerplate e con commenti chiari e informativi.

Dovrebbe non essere miscelato con il codice di "infrastruttura" che implementa la funzionalità necessaria per svolgere la logica di business, come ad esempio, ad esempio, l'applicazione del attachDocument()metodo nel esempio, o ad esempio di interfaccia utente, la registrazione o il codice del database in generale. Mentre un modo per applicare questa separazione è "codificare" tutta la logica aziendale in un file di configurazione, questo è tutt'altro che l'unico (o il migliore) metodo.

Tale codice di logica aziendale dovrebbe anche essere scritto in modo abbastanza chiaro che, se lo mostrassi a un esperto di dominio aziendale senza capacità di codifica, sarebbero in grado di dargli un senso. Per lo meno, se e quando cambiano i requisiti aziendali, il codice che li codifica dovrebbe essere abbastanza chiaro che persino un nuovo programmatore senza precedenti familiari con la base di codice dovrebbe essere in grado di individuare, rivedere e aggiornare facilmente la logica aziendale, supponendo che nessuna funzionalità qualitativamente nuova è richiesta.

Idealmente, tale codice verrebbe anche scritto in un linguaggio specifico del dominio per imporre la separazione tra la logica aziendale e l'infrastruttura sottostante, ma ciò potrebbe essere inutilmente complicato per un'app interna di base. Detto questo, se ad esempio stai vendendo il software a più clienti, ognuno dei quali ha bisogno del proprio set personalizzato di regole aziendali, un semplice linguaggio di scripting specifico per il dominio (forse ad esempio basato su un sandbox Lua ) potrebbe essere la cosa giusta.


Questo è esattamente quello che stavo pensando !!! Quando la logica è sepolta nel profondo del codice, come può un esperto di dominio / materia o un utente aziendale vedere i valori e la logica che sono in uso al fine di assicurarsi che siano corretti e diagnosticare il comportamento del sistema? Una cosa che fa un file di configurazione è rendere visibili le impostazioni . Devono esserci alcuni mezzi per promuovere la visibilità delle regole aziendali, anche se ciò rende la codifica "più difficile". Posso accettare una classe sottile o un insieme di classi che svolgono il lavoro, senza mescolare altre preoccupazioni, purché l'utente aziendale abbia i mezzi per accedervi e comprenderle.
ErikE
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.