È una violazione del principio Open-Closed aggiornare una costante che rappresenta un valore reale?


10

Ho una classe che calcola il reddito annuo netto dei lavoratori. Ha una costante che rappresenta una percentuale fiscale. Ma un giorno l'aliquota fiscale è cambiata, quindi devo correggere il codice.

L'atto di fissare questa costante indica una violazione del principio aperto-chiuso , poiché postula che una classe dovrebbe essere chiusa alla modifica?


10
Il software cambia perché il mondo reale cambia. D'altra parte, rendere una percentuale fiscale una costante non è tanto una violazione del principio aperto-chiuso, ma è solo una cosa ignorante da fare. La percentuale fiscale è un elemento modificabile evidente che dovrebbe essere vincolato in fase di esecuzione.
Richard Chambers,

4
Sono completamente d'accordo con Richard. Se devi modificare il codice per correggere questa "costante", OCP è l'ultimo dei tuoi problemi.
Robert Harvey,

3
Ciò che costituisce una violazione dell'OCP è altamente soggettivo e il tutto è comunque in qualche modo obsoleto (poiché l'ereditarietà dell'implementazione non è più la migliore pratica). Questa è una domanda tipica in cui devi indovinare cosa pensa la persona che pone la domanda.
Robert Bräutigam l'

2
@DocBrown: cosa costituisce un "nuovo requisito"? Mi mostri un po 'di codice, posso indicare nuovi requisiti che richiederanno sicuramente una modifica del codice, indipendentemente dalla conformità con OCP. Quindi torniamo alla domanda: se lo sviluppatore ha chiesto all'esperto aziendale a riguardo, e non ci si aspettava che l'aliquota fiscale cambiasse più di una volta ogni due anni, non ha senso renderla configurabile o iniettabile. Mantieni la semplicità e preparati a ciò che sai . E per quelle cose, certo, renderlo esterno alla classe. Quindi dipende .
Robert Bräutigam,

1
@ RobertBräutigam: il mio punto è che non esiste IMHO come "OCP conforme", esiste solo "OCP conforme nel contesto di determinate categorie di requisiti". Può sicuramente esserci una certa soggettività a quali categorie un componente dovrebbe essere "conforme OCP". Ma nel caso descritto in questa domanda, per come la capisco, era già stato identificato un requisito in evoluzione, in modo che questa "classe di calcolo del reddito" chiaramente non obbedisse all'OCP nel contesto di questo requisito specifico.
Doc Brown,

Risposte:


14

L'OCP può essere meglio compreso quando si pensa a classi o componenti forniti da un fornitore A in una sorta di libreria a scatola nera, per l'utilizzo da parte degli utenti B, C e D (si noti che questo è solo un modello mentale che sto usando per chiarezza, non importa se in realtà l'unico utente della classe è A stesso).

Se B, C e D possono utilizzare o riutilizzare le classi fornite per diversi casi d'uso, senza la necessità di modificare il codice sorgente della libreria, il componente soddisfa l'OCP ( rispetto a una categoria di casi d'uso ). Ci sono diversi modi per raggiungere questo obiettivo, come

  • rendere ereditaria la classe (in genere in combinazione con il modello di metodo del modello o il modello di strategia)

  • fornendo "punti di iniezione" per l'iniezione di dipendenza

  • fornendo i parametri di configurazione per la classe o il componente (ad esempio, avendo un parametro costruttore "percentuale fiscale", come nel tuo caso, o usando qualche altro meccanismo di configurazione)

  • forse altri mezzi, a seconda del linguaggio di programmazione o dell'ecosistema

Gli esempi tipici che trovi nei libri di testo sono spesso di primo o secondo tipo (immagino perché agli occhi degli autori di quel libro, il terzo tipo è troppo banale per essere menzionato).

Come vedi, questo non ha nulla a che fare con la proibizione di qualsiasi modifica del codice sorgente da parte del fornitore A (come per la correzione di bug, l'ottimizzazione o l'aggiunta di nuove funzionalità in modo compatibile con le versioni precedenti), che non è affatto correlato all'OCP. L'OCP riguarda il modo in cui A progetta l'interfaccia e la granularità dei componenti nella libreria, quindi diversi scenari di riutilizzo (come il resuage con aliquote fiscali diverse) non inducono automaticamente i requisiti per il cambiamento.

Quindi, nonostante ciò che gli altri ti dicono qui, la risposta è chiaramente "sì" , sarebbe una violazione dell'OCP.

EDIT: sembra che qualcuno abbia scritto un post dettagliato sul blog sull'esatto argomento. Sebbene parti di esso possano essere state formulate meglio (come sottolineato da Derek Elkins), sembra che l'autore generalmente condivida il mio punto di vista sul fatto che "soddisfare l'OCP" non è una proprietà assoluta, ma qualcosa che può essere valutato solo nel contesto di alcuni categorie di modifiche ai requisiti.


OK, quindi OCP consiste nel fornire un comportamento estensibile per diversi casi d'uso con uno dei tre mezzi che hai elencato, giusto? Ma cosa succede se l'esempio di un PO implica che qualcosa di fondamentale sta per cambiare? Non so di che paese provenga l'OP, ma nel mio paese l'aliquota fiscale è qualcosa che non cambia molto spesso. Era un cattivo esempio, ma forse è stato estratto intenzionalmente in modo costante, per sottolineare il punto. Sono abbastanza sicuro che non fosse pensato per essere configurabile o estendibile. Quindi forse la domanda era "questo non ha nulla a che fare con la proibizione di qualsiasi modifica del codice sorgente da parte del fornitore A".
Vadim Samokhin l'

Almeno l'ho capito in quel modo. Il povero ragazzo che ha cancellato la sua risposta accettata lo ha fatto o immagino. L'hai visto da una prospettiva un po 'diversa: capisco il tuo punto di vista e sono d'accordo. Ma sembra che il commento più saggio sia stato dato da @Robert Bräutigam. Fino ad ora non ho capito che OCP è COSÌ soggettivo.
Vadim Samokhin l'

1
Immagino che se mi viene mai posta la stessa domanda, c'è una domanda che dovrei porre in risposta: "quel comportamento dovrebbe essere esteso o configurato in qualche modo?". In caso affermativo, la modifica diretta di una classe stessa costituisce una violazione di OCP. Se no - di OCP non è semplicemente applicabile in quella situazione.
Vadim Samokhin,

1
@Zapadlo: Penso che se un componente soddisfa l'OCP per una classe di requisiti non è molto soggettivo - nella maggior parte dei casi è abbastanza chiaro se un nuovo requisito necessita di una modifica del codice sorgente di un componente o se il componente supporta questo requisito ". I possibili approcci per implementarlo non sono limitati ai primi 3 mezzi che ho elencato, vedi la mia modifica. La tua nozione di soggettività potrebbe essere causata perché l'OCP ha solo un nome fuorviante ed è piuttosto male spiegato in molti libri di testo.
Doc Brown,

La mia nozione di soggettività è stata causata dal fatto di non aver compreso appieno quello che hai detto, ma ora lo faccio, immagino. Grazie mille per i commenti perspicaci e la tua risposta.
Vadim Samokhin,

4

Come altri stanno dicendo, idealmente la classe di reddito del lavoratore consentirebbe la parametrizzazione della costante, rendendo questa classe indipendente da quel valore.

In definitiva, l'applicazione chiamante potrebbe anche consentire la parametrizzazione in termini di configurazione esterna (ad esempio un file). Una volta che abbiamo una configurazione esterna, possiamo modificare l'aliquota fiscale, anche se considera che se il file di configurazione viene letto solo una volta all'avvio, l'applicazione dovrà essere riavviata per rendere effettive le percentuali fiscali aggiornate, quindi è qualcosa da mantenere mente. Potremmo fornire una funzione applicativa per rileggere la configurazione quando richiesto per farlo, oppure potremmo fornire un meccanismo più complicato che rileva quando il file di configurazione cambia ...

A lungo termine, potresti scoprire che i problemi fiscali richiedono più di una semplice percentuale, ad esempio che un giorno le leggi fiscali sono più complesse e richiedono diverse percentuali e alcune costanti (ad esempio l'importo inferiore a $ 10k tassato all'X%, mentre il resto tassato all'Y%).

Ciò suggerisce fondamentalmente l'utilizzo di un modello di strategia, in cui la classe principale in questione qui accetta un oggetto di strategia per il calcolo dell'imposta.

Le varie strategie (e% 's e $ costanti) dovrebbero essere selezionabili dal file di configurazione, e ora, l'aggiunta di una nuova strategia richiede l'aggiunta di un nuovo codice, ma non necessariamente gli aggiornamenti al codice esistente.

Ogni strategia potrebbe sapere come analizzare / interpretare i propri argomenti di configurazione esterni, insieme a come calcolare l'imposta effettiva.

Dinamicamente, l'imposta può dipendere ulteriormente dalle impostazioni internazionali, pertanto è possibile che le impostazioni locali siano associate agli utili o ai dipendenti (o entrambi). Nella configurazione esterna, potremmo associare le impostazioni locali alla strategia fiscale.


Vedi anche l' iniezione delle dipendenze , dove gestiamo queste cose in modo esplicito.


1
La domanda non era se fosse una cattiva idea seppellire qualcosa come una percentuale fiscale nel codice, sono sicuro che sia ovvio per la maggior parte di noi qui (incluso il PO). La domanda era: "questo viola l'OCP?" Quindi non vedo come la tua risposta si riferisca a questa domanda.
Doc Brown,

1

Se è necessario modificare la classe per modificare il valore fiscale, il suo design sta effettivamente violando OCP. Il design appropriato, per quello che hai descritto finora, è che la classe calcolatrice prenda il valore fiscale come parametro.

Se la tua classe è istanziata (nel senso che non è una classe statica), rendendo la proprietà della classe variabile fiscale, il cui valore viene iniettato attraverso il costruttore, migliorerai anche la coesione della classe.

In breve, il tuo progetto attuale fa sì che la tua classe dipenda da un valore costante che non è in realtà una costante (che definisce la costante come un valore che non cambierebbe mai, come il valore di PI). Viola OCP. Modificare il progetto per ricevere il valore fiscale come argomento del costruttore.


0

Totalmente d'accordo con @Becuzz, e voglio solo riassumere questo: OCP riguarda la ricerca di astrazioni riutilizzate (quindi utili) che vengono iniettate in una classe. Quindi il comportamento della classe viene modificato non cambiando il suo codice, ma fornendo diverse implementazioni. Ciò è chiarissimo nel libro di Robert Martin " Sviluppo software agile, principi, schemi e pratiche ", controlla il capitolo corrispondente "Il principio aperto-chiuso", sotto-capitolo "L'astrazione è la chiave". Chiarisce un altro malinteso secondo cui il comportamento può essere modificato solo con l'eredità. Fu Bertrand Meyer a proporlo nel 1988 nel suo libro " Object Oriented Software Construction ", non Robert Martin.


-2

Per come la vedo io non è una violazione del principio aperto chiuso. Tuttavia, il fatto che qualcosa che è destinato a cambiare nel tempo (come la percentuale fiscale) è una costante è un difetto di progettazione: non si deve cambiare il valore della costante ma come si gestisce la percentuale fiscale. Questo dovrebbe essere un tipo di impostazione che potrebbe essere modificata senza ricompilare il tutto.


Il "difetto di progettazione" è che sta violando il principio aperto chiuso in quanto è necessario ricompilare il codice per modificare la costante?
Erdrik Ironrose,
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.