La soluzione dovrebbe essere il più generica possibile o il più specifica possibile?


124

Supponiamo di avere un'entità con l'attributo "tipo". Potrebbero esserci più di 20 tipi possibili.

Ora mi viene chiesto di implementare qualcosa che consenta di cambiare il tipo da A-> B, che è l'unico caso d'uso.

Quindi dovrei implementare qualcosa che consenta modifiche arbitrarie di tipo purché siano tipi validi? O dovrei consentire SOLO di cambiare da A-> B secondo il requisito e rifiutare qualsiasi altro cambio di tipo come B-> A o A-> C?

Riesco a vedere i pro e i contro di entrambe le parti, in cui una soluzione generica significherebbe meno lavoro nel caso in cui si presentino requisiti simili in futuro, ma significherebbe anche maggiori possibilità di sbagliare (anche se al 100% controlliamo il chiamante in questo punto).
Una soluzione specifica è meno soggetta a errori, ma richiede più lavoro in futuro se si presenta un requisito simile.

Continuo a sentire che un buon sviluppatore dovrebbe cercare di anticipare il cambiamento e progettare il sistema in modo che sia facile estenderlo in futuro, che suona come una soluzione generica è la strada da percorrere?

Modificare:

Aggiunta di maggiori dettagli al mio esempio non così specifico: la soluzione "generica" ​​in questo caso richiede meno lavoro rispetto alla soluzione "specifica", poiché la soluzione specifica richiede la convalida sul vecchio tipo e sul nuovo tipo, mentre la soluzione generica è necessario solo convalidare il nuovo tipo.


97
Questa è una domanda interessante. Ho avuto una discussione su qualcosa del genere con i miei nonni (un programmatore di timer molto, molto vecchio) e la sua risposta è stata qualcosa in linea con "la cosa più generica che risolve il tuo problema specifico", che si riduce a una fantasia " Dipende". Le dichiarazioni generali nello sviluppo del software raramente funzionano: le cose dovrebbero essere prese sempre caso per caso.
T. Sar,

2
@ T.Sar aggiungo questo come risposta e voterò :-)
Christophe il

4
Qual è una "soluzione generica" ​​secondo te? Inoltre, si prega di chiarire cosa si intende per "solo caso d'uso". Vuoi dire che è consentita solo una transizione da A-> B o è specificata solo quella transizione e non sarebbe una condizione di errore passare da un altro stato a un altro stato. Come sviluppatore devi chiedere all'autore del caso d'uso di chiarire. Se non è consentita alcuna altra transizione e il codice lo consente indipendentemente da chi controlla il chiamante, il codice non è riuscito a soddisfare i requisiti.
RibaldEddie,

5
Il principio secondo cui se X è una buona idea, allora solo X per tutto il tempo deve essere ottimale, sembra avere un fascino particolare per gli sviluppatori (o almeno un gruppo vocale tra loro), ma considera questo: le regole empiriche di programmazione sono come i proverbi, in quanto spesso puoi trovare una coppia con implicazioni opposte. Questo è un segno che dovresti usare il tuo giudizio (come sostenuto dalle risposte qui) e fare attenzione al dogma.
sdenham,

2
La generalizzazione precoce può causare bruciori di stomaco tanto quanto l'ottimizzazione precoce: finisci per scrivere un sacco di codice che non potresti mai usare. Risolto per primo il problema specifico, quindi generalizzare in caso di necessità.
John Bode,

Risposte:


296

La mia regola empirica:

  1. la prima volta che riscontri il problema, risolvi solo il problema specifico (questo è il principio YAGNI )
  2. la seconda volta che si verifica lo stesso problema, prendere in considerazione la generalizzazione del primo caso, se non richiede molto lavoro
  3. una volta che hai tre casi specifici in cui saresti in grado di utilizzare la versione generalizzata, allora dovresti iniziare davvero a pianificare la versione generalizzata - ormai dovresti capire il problema abbastanza bene da poterlo effettivamente generalizzare.

Naturalmente, questa è una linea guida e non una regola rigida: la vera risposta è usare il tuo miglior giudizio, caso per caso.


1
Puoi spiegare cos'è YAGNI?
Bernhard,

7
@ Bernardo non ne avrai bisogno . Un principio di progettazione software molto utile.
Angew,

4
"At thing1, thing2, pensa forse all'utilizzo di un array. At thing1, thing2, thing3, quasi certamente usa thing[]invece l'array." è una regola empirica simile per decidere tra più variabili o un singolo array.
Joker_vD

15
Un altro modo per affermare la regola n. 1: "Non puoi generalizzare una cosa".
Wayne Conrad,

2
@SantiBailors: Come dice Doc Brown nella sua risposta, spesso sopravvalutiamo enormemente la quantità di sforzi sprecati che potremmo fare costruendo il primo da buttare via. In The Mythical Man-Month , Fred Brooks dice: "Pianifica di buttarne via uno - lo farai, comunque." Detto questo: se riscontri immediatamente più di un uso per qualcosa - ad esempio, ottenendo una serie di requisiti in cui dovrai chiaramente risolvere lo stesso problema più di una volta - allora hai già più di un caso da generalizzare da, e va benissimo e non è in conflitto con la mia risposta.
Daniel Pryden,

95

Una soluzione specifica [...] richiede più lavoro in futuro se sono necessari requisiti simili

Ho ascoltato questa discussione diverse decine di volte e, per la mia esperienza, risulta regolarmente un errore. Se generalizzi ora o più tardi, quando sorge il secondo requisito simile, il lavoro sarà quasi lo stesso in totale. Quindi non ha assolutamente senso investire ulteriori sforzi in termini di generalizzazione, quando non sai che questo sforzo sarà ripagato.

(Ovviamente questo non si applica quando una soluzione più generale è meno complicata e richiede meno sforzi di una specifica, ma per la mia esperienza, questi sono casi rari. Un tale tipo di scenario è stato successivamente modificato nella domanda, e non è il una è la mia risposta).

Quando appare il "secondo caso simile", allora è il momento di iniziare a pensare alla generalizzazione. Sarà molto più facile generalizzare correttamente allora, perché questo secondo requisito ti offre uno scenario in cui puoi validare se hai reso le cose giuste generiche. Quando cerchi di generalizzare solo per un caso, stai sparando nel buio. È molto probabile che tu sovra-generalizzi certe cose che non hanno bisogno di essere generalizzate e perdi altre parti che dovrebbero. E quando sorge un secondo caso e ti rendi conto di aver generalizzato le cose sbagliate, allora hai molto più lavoro da fare per risolvere questo problema.

Quindi consiglio di ritardare qualsiasi tentazione di fare le cose "per ogni evenienza". Questo approccio porterà a maggiori sforzi di lavoro e manutenzione solo quando ti sei perso l'occasione di generalizzare tre, quattro o più volte e poi hai una pila di codice simile (così duplicato) da mantenere.


2
Per me questa risposta non ha senso nel contesto di OP. Sta dicendo che passerà meno tempo a generalizzare ora e meno tempo in futuro, a meno che in futuro non sia necessario che l'implementazione sia specifica. Stai discutendo contro "l'investimento di ulteriori sforzi nella generalizzazione", mentre l'OP investirà ulteriori sforzi solo se non generalizzano. (pensa) .... strano: $
msb

2
@msb: quel contesto è stato aggiunto dopo che ho scritto la mia risposta e va contro ciò che l'OP stava dicendo prima, specialmente nella parte che ho citato. Vedi la mia modifica.
Doc Brown,

2
Inoltre, la soluzione generalizzata sarà più complicata, quindi quando dovrai adattarla per il secondo caso, ci vorrà molto più tempo per capirla di nuovo.
AndreKR,

4
Doc, a parte, ma non avrei mai immaginato che fossi un madrelingua. Le tue risposte sono sempre ben scritte e ben argomentate.
user949300

2
Immaginerò il tuo accento quando leggerò le tue risposte future. :-)
user949300

64

TL; DR: dipende da cosa stai cercando di risolvere.

Ho avuto una conversazione simile con i miei Gramps su questo, mentre stavamo parlando di come Func e Action in C # siano fantastici. My Gramps è un programmatore di timer molto vecchio, che è stato basato sui codici sorgente da quando il software è stato eseguito su computer che occupavano un'intera stanza.

Ha cambiato tecnologia diverse volte nella sua vita. Ha scritto codice in C, COBOL, Pascal, BASIC, Fortran, Smalltalk, Java e alla fine ha iniziato C # come hobby. Ho imparato a programmare con lui, seduto in grembo mentre ero solo un devoto, intagliando le mie prime righe di codice sull'editor blu di IBM SideKick. Quando avevo 20 anni, avevo già trascorso più tempo a scrivere codice che a suonare fuori.

Questi sono un po 'dei miei ricordi, quindi mi scusi se non sono esattamente pratico mentre li ripeto. Sono un po 'affezionato a quei momenti.

Questo è quello che mi ha detto:


"Dovremmo andare per la generalizzazione di un problema, o risolverlo nello specifico ambito, chiedete? Bene, questa è una ... domanda."

Gramps fece una pausa per pensarci su per un breve momento, fissando la posizione dei suoi occhiali sul viso. Stava giocando una partita a 3 sul suo computer, mentre ascoltava un LP di Deep Purple sul suo vecchio sistema audio.

"Bene, ciò dipenderebbe dal problema che stai cercando di risolvere", mi ha detto. "È allettante credere che esista un'unica soluzione sacra per tutte le scelte progettuali, ma non ce n'è una. L'architettura software è come il formaggio, vedi."

"... Formaggio, Gramps?"

"Non importa cosa pensi del tuo preferito, ci sarà sempre qualcuno che pensa che sia puzzolente".

Sbattei le palpebre confuso per un momento, ma prima che potessi dire qualsiasi cosa Gramps continuò.

"Quando costruisci un'auto, come scegli il materiale per una parte?"

"Im ... suppongo che dipenda dai costi e da cosa dovrebbe fare la parte, suppongo."

"Dipende dal problema che una parte sta cercando di risolvere. Non costruirai una gomma in acciaio o un parabrezza in pelle. Scegli il materiale che risolve meglio il problema che hai a portata di mano. Ora, cos'è un soluzione generica? O una specifica? A quale problema, a quale caso d'uso? Dovresti seguire un approccio completamente funzionale, per dare la massima flessibilità a un codice che verrà usato una sola volta? Dovresti scrivere un codice molto specializzato e fragile su una parte del tuo sistema che vedrà molti e molti usi e forse molti cambiamenti? Le scelte di design come quelle sono come i materiali che scegli per una parte in un'auto o la forma del mattoncino Lego che scegli per costruire una piccola casa Quale mattoncino Lego è il migliore? "

L'anziano programmatore ha preso un piccolo modello di treno Lego che ha sul tavolo prima di continuare.

"Puoi rispondere solo se sai per cosa hai bisogno di quel mattone. Come diavolo saprai se la soluzione specifica è migliore di quella generica, o viceversa, se non sai nemmeno quale problema stai stai cercando di risolvere? Non puoi vedere oltre una scelta che non capisci. "

"..Hai appena citato The Matrix? "

"Che cosa?"

"Niente, dai."

"Bene, supponiamo che tu stia cercando di creare qualcosa per il National Invoice System. Sai come appariranno dall'interno quell'infernale API e il suo file XML di trentamila righe. Come sarebbe una soluzione" generica "per creare quel file ad esempio? Il file è pieno di parametri opzionali, pieno di casi che dovrebbero utilizzare solo settori di attività molto specifici. Nella maggior parte dei casi, è possibile ignorarli in modo sicuro. Non è necessario creare un sistema di fatturazione generico se l'unica cosa che si ' venderò mai sono scarpe. Basta creare un sistema per vendere scarpe e renderlo il miglior sistema di fatturazione per la vendita di scarpe maledetto là fuori. Ora, se dovessi creare un sistema di fatturazione per qualsiasi tipo di cliente, su un'applicazione più ampia - essere rivenduto come un sistema di vendita generico indipendente,per esempio - ora è interessante implementare quelle opzioni che sono usate solo per gas, cibo o alcool.Ora quelli sono possibili casi d'uso. Prima erano solo alcuni ipotetici casi di non utilizzo e non si desidera implementare casi di non utilizzo . Non usare è il fratellino di Non ho bisogno ".

Gramps rimise il lego train al suo posto e tornò al suo match-3 game.

"Quindi, per essere in grado di scegliere una soluzione generica o specifica per un determinato problema, devi prima capire qual è il problema. Altrimenti stai solo indovinando, e indovinare è il lavoro dei manager, non dei programmatori. Come quasi tutto nell'IT, dipende. "


Così il gioco è fatto. "Dipende". Questa è probabilmente la più potente espressione di due parole quando si pensa alla progettazione del software.


14
Sono sicuro che ci sia qualcosa di utile in quella storia ma è stato troppo doloroso da leggere, scusa
GoatInTheMachine,

28
Il tuo primo post è stato un breve aneddoto divertente - e ovviamente è una questione di opinione - ma a meno che non mi piaccia davvero qualcuno che scrive lo stile, trovo storie lunghe come questa davvero autoindulgente e un po 'inappropriata al di fuori di un blog personale
GoatInTheMachine

16
@T.Sar non ascolta chi odia, il tuo post è un gioiello di consigli utili da parte di un guru. +1
LLlAMnYP

7
La parte "l'architettura del software è come il formaggio" era semplicemente fantastica. In effetti, questa risposta è una gemma!
Mathieu Guindon,

3
Forse questa risposta è come anche il formaggio? ;) Ma per favore, "SmallTalk" dovrebbe essere "Smalltalk", e sì, io sono quel ragazzo, scusa.
fede s.

14

In primo luogo, dovresti cercare di prevedere se è probabile che si verifichi un tale cambiamento, non solo una possibilità remota da qualche parte lungo la linea.

In caso contrario, di solito è meglio cercare subito la soluzione semplice ed estenderla in seguito. È possibile che tu abbia una visione molto più chiara di ciò che è necessario allora.


13

Se stai lavorando in un dominio che è nuovo per te, allora la Regola dei tre che Daniel Pryden ha menzionato sicuramente dovrebbe essere applicata. Dopo tutto, come dovresti costruire astrazioni utili se sei un principiante in quella zona? Le persone sono spesso sicure della propria capacità di catturare le astrazioni, anche se raramente è così. Secondo la mia esperienza, l'astrazione prematura non è meno malefica della duplicazione del codice. Le astrazioni errate sono davvero dolorose da comprendere. A volte anche più doloroso da refactoring.

C'è un libro che affronta il mio punto su cui sta lavorando uno sviluppatore di un'area sconosciuta. È costituito da domini specifici con astrazioni utili estratte.


La domanda è chiara su un problema concreto.
RibaldEddie,

4
La risposta è abbastanza generica per affrontare questo problema concreto. E la domanda non è abbastanza specifica per ricevere una ricevuta concreta: come puoi vedere, in una domanda non vengono menzionati i dettagli del dominio. Anche i nomi delle classi non sono specificati (A e B non contano).
Zapadlo,

7
"Una risposta stackoverflow dovrebbe essere il più generica possibile o il più specifica possibile?"
Lyndon White il

@LyndonWhite una domanda di StackOver dovrebbe essere il più generica possibile (troppo ampia!) O il più specifica possibile (come si chiama quel fallimento!)? Ha.

4

Data la natura del corpo della tua domanda, supponendo che l'abbia capito correttamente, in realtà la vedo come una domanda di progettazione delle caratteristiche del sistema centrale più che una domanda su soluzioni generiche o specifiche.

E quando si tratta di funzionalità e capacità del sistema centrale, quelle più affidabili sono quelle che non ci sono. Vale la pena sbagliare dal punto di vista del minimalismo, soprattutto considerando che è generalmente più facile aggiungere funzionalità centralmente, a lungo desiderato, piuttosto che rimuovere funzionalità problematiche, a lungo indesiderate, con numerose dipendenze perché ha reso il lavoro con il sistema molto più difficile di quanto deve essere mentre solleva infinite domande sul design con ogni nuova funzionalità.

In effetti, mancando di una forte anticipazione sulla necessità che ciò sia necessario frequentemente in futuro, cercherei di evitare di considerare questo come un rimpiazzo di tipo da A a B, se possibile, e invece cerco solo un modo per trasformare lo stato di A. Ad esempio, imposta alcuni campi in A per renderlo trasformabile e apparire come B per l'utente senza effettivamente cambiare in un 'tipo' diverso di cose - potresti potenzialmente creare un negozio B privatamente usando la composizione e chiamare le funzioni in B quando lo stato di A è impostato per indicare che dovrebbe simulare B per semplificare l'implementazione, se possibile. Dovrebbe essere una soluzione molto semplice e minimamente invasiva.

Quindi, facendo eco a molti altri, suggerirei di sbagliare sul lato evitando soluzioni generiche in questo caso, ma soprattutto perché presumo che questo sia in considerazione dell'aggiunta di una capacità molto audace al sistema centrale, e lì avrei suggerire di sbagliare sul lato di lasciarlo fuori, soprattutto per ora.


"ti mancano tutti i bug che non scrivi." (dal poster del basket: ti mancano tutti i colpi che non fai)

3

È difficile dare una risposta generica a questo specifico problema ;-)

Più è generico, più tempo guadagnerai per le modifiche future. Ad esempio, per questo motivo molti programmi di gioco usano il modello di componenti entità invece di costruire un sistema di tipo molto elaborato ma rigido dei personaggi e degli oggetti nel gioco.

D'altra parte, fare qualcosa di generico richiede un investimento iniziale in termini di tempo e fatica nel design che è molto più elevato rispetto a qualcosa di molto specifico. Ciò comporta il rischio di un eccesso di ingegneria e persino di perdersi in potenziali requisiti futuri.

Vale sempre la pena vedere se c'è una generalizzazione naturale che ti farà fare una svolta. Tuttavia, alla fine, si tratta di una questione di equilibrio, tra lo sforzo che puoi spendere ora e lo sforzo di cui potresti aver bisogno in futuro.


3
  1. Ibrido. Questa non deve essere una / o domanda. Puoi progettare l'API per le conversioni di tipo generale implementando solo la conversione specifica di cui hai bisogno in questo momento. (Assicurati solo che se qualcuno chiama l'API generale con una conversione non supportata, fallisca con uno stato di errore "non supportato".)

  2. Testing. Per la conversione A-> B, dovrò scrivere uno (o un piccolo numero) di test. Per una conversione x-> y generica, potrei dover scrivere un'intera matrice di test. È sostanzialmente più lavoro, anche se tutte le conversioni condividono un'unica implementazione generica.

    Se, d'altra parte, si scopre che esiste un modo generico per testare tutte le possibili conversioni, allora non c'è molto altro lavoro e potrei essere propenso ad andare prima a una soluzione generica.

  3. Accoppiamento. Un convertitore da A a B potrebbe necessariamente aver bisogno di conoscere i dettagli di implementazione di A e B (accoppiamento stretto). Se A e B sono ancora in evoluzione, ciò significa che potrei dover continuare a rivisitare il convertitore (e i suoi test), il che fa schifo, ma almeno è limitato a A e B.

    Se avessi scelto una soluzione generica che necessita dell'accesso ai dettagli di tutti i tipi, quindi anche con l'evoluzione di C e D, potrei aver bisogno di continuare a modificare il convertitore generico (e un sacco di test), il che può rallentarmi anche se nessuno ancora ha bisogno di convertire in C o D .

    Se sia le conversioni generiche sia quelle specifiche possono essere implementate in un modo che è solo vagamente accoppiato ai dettagli dei tipi, allora non mi preoccuperei di questo. Se uno di questi può essere fatto in modo vagamente accoppiato ma l'altro richiede un accoppiamento stretto, allora questo è un argomento forte per l'approccio liberamente accoppiato appena uscito dal cancello.


2
Il test è un buon punto. È un grande vantaggio se si progettano soluzioni generiche basate su concetti tratti dalla teoria delle categorie , perché spesso si ottengono teoremi gratuiti che dimostrano che l'unica possibile implementazione per una firma (che il verificatore del tipo del compilatore accetta) è quella corretta , o almeno che se l'algoritmo funziona per qualsiasi tipo particolare deve funzionare anche per tutti gli altri tipi.
sinistra il

Immagino che ci sia un motivo specifico del dominio per cui è stata richiesta solo una conversione di tipo, il che significa che la maggior parte delle conversioni di tipo sarebbe azioni non valide nel dominio problematico e, per tale motivo, non dovrebbero essere supportate dall'app fino a quando sono ufficialmente ammessi. Questa risposta si avvicina di più a tale argomento.
Ralf Kleberhoff,

3

La soluzione dovrebbe essere il più generica possibile o il più specifica possibile?

Questa non è una domanda rispondibile.

Il meglio che puoi ragionevolmente ottenere è un paio di euristiche per decidere quanto generale o specifico fare una determinata soluzione. Lavorando attraverso qualcosa come il processo di seguito, di solito l'approssimazione del primo ordine è corretta (o abbastanza buona). In caso contrario, è probabile che il motivo sia troppo specifico per il dominio per essere utilmente trattato in dettaglio qui.

  1. Approssimazione del primo ordine: la solita regola YAGNI di tre come descritta da Daniel Pryden, Doc Brown, et al .

    Questa è un'euristica generalmente utile perché è probabilmente il meglio che puoi fare che non dipende dal dominio e da altre variabili.

    Quindi, la presunzione iniziale è: facciamo la cosa più specifica.

  2. Approssimazione del secondo ordine: in base alla tua conoscenza approfondita del dominio della soluzione , dici

    La soluzione "generica" ​​in questo caso richiede meno lavoro rispetto alla soluzione "specifica"

    quindi potremmo reinterpretare YAGNI come raccomandando di evitare lavori inutili , piuttosto che evitare inutili generalità. Quindi, potremmo modificare la nostra presunzione iniziale e invece fare la cosa più semplice .

    Tuttavia, se le tue conoscenze sul dominio della soluzione indicano che è probabile che la soluzione più semplice apra molti bug o sia difficile testare adeguatamente o causare altri problemi, essere più facile da codificare non è necessariamente un motivo sufficiente per cambiare il nostro scelta originale.

  3. Approssimazione di terzo ordine: la tua conoscenza del dominio problematico suggerisce che la soluzione più semplice sia effettivamente corretta o stai permettendo a molte transizioni che conosci di essere insignificanti o sbagliate?

    Se la soluzione semplice ma generica sembra problematica, o non sei sicuro della tua capacità di giudicare questi rischi, fare il lavoro extra e rimanere con la tua ipotesi iniziale è probabilmente meglio.

  4. Approssimazione del quarto ordine: la tua conoscenza del comportamento del cliente, o in che modo questa funzionalità si collega ad altri, o priorità di gestione del progetto, o ... qualsiasi altra considerazione non strettamente tecnica modifica la tua attuale decisione di lavoro?


2

Non è una domanda facile a cui rispondere con una risposta semplice. Molte risposte hanno dato l'euristica costruita attorno a una regola di 3 o qualcosa di simile. Andare oltre tali regole empiriche è difficile.

Per rispondere davvero alla tua domanda, devi considerare che molto probabilmente il tuo lavoro non implementerà qualcosa che cambia A-> B. Se sei un appaltatore, forse questo è il requisito, ma se sei un dipendente, sei stato assunto per svolgere molte attività più piccole per l'azienda. Cambiare A-> B è solo una di quelle attività. La tua azienda si preoccuperà anche della possibilità di apportare le modifiche future, anche se ciò non è indicato nella richiesta. Per trovare "TheBestImplementation (tm)", devi guardare il quadro più ampio di ciò che ti viene veramente chiesto di fare, quindi usalo per interpretare la piccola richiesta che ti è stata data per cambiare A-> B.

Se sei un programmatore di basso livello appena uscito dal college, è spesso consigliabile fare esattamente quello che ti è stato detto di fare. Se sei stato assunto come architetto del software con 15 anni di esperienza, in genere è consigliabile pensare a grandi cose. Ogni lavoro vero e proprio cadrà tra "fai esattamente quello che è il compito ristretto" e "pensa al quadro generale". Sentirai dove si inserisce il tuo lavoro in quello spettro se parli abbastanza con le persone e fai abbastanza lavoro per loro.

Posso fare alcuni esempi concreti in cui la tua domanda ha una risposta definitiva basata sul contesto. Considera il caso in cui stai scrivendo un software critico per la sicurezza. Ciò significa che hai un team di test in piedi per garantire che il prodotto funzioni come promesso. Alcuni di questi team di test sono tenuti a testare ogni singolo percorso possibile attraverso il codice. Se parli con loro, potresti scoprire che se generalizzi il comportamento, aggiungerai $ 30.000 ai loro costi di test perché dovranno testare tutti quei percorsi extra. In tal caso, non aggiungere funzionalità generalizzate, anche se è necessario duplicare il lavoro 7 o 8 volte a causa di esso. Risparmia i soldi dell'azienda e fai esattamente quello che la richiesta ha dichiarato.

D'altra parte, considera che stai creando un'API per consentire ai clienti di accedere ai dati in un programma di database creato dalla tua azienda. Un cliente richiede di consentire le modifiche A-> B. Le API in genere hanno un aspetto di manette d'oro: una volta aggiunta la funzionalità a un'API, in genere non è necessario rimuovere tale funzionalità (fino al prossimo numero di versione principale). Molti dei tuoi clienti potrebbero non essere disposti a pagare per il costo dell'aggiornamento al prossimo numero di versione principale, quindi potresti rimanere bloccato con qualsiasi soluzione tu scelga da molto tempo. In questo caso, consiglio vivamente di creare la soluzione generica dall'inizio. Non vuoi davvero sviluppare una cattiva API piena di comportamenti unici.


1

Hmm ... non c'è molto contesto da seguire per una risposta ... che fa eco alle risposte precedenti, "Dipende".

In un certo senso, devi ricorrere alla tua esperienza. Se non il tuo, allora qualcuno più anziano nel dominio. Potresti discutere di ciò che affermano i criteri di accettazione. Se è qualcosa sulla falsariga di "l'utente dovrebbe essere in grado di cambiare il tipo da" A "a" B "'rispetto a' l'utente dovrebbe essere in grado di cambiare il tipo dal suo valore corrente a qualsiasi valore alternativo consentito '.

I criteri di accettazione frequente sono soggetti a interpretazione, ma un buon personale addetto al controllo qualità può scrivere criteri adeguati all'attività in corso, riducendo al minimo l'interpretazione necessaria.

Esistono restrizioni di dominio che non consentono il passaggio da "A" a "C" o qualsiasi altra opzione, ma solo da "A" a "B"? O è solo un requisito strettamente limitato che non è "lungimirante"?

Se il caso generale fosse più difficile, andrei a chiedere prima di iniziare il lavoro, ma nel tuo caso se potessi "prevedere" che altre richieste di modifica di "tipo" sarebbero arrivate in futuro, sarei tentato di: a) scrivere qualcosa di riutilizzabile per il caso generale e b) avvolgerlo in un condizionale che consenta solo A -> B per ora.

Abbastanza facile da verificare per il caso corrente nei test automatizzati e abbastanza facile da aprirsi ad altre opzioni in seguito se / quando insorgono casi d'uso diversi.


1

Per me, una linea guida che ho stabilito qualche tempo fa è: "Per requisiti ipotetici scrivere solo un codice ipotetico". Cioè - se anticipi requisiti aggiuntivi, dovresti pensare un po 'a come implementarli e strutturare il tuo codice attuale in modo che non si blocchi in quel modo.

Ma non scrivere codice reale per questi ora - pensa solo a ciò che faresti. Altrimenti di solito renderai le cose inutilmente complesse e probabilmente sarai infastidito più tardi quando arriveranno requisiti effettivi che differiscono da ciò che avevi previsto.

Quattro il tuo esempio: se hai tutti gli usi del metodo di conversione sotto il tuo controllo, puoi semplicemente chiamarlo convertAToB per ora e pianificare di utilizzare un refactoring "rinomina metodo" nell'IDE per rinominarlo se hai bisogno di funzionalità più generali in seguito. Tuttavia, se il metodo di conversione fa parte di un'API pubblica, questo potrebbe essere piuttosto diverso: essere così specifici bloccherebbe la generalizzazione in un secondo momento, poiché in quel caso è difficile rinominare le cose.


0

Continuo a sentire che un buon sviluppatore dovrebbe cercare di anticipare il cambiamento e progettare il sistema in modo che sia facile estenderlo in futuro,

In linea di principio si. Ma questo non porta necessariamente a soluzioni generiche.

Esistono due tipi di argomenti nello sviluppo del software, per quanto mi riguarda, in cui dovresti anticipare i cambiamenti futuri:

  • Librerie destinate ad essere utilizzate da terze parti e
  • architettura generale del software.

Il primo caso viene risolto osservando coesione / accoppiamento, iniezione di dipendenza o altro. Il secondo caso è a un livello più astratto, ad esempio la scelta di un'architettura orientata ai servizi anziché di una grande quantità di codice monolotico per un'applicazione di grandi dimensioni.

Nel tuo caso, stai chiedendo una soluzione specifica per un problema specifico, che non ha alcun impatto prevedibile sul futuro. In questo caso, YAGNI e DRY sono buoni motti per cui sparare:

  • YAGNI (non ne avrai bisogno) ti dice di implementare le cose di base assolutamente necessarie e di cui hai bisogno in questo momento . Significa implementare il minimo che rende la tua attuale suite di test da rossa a verde, se dovessi usare lo sviluppo in stile TDD / BDD / FDD. Non una sola riga in più.
  • ASCIUTTO (non ripeterti) significa che se riscontri di nuovo un problema simile, allora dai una buona occhiata alla ricerca di una soluzione generica.

Combinato con altre pratiche moderne (come una buona copertura del test per essere in grado di eseguire il refactoring in modo sicuro), ciò significa che si finisce con un codice medio scritto, snello e rapido che cresce secondo necessità.

quale suona come una soluzione generica è la strada da percorrere?

No, sembra che dovresti avere ambienti di programmazione, linguaggi e strumenti che rendono facile e divertente il refactoring quando ne hai bisogno. Le soluzioni generiche non lo forniscono; disaccoppiano l'applicazione dal dominio effettivo.

Dai un'occhiata ai moderni ORM o framework MVC, ad esempio Ruby on Rails; a livello di applicazione, tutto si concentra sul fare un lavoro non generico. Le stesse librerie di rotaie sono ovviamente quasi al 100% generiche, ma il codice di dominio (di cui si tratta la tua domanda) dovrebbe essere minimale in questo aspetto.


0

Un modo diverso di pensare al problema è considerare ciò che ha senso.

Ad esempio, c'era un'applicazione che stavo sviluppando che aveva sezioni che facevano quasi la stessa cosa ma avevano regole di autorizzazione incoerenti. Poiché non c'era motivo di mantenerli diversi, quando ho riformattato quella sezione, ho fatto in modo che tutti facessero i permessi allo stesso modo. Ciò ha reso il codice complessivo più piccolo, più semplice e l'interfaccia era più coerente.

Quando la direzione ha deciso di consentire ad altre persone l'accesso a una funzione, siamo riusciti a farlo semplicemente cambiando una bandiera.

Ovviamente ha senso effettuare la conversione del tipo specifico. Ha anche senso fare conversioni di tipo aggiuntive?

Tieni presente che se la soluzione generale è più veloce da implementare, anche il caso specifico è semplice, controlla che sia l'unica conversione di tipo che stai consentendo.

Se l'applicazione si trova in un'area altamente regolamentata (un'applicazione medica o finanziaria), cerca di coinvolgere più persone nella progettazione.

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.