Following Open Closed Principle

3

Cerco di scrivere "codice pulito" per la maggior parte del tempo. Ma praticamente lo trovano molto difficile, il che significa - graduali esigenze aziendali cambiano drasticamente o requisiti aziendali che sembrano solo una forza condizionale per modificare il codice esistente.

Se applichiamo l'approccio "estendere" invece di "modificare", l'implementazione sembra pulita. Ma sembra una gerarchia di classi molto ampia per casi d'uso che sembra semplice. Inoltre, a volte scrivendo poche righe di codice con "modifica" correggi il problema nel dato "Tempo" invece di scrivere poche serie di classi con un approccio "estendibile".

Come assicurarsi di mantenere il codice pulito non quando viene impiantato per la prima volta, ma pochi anni dopo la linea. In particolare quando il tempo è fondamentale e per le imprese i nuovi requisiti sono "SOLO un piccolo cambiamento".

    
posta Bhalchandra Kadam 21.12.2017 - 07:25
fonte

3 risposte

5

Non seguire il principio Open / Closed (OCP) a meno che non sia assolutamente necessario. Nella maggior parte dello sviluppo di applicazioni, l'OCP non è appropriato e porta solo a un codice eccessivamente complesso, come già notato.

L'OCP è appropriato in scenari in cui si hanno client esterni indipendenti che utilizzano il codice e si ha bisogno di evolvere il codice preservando la retrocompatibilità. Prendi il framework .net: MS non può semplicemente modificare il comportamento di un'API esistente nel framework, perché ciò interromperà tutto il client a seconda del comportamento corrente. Possono solo estendere l'API. L'OCP non porta in realtà a un codice pulito, ad esempio i framework hanno più API deprecate che non possono mai essere rimosse. Ma conserva la retrocompatibilità.

Un altro scenario è se si dispone di un'architettura "big-ball-of-mud" in cui ogni cambiamento può avere effetti collaterali imprevisti in tutto il sistema e nessun test automatizzato da proteggere dalle regressioni. In tal caso, puoi adottare una mentalità paranoica e mantenere il codice "chiuso" per evitare di rompere il codice esistente. Ma qui non modificare il codice è solo trattando i sintomi e non migliorerà di per sé la qualità del codice. Se possibile, dovresti preferire trattare la causa principale dei problemi.

Se non sei obbligato a seguire il principio OCP, spesso è più semplice e pulito modificare il comportamento piuttosto che estenderlo.

Come tutte le linee guida di programmazione, OC non è una regola universale, ma è appropriata solo in contesti specifici.

    
risposta data 21.12.2017 - 08:36
fonte
4

Ti aspetti che OCP ti impedisca di modificare il codice su tutte le modifiche aziendali? Quando i requisiti cambiano da "dammi un'applicazione che presterà bici" a "dammi un'applicazione che ruberà auto" nessuna regola ti salverà.

Quindi, perché dovremmo seguire l'OCP? Perché è utile? Penso che Strategy Pattern sia il modo più semplice per spiegare il potere dell'OCP. Consideriamo parte del sistema che calcola lo sconto per alcuni processi di vendita. Supponiamo che lo sconto dipenda dal valore dell'ordine e dall'utente che acquista (VIP, regolare ecc.). Un approccio è:

public calculateDiscount(Customer customer, Order order) {
    // some common part

    Discount d;

    if(customer.isVip(){
        d = // some code
    } else if(customer.isRegular()){
        d = // some code
    }
    // etc.

    // some common code
}

un altro:

public calculateDiscount(Customer customer, Order order) {
    // some common part

    DiscountPolicy dp = customer.getDiscountPolicy();
    Discount d = dp.calculateOn(order);

    // some common code

}

Che cosa succede se ci sarà un altro tipo di cliente? Il primo approccio ti obbliga a modificare il codice. Questo cambiamento interromperà il comportamento di calculateDiscount ? Sarai in grado di apportare modifiche senza introdurre errori? Lo so, in questo semplice esempio probabilmente sì;)

Ma ci sono molte parti del tuo sistema che già conosci o senti strongmente che saranno modificate o estese (non in termini di ereditarietà, ma nel senso di coprire altre sfumature di casi d'uso) in futuro. Devi impedire il codice dagli errori il più possibile. Uno dei metodi di tale prevenzione è non cambiare il codice che funziona . L'OCP non sta cambiando il codice che funziona. Strategia, Decoratore, Fabbrica astratta, Comando, ecc., I modelli riguardano solo il mantenimento di parte del codice in conformità con l'OCP.

Ovviamente, ci sono cambiamenti da cui non vieni impedito. L'aggiunta del requisito per calcolare lo sconto a seconda del tipo di mercato finirà anche nel cambiare il contratto e il codice all'interno del metodo calculateDiscount così come il codice dei test unitari e altri test che hai. È inevitabile Ma l'OCP ti dà la "zona di sgualcitura". Come nel mondo reale - dato che la zona di accartocciamento non è sempre sufficiente per i crash che incontriamo.

    
risposta data 22.12.2017 - 01:08
fonte
3

Seguire l'OCP dovrebbe essere sempre uno degli obiettivi di un programmatore OOP. Ignorare questo principio erode quanto è utile decomporsi in oggetti. È eccezionalmente pigro pensare: "Beh, se vogliono reagire al cambiamento possono semplicemente riscriverlo".

OCP ti chiede di favorire un design che permetta il cambiamento aggiungendo un nuovo codice piuttosto che cambiando il vecchio codice.

I meccanismi strutturali per questo possono essere complessi come un modello di progettazione o semplici come introdurre una variabile. L'astrazione funziona al meglio quando non riesci a vedere i dettagli che stai utilizzando.

Il problema più eloquente è quando ritieni opportuno separare un'idea da un'altra inserendole in oggetti diversi, ma l'UNO sa esattamente quale implementazione dell'altro sta parlando. Fare ciò non solo viola l'OCP, ma significa che hai digitato una classe extra senza una buona ragione. Se si separano le idee in oggetti diversi, non dovrebbero tenersi reciprocamente in una presa mortale.

Tuttavia, il cambiamento è difficile da prevedere. Yagni ci insegna a non creare cose che potrebbero essere utili, solo cose che sono utili oggi.

Piuttosto che predire il futuro, sii prudente quando si assume che qualcosa sarà stabile. Le nostre astrazioni di alto livello, le nostre interfacce, ci feriscono davvero quando cambiano. Mantenere ciò che assumono essere al minimo stabile. Spingi ciò che non sei sicuro di scendere ai livelli più bassi. Spezzali per mantenere la loro vulnerabilità a cambiare l'impronta di piccole dimensioni. Lascia che servano solo un master.

Fai questo e seguire l'OCP non dovrebbe essere troppo diverso. Se, però, impazzisci le interfacce su ogni oggetto e rifiuti di chiamare qualsiasi cosa che non sia polimorfica, beh, ci stai dando un pessimo nome ai codificatori di OOP.

Il miglior consiglio che potresti applicare qui era in realtà su quando reagire a una violazione di DRY. È molto più probabile che si decompongano correttamente la seconda volta che ti ripeti, quindi sei la prima volta. Quindi forse non essere così pronto a reagire.

Questa saggezza dovrebbe attenuare quanto sei veloce nel prevedere il cambiamento. I test unitari ci aiutano a vedere come possiamo modificare i dettagli di implementazione. Mentre questo è un buon test di unità di esercizi strutturali non è il codice di produzione. Stai attento a pensare che ti mostrano come cambieranno le cose.

Ma dovresti sentirti male ogni volta che aggiungi una funzione o correggi un bug modificando il codice esistente. Anche se in realtà non hai client esterni indipendenti, è davvero bello poter supportare grandi quantità di codice come se lo fosse.

Ricorda, questi principi non ti aiuteranno a far funzionare il tuo codice più velocemente. Ti aiutano a mantenere il tuo codice funzionante una volta fatto. Perciò non scoprirai se stai sprecando il tuo tempo facendo sforzi per seguirli fino a quando i cambiamenti cominciano ad arrivare. Se vuoi esercitarti ad applicarli, non puoi semplicemente codificare su una specifica fissa. Devi codificare su una specifica mutevole che ti sorprende.

Un modo conservativo per applicare questi principi è aggiungere complessità in reazione al cambiamento piuttosto che in previsione. Quando prenderò questo trattato mi perdonerò per aver dovuto cambiare il codice esistente in un modulo una volta, forse due volte. Dopodiché è il momento di vedere come impedire che accada di nuovo.

Altrimenti, potremmo anche tornare alla programmazione procedurale perché anche se è in grado di riscrivere ogni volta, può gestire il cambiamento.

    
risposta data 21.12.2017 - 17:00
fonte

Leggi altre domande sui tag