Perché abbiamo bisogno di così tante classi nei modelli di progettazione?


209

Sono uno sviluppatore junior tra gli anziani e sto lottando molto per capire il loro pensiero, ragionamento.

Sto leggendo Domain-Driven Design (DDD) e non riesco a capire perché dobbiamo creare così tante classi. Se seguiamo quel metodo di progettazione del software finiremo con 20-30 classi che possono essere sostituite con al massimo due file e 3-4 funzioni. Sì, questo potrebbe essere disordinato, ma è molto più gestibile e leggibile.

Ogni volta che voglio vedere cosa fa un qualche tipo EntityTransformationServiceImpl, devo seguire molte classi, interfacce, le loro chiamate di funzione, i costruttori, la loro creazione e così via.

Matematica semplice:

  • 60 righe di codice fittizio vs 10 classi X 10 (diciamo che abbiamo logiche totalmente diverse tra loro) = 600 righe di codice disordinato rispetto a 100 classi + alcune in più per avvolgerle e gestirle; non dimenticare di aggiungere l'iniezione di dipendenza.
  • Lettura di 600 righe di codice disordinato = un giorno
  • 100 lezioni = una settimana, dimentica ancora quale fa cosa, quando

Tutti dicono che è facile da mantenere, ma per cosa? Ogni volta che aggiungi nuove funzionalità, aggiungi altre cinque classi con fabbriche, entità, servizi e valori. Sento che questo tipo di codice si muove molto più lentamente del codice disordinato.

Diciamo, se si scrive 50K LOC codice disordinato in un mese, la cosa DDD richiede molte recensioni e modifiche (non mi dispiace test in entrambi i casi). Un'aggiunta semplice può richiedere una settimana se non di più.

In un anno, scrivi un sacco di codice disordinato e puoi persino riscriverlo più volte, ma con lo stile DDD, non hai ancora abbastanza funzionalità per competere con il codice disordinato.

Spiega per favore. Perché abbiamo bisogno di questo stile DDD e molti modelli?

UPD 1 : Ho ricevuto così tante risposte fantastiche, potete per favore aggiungere un commento da qualche parte o modificare la vostra risposta con il link per leggere l'elenco (non sono sicuro da dove cominciare, DDD, Design Patterns, UML, Code Complete, Refactoring, Pragmatic,. .. tanti buoni libri), ovviamente con sequenza, in modo che io possa anche iniziare a capire e diventare senior come alcuni di voi.


81
Penso che ci sia una buona domanda qui, ma si nasconde dietro l'iperbole e la frustrazione. @ user1318496, potresti trarre vantaggio dal riformulare un po 'la tua domanda.
MetaFight,

48
A rischio di calpestare le dita dei piedi, perché la tua lingua fa schifo. Non prenderlo per più di quello che è: un linguaggio sucky è spesso la scelta tecnica corretta per una serie di motivi, ma ciò non lo rende non-sucky. Per quanto riguarda la tua vera domanda, la correttezza è più importante della leggibilità. O per dirla in modo leggermente diverso: la leggibilità conta in quanto consente il ragionamento sulla correttezza. Quindi, qual è più facile da testare, le tue 100 classi o la tua classe monolitica divina? Scommetto 100 classi semplici.
Jared Smith,

87
"Sì, questo potrebbe essere disordinato, ma è molto più gestibile e leggibile.". Se è disordinato, come può essere leggibile e mantenibile?
Polygnome,

37
@Polygnome: stavo per scrivere lo stesso identico commento. Un altro commento di scelta caratteristica degli sviluppatori junior è "Sento che questo tipo di codice si muove molto più lentamente del codice disordinato". Non ti va di correre più veloce che puoi se passi metà del tuo tempo a correre contro i muri! Lento è liscio, liscio è veloce.
Eric Lippert,

40
No, a meno che tu non stia facendo Java. Quando tutto ciò che hai è Java, tutto sembra una classe.
Hobbs

Risposte:


336

Questo è un problema di ottimizzazione

Un bravo ingegnere comprende che un problema di ottimizzazione non ha senso senza un obiettivo. Non puoi semplicemente ottimizzare, devi ottimizzare per qualcosa. Ad esempio, le opzioni del compilatore includono l'ottimizzazione per la velocità e l'ottimizzazione per la dimensione del codice; questi a volte sono obiettivi opposti.

Mi piace dire a mia moglie che la mia scrivania è ottimizzata per le aggiunte. È solo un mucchio ed è molto facile aggiungere cose. Mia moglie lo preferirebbe se ottimizzassi per il recupero, cioè organizzavo un po 'le mie cose in modo da poter trovare le cose. Questo rende più difficile, ovviamente, aggiungere.

Il software è allo stesso modo. Puoi sicuramente ottimizzare per la creazione del prodotto: generare una tonnellata di codice monolitico il più rapidamente possibile, senza preoccuparti di organizzarlo. Come hai già notato, questo può essere molto, molto veloce. L'alternativa è ottimizzare per la manutenzione: rendere la creazione un tocco più difficile, ma rendere le modifiche più facili o meno rischiose. Questo è lo scopo del codice strutturato.

Vorrei suggerire che un prodotto software di successo verrà creato solo una volta ma modificato molte, molte volte. Ingegneri esperti hanno visto basi di codice non strutturate prendere una vita propria e diventare prodotti, crescendo in dimensioni e complessità, fino a quando anche piccole modifiche sono molto difficili da fare senza introdurre rischi enormi. Se il codice fosse strutturato, il rischio può essere contenuto. Ecco perché andiamo a tutti questi problemi.

La complessità deriva dalle relazioni, non dagli elementi

Ho notato nella tua analisi che stai osservando le quantità: quantità di codice, numero di classi, ecc. Mentre questi sono in qualche modo interessanti, il vero impatto deriva dalle relazioni tra gli elementi, che esplodono in modo combinatorio. Ad esempio, se hai 10 funzioni e non hai idea di quale dipende da quali, hai 90 possibili relazioni (dipendenze) di cui ti devi preoccupare: ognuna delle dieci funzioni potrebbe dipendere da una qualsiasi delle altre nove funzioni e 9 x 10 = 90. Potresti non avere idea di quali funzioni modificano quali variabili o in che modo vengono trasmessi i dati, quindi i programmatori hanno un sacco di cose di cui preoccuparsi quando risolvono un particolare problema. Al contrario, se hai 30 classi ma sono organizzate in modo intelligente, possono avere fino a 29 relazioni, ad esempio se sono stratificate o disposte in una pila.

In che modo ciò influisce sul rendimento della tua squadra? Bene, ci sono meno dipendenze, il problema è molto più trattabile; i programmatori non devono destreggiarsi tra mille miliardi di cose ogni volta che fanno un cambiamento. Quindi ridurre al minimo le dipendenze può essere di grande aiuto per la tua capacità di ragionare su un problema con competenza. Questo è il motivo per cui dividiamo le cose in classi o moduli, e le variabili dell'ambito il più strettamente possibile e utilizziamo i principi SOLID .


103
Vorrei notare, tuttavia, che una sovrabbondanza di classi e di riferimenti indiretti NON aiuta a comprendere la manutenzione del NOR. E nemmeno i flussi di controllo contorti (alias, callback hell).
Matthieu M.

9
@JohnWu questa spiegazione è la migliore e più facile da capire quella che io abbia mai letto.
Adriano Repetti,

13
Ben scritto, ma forse manca perché "creato una volta ma modificato molte, molte volte" è importante? (Se tutto il codice è inserito EntityTransformationServiceImpl, sei costretto a imparare come funziona tutto prima di poterlo riparare - ma se ad esempio qualcosa non va nel formato e una Formatterclasse lo gestisce, devi solo imparare come funziona quella parte . leggere il proprio codice dopo ~ 3 mesi è come leggere il codice di uno sconosciuto.) Sento che la maggior parte di noi inconsciamente ci abbia pensato, ma potrebbe essere a causa dell'esperienza. Non ne sono sicuro al 100%.
R. Schmitz,

17
Preferirei l'intero 10 × 10 = 100 per il combinatorio: quelle funzioni potrebbero essere ricorsive, e in un codice particolarmente scarso, non necessariamente ovviamente.
KRyan,

32
"L'alternativa è ottimizzare per la manutenzione: rendere la creazione un tocco più difficile, ma rendere le modifiche più facili o meno rischiose. Questo è lo scopo del codice strutturato." Metto in dubbio l'idea implicita che più classi = più manutenibilità. In particolare, la logica di scattering in molte classi spesso rende difficile trovare i concetti logici generali nel codice (specialmente senza un occhio molto intenzionale nel garantire che i concetti siano molto visibili), il che degrada enormemente la manutenibilità.
jpmc26,

67

Bene, prima di tutto, la leggibilità e la manutenibilità sono spesso negli occhi di chi guarda.

Ciò che è leggibile per te potrebbe non essere per il tuo vicino.

La manutenibilità si riduce spesso alla rilevabilità (la facilità con cui un comportamento o un concetto viene scoperto nella base di codice) e la rilevabilità è un'altra cosa soggettiva.

DDD

Uno dei modi in cui DDD aiuta i team di sviluppatori è suggerendo un modo specifico (ma ancora soggettivo) di organizzare concetti e comportamenti del codice. Questa convenzione semplifica la scoperta di cose e quindi la manutenzione dell'applicazione.

  • I concetti di dominio sono codificati come entità e aggregati
  • Il comportamento del dominio risiede in Entità o Servizi di dominio
  • La coerenza è garantita dalle radici aggregate
  • I problemi di persistenza sono gestiti dai repository

Questa disposizione non è oggettivamente più facile da mantenere. E ', tuttavia, misurabile più facile da mantenere quando tutti capiscono che stanno operando in un contesto DDD.

Classi

Le lezioni aiutano con manutenibilità, leggibilità, rilevabilità, ecc ... perché sono una convenzione ben nota .

Nelle impostazioni orientate agli oggetti, le classi vengono generalmente utilizzate per raggruppare comportamenti strettamente correlati e incapsulare lo stato che deve essere controllato attentamente.

So che sembra molto astratto, ma puoi pensarci in questo modo:

Con Classes, non devi necessariamente sapere come funziona il codice in esse. Devi solo sapere di cosa è responsabile la classe.

Le lezioni ti consentono di ragionare sulla tua applicazione in termini di interazioni tra componenti ben definiti .

Ciò riduce il carico cognitivo quando si ragiona su come funziona l'applicazione. Invece di dover ricordare cosa compiono 600 righe di codice , puoi pensare a come interagiscono 30 componenti .

E, considerando quei 30 componenti probabilmente si estendono su 3 livelli dell'applicazione, probabilmente ognuno deve ragionare su circa 10 componenti alla volta.

Sembra abbastanza gestibile.

Sommario

In sostanza, quello che stai vedendo fare dagli sviluppatori senior è questo:

Stanno suddividendo l'applicazione in motivi facili da ragionare sulle classi.

Quindi li stanno organizzando in livelli facili da ragionare .

Lo stanno facendo perché sanno che, man mano che l'applicazione cresce, diventa sempre più difficile ragionare su di essa nel suo insieme. Suddividendolo in livelli e classi significa che non devono mai ragionare sull'intera applicazione. Hanno sempre e solo bisogno di ragionare su un piccolo sottoinsieme di esso.


5
Inoltre le classi più piccole sono più facili da sostituire / refactor.
Zalomon,

12
L'ingegnerizzazione eccessiva non fornisce un codice più gestibile o comprensibile, al contrario, nonostante ciò che affermi. Chi ha bisogno di un AddressServiceRepositoryProxyInjectorResolverquando puoi risolvere il problema in modo più elegante? I modelli di progettazione per motivi di modelli portano solo a complessità e verbosità inutili.
vikingsteve,

27
Sì, l'ingegnerizzazione eccessiva è negativa. Così sta uccidendo i cuccioli. Nessuno qui sta sostenendo per entrambi. logicallyfallacious.com/tools/lp/Bo/LogicalFallacies/169/...
MetaFight

5
Inoltre, "eleganza" nel contesto dell'ingegneria del software è spesso una parola Weasel. en.wikipedia.org/wiki/Weasel_word
MetaFight

11
Lo stesso si può dire di qualsiasi approccio all'organizzazione del codice. Tutto dipende dal team di manutenzione che comprende perché il codice è organizzato così com'è. Questo è il punto centrale dell'uso di convenzioni ben consolidate e comprese.
MetaFight,

29

Per favore, spiegami, perché abbiamo bisogno di questo stile DDD, molti Pattern?

Innanzitutto, una nota: la parte importante di DDD non sono gli schemi , ma l'allineamento dello sforzo di sviluppo con il business. Greg Young ha osservato che i capitoli del libro blu sono nell'ordine sbagliato .

Ma alla tua domanda specifica: ci sono molte più classi di quanto ti aspetteresti, (a) perché si sta facendo uno sforzo per distinguere il comportamento del dominio dall'impianto idraulico e (b) perché si sta facendo uno sforzo supplementare per garantire che i concetti nel modello di dominio sono espressamente espressi.

Senza mezzi termini, se hai due concetti diversi nel dominio, allora dovrebbero essere distinti nel modello anche se capita di condividere lo stesso nella rappresentazione della memoria .

In effetti, stai costruendo un linguaggio specifico di dominio che descriva il tuo modello nella lingua dell'azienda, in modo tale che un esperto di dominio dovrebbe essere in grado di guardarlo e individuare errori.

Inoltre, vedi un po 'più di attenzione alla separazione delle preoccupazioni; e l'idea di isolare i consumatori di alcune capacità dai dettagli di attuazione. Vedi DL Parnas . I confini chiari ti consentono di modificare o estendere l'implementazione senza che gli effetti si increspino nell'intera soluzione.

La motivazione qui: per un'applicazione che fa parte della competenza principale di un'azienda (ovvero un luogo in cui deriva un vantaggio competitivo), vorrai essere in grado di sostituire facilmente ed economicamente un comportamento di dominio con una variazione migliore. In effetti, hai parti del programma che vuoi evolvere rapidamente (come lo stato si evolve nel tempo) e altre parti che vuoi cambiare lentamente (come lo stato viene memorizzato); gli strati extra di astrazione aiutano a evitare l'accoppiamento involontario tra loro.

In tutta onestà: in parte è anche un danno cerebrale orientato agli oggetti. Gli schemi originariamente descritti da Evans si basano su progetti Java a cui ha partecipato più di 15 anni fa; lo stato e il comportamento sono strettamente associati in quello stile, il che porta a complicazioni che potresti preferire evitare; vedi Perception and Action di Stuart Halloway o Inlining Code di John Carmack.

Indipendentemente dal linguaggio in cui lavori, la programmazione in uno stile funzionale offre vantaggi. Dovresti farlo ogni volta che è conveniente e dovresti riflettere molto sulla decisione quando non è conveniente. Carmack, 2012


2
Stavo per aggiungere la mia risposta fino a quando non ho letto questo. Vorrei sottolineare il primo paragrafo, che l'obiettivo è quello di modellare i concetti di business nel software per allineare il software con i requisiti aziendali. In tutta onestà, l'analista che guida il progetto dovrebbe anche esprimere la quantità di tempo del conducente alla consegna, e la qualità o completezza del codice / test dovrebbe essere adattata di conseguenza.
Sentinel

1
John Carmack è un ottimo esempio di IMO, dal momento che è ben noto per la scrittura di codice che è allo stesso tempo pulito e facile da capire, ma anche con buone prestazioni. Ciò è particolarmente visibile mentre traccia il suo codice con tecnologie avanzate: con CPU e memoria migliori, puoi vedere molte cose spinte da "questo deve essere davvero conciso" a "questo deve essere davvero chiaro / isolato / ... ". Uno dei programmatori più pragmatici che conosco :)
Luaan,

Penso che questa sia la migliore risposta qui. Anche se non sono in alcun modo venduto su DDD, questa risposta spiega almeno quello che è realmente e una motivazione reale per esso, piuttosto che fare appello a banalità comuni che non significano nulla.
jpmc26,

29

Ci sono molti punti positivi nelle altre risposte, ma penso che manchino o non sottolineino un importante errore concettuale che commetti:

Stai confrontando gli sforzi per comprendere il programma completo.

Questo non è un compito realistico con la maggior parte dei programmi. Anche i programmi semplici sono costituiti da così tanto codice che è semplicemente impossibile gestirli tutti in testa in un dato momento. La tua unica possibilità è trovare la parte di un programma che è rilevante per l'attività in corso (correggere un bug, implementare una nuova funzionalità) e lavorare con quello.

Se il tuo programma è composto da enormi funzioni / metodi / classi, questo è quasi impossibile. Dovrai capire centinaia di righe di codice solo per decidere se questo blocco di codice è rilevante per il tuo problema. Con le stime che hai dato diventa facile passare una settimana solo per trovare il pezzo di codice su cui devi lavorare.

Confrontalo con una base di codice con piccole funzioni / metodi / classi denominate e organizzate in pacchetti / spazi dei nomi che rendono ovvio dove trovare / inserire un dato pezzo di logica. Se fatto correttamente in molti casi, puoi saltare direttamente al posto giusto per risolvere il tuo problema, o almeno in un posto da cui accendere il debugger ti porterà nel posto giusto in un paio di salti.

Ho lavorato in entrambi i tipi di sistemi. La differenza può essere facilmente di due ordini di grandezza nelle prestazioni per attività comparabili e dimensioni del sistema comparabili.

L'effetto che ciò ha su altre attività:

  • il test diventa molto più semplice con unità più piccole
  • meno conflitti di unione perché le possibilità per due sviluppatori di lavorare sullo stesso pezzo di codice sono minori.
  • meno duplicazione perché è più facile riutilizzare i pezzi (e trovarli in primo luogo).

19

Perché testare il codice è più difficile della scrittura del codice

Molte risposte hanno fornito buoni ragionamenti dal punto di vista dello sviluppatore: la manutenzione può essere ridotta, a costo di rendere il codice più faticoso da scrivere in primo luogo.

Tuttavia, c'è un altro aspetto da considerare: i test possono essere solo dettagliati come il codice originale.

Se scrivi tutto in un monolite, l'unico test efficace che puoi scrivere è "dati questi input, l'output è corretto?". Questo significa che tutti i bug trovati, sono mirati a "da qualche parte in quel gigantesco mucchio di codice".

Naturalmente, puoi quindi far sedere uno sviluppatore con un debugger e trovare esattamente dove è iniziato il problema e lavorare su una correzione. Questo richiede molte risorse ed è un cattivo uso del tempo di uno sviluppatore. Immagina che ogni bug minore che hai, provochi uno sviluppatore che deve eseguire nuovamente il debug dell'intero programma.

La soluzione: molti test più piccoli che individuano uno specifico, potenziale fallimento ciascuno.

Questi piccoli test (ad esempio Test di unità) hanno il vantaggio di controllare un'area specifica della base di codice e di aiutare a trovare errori in un ambito limitato. Questo non solo accelera il debug quando un test fallisce, ma significa anche che se tutti i tuoi piccoli test falliscono, puoi trovare più facilmente l'errore nei tuoi test più grandi (cioè se non si trova in una specifica funzione testata, deve essere nell'interazione tra loro).

Come dovrebbe essere chiaro, rendere i test più piccoli significa che la tua base di codice deve essere divisa in blocchi più piccoli testabili. Il modo per farlo, su una base di codice commerciale di grandi dimensioni, spesso porta a un codice simile a quello con cui stai lavorando.

Proprio come una nota a margine: questo non vuol dire che le persone non porteranno le cose "troppo lontano". Ma c'è un motivo legittimo per separare le basi di codice in parti più piccole / meno connesse, se fatto in modo ragionevole.


5
Mentre la tua risposta riguarda solo i test e la testabilità, questo è il problema più importante che alcune delle altre risposte hanno completamente ignorato, quindi +1.
skomisa,

17

Per favore, spiegami, perché abbiamo bisogno di questo stile DDD, molti Pattern?

Molti (molti ...) di noi non ne hanno davvero bisogno . Teorici e programmatori esperti molto avanzati scrivono libri su teorie e metodologie come risultato di molte ricerche e della loro profonda esperienza - ciò non significa che tutto ciò che scrivono sia applicabile a tutti i programmatori nella loro pratica quotidiana.

Come sviluppatore junior, è bene leggere libri come quello che hai menzionato per ampliare le tue prospettive e renderti consapevole di alcuni problemi. Ti eviterà anche di essere imbarazzato e confuso quando i tuoi colleghi senior usano una terminologia con cui non hai familiarità. Se trovi qualcosa di molto difficile e non sembra avere senso o sembrare utile, non ucciderti su di esso - basta archiviarlo nella tua testa che ci sia un tale concetto o approccio.

Nel tuo sviluppo quotidiano, a meno che tu non sia un accademico, il tuo compito è trovare soluzioni praticabili e sostenibili. Se le idee che trovi in ​​un libro non ti aiutano a raggiungere questo obiettivo, non preoccuparti in questo momento, purché il tuo lavoro sia ritenuto soddisfacente.

Potrebbe venire un momento in cui scoprirai che puoi usare parte di ciò che leggi ma che all'inizio non hai "capito", o forse no.


12
Mentre a un livello puro questo è corretto sembra DDD e altri Patterns sono solo teoria. Non lo sono. Sono strumenti importanti per ottenere codice leggibile e gestibile.
Jens Schauder,

9
@PeteKirkham il dilemma dei PO è l' uso eccessivo di modelli di progettazione. Hai davvero bisogno di un AccountServiceFacadeInjectResolver(vero esempio che ho appena trovato in un sistema al lavoro) - probabilmente la risposta è no.
vikingsteve,

4
@vikingsteve OP non è un guru della programmazione che commenta l'abuso generale di modelli di progettazione. OP è un apprendista e pensa di essere abusato nel suo negozio . So che il principiante-me avrebbe pensato lo stesso del codice che scrivo oggi, ma il principiante-me ha avuto molti progetti personali falliti perché sono finiti troppo contorti.
R. Schmitz,

3
@ R.Schmitz Detto questo, il principiante ha avuto molti progetti personali falliti perché hanno cercato troppo duramente di rendere le cose ben progettate, organizzate, strutturate, OOP ... Tutti questi sono strumenti. Devono essere capiti e usati correttamente e difficilmente si può incolpare il martello per essere povero nell'avvitamento. Sorprendentemente, ci vuole molta comprensione ed esperienza per capire questa cosa semplice :)
Luaan,

3
@Luaan Se ti prendessi già cura di OOP ben progettato, organizzato, strutturato, difficilmente chiamerei quel principiante, ma sì, l'abuso è male. Tuttavia, la domanda è di più su come l'OP non capisca realmente quali problemi risolvono queste cose. Se non conosci il motivo, sembra che non ci sia alcun motivo, ma in realtà non lo sai ancora.
R. Schmitz,

8

Poiché la tua domanda copre molto terreno, con molte ipotesi, selezionerò l'argomento della tua domanda:

Perché abbiamo bisogno di così tante classi nei modelli di progettazione

Noi non. Non esiste una regola generalmente accettata che dice che ci devono essere molte classi nei modelli di progettazione.

Esistono due guide chiave per decidere dove inserire il codice e come suddividere le attività in diverse unità di codice:

  • Coesione: qualsiasi unità di codice (sia esso un pacchetto, un file, una classe o un metodo) dovrebbe appartenere insieme . Cioè, qualsiasi metodo specifico dovrebbe avere un compito e farlo bene. Ogni classe dovrebbe essere responsabile di un argomento più ampio (qualunque esso sia). Vogliamo alta coesione.
  • Accoppiamento: ogni due unità di codice dovrebbe dipendere il meno possibile l'una dall'altra - in particolare non dovrebbero esserci dipendenze circolari. Vogliamo un accoppiamento basso.

Perché quei due dovrebbero essere importanti?

  • Coesione: un metodo che fa molte cose (ad es. Uno script CGI vecchio stile che fa GUI, logica, accesso a DB ecc. Tutto in un lungo pasticcio di codice) diventa ingombrante. Al momento della stesura, è allettante mettere il treno del pensiero in un metodo lungo. Funziona, è facile da presentare e così, e puoi farcela. I problemi sorgono più tardi: dopo alcuni mesi, potresti dimenticare quello che hai fatto. Una riga di codice in alto potrebbe trovarsi a poche schermate da una riga in basso; è facile dimenticare tutti i dettagli. Qualsiasi modifica in qualsiasi parte del metodo può interrompere qualsiasi quantità di comportamenti della cosa complessa. Sarà piuttosto complicato rifattorizzare o riutilizzare parti del metodo. E così via.
  • Accoppiamento: ogni volta che modifichi un'unità di codice, potenzialmente rompi tutte le altre unità che dipendono da essa. In linguaggi rigorosi come Java, potresti ricevere suggerimenti durante il tempo di compilazione (ad es. Su parametri, eccezioni dichiarate e così via). Ma molti cambiamenti non stanno innescando tali (cioè cambiamenti comportamentali) e altri linguaggi più dinamici non hanno tali possibilità. Maggiore è l'accoppiamento, più difficile diventa cambiare qualcosa e potresti fermarti, dove è necessaria una riscrittura completa per raggiungere qualche obiettivo.

Questi due aspetti sono i "driver" di base per qualsiasi scelta di "dove mettere cosa" in qualsiasi linguaggio di programmazione e qualsiasi paradigma (non solo OO). Non tutti sono esplicitamente consapevoli di loro e ci vuole tempo, spesso anni, per avere una sensazione davvero radicata e automatica su come questi software influenzano.

Ovviamente, questi due concetti non ti dicono nulla su cosa fare realmente . Alcune persone sbagliano sul lato di troppo, altre sul lato di troppo poco. Alcune lingue (che ti guardano qui, Java) tendono a favorire molte classi a causa della natura estremamente statica e pedante del linguaggio stesso (questa non è una dichiarazione di valore, ma è quello che è). Ciò diventa particolarmente evidente quando lo confronti con linguaggi dinamici e più espressivi, ad esempio Ruby.

Un altro aspetto è che alcune persone sottoscrivono l'approccio agile della sola scrittura del codice che è necessario in questo momento , e di rifattorizzare pesantemente in seguito, quando necessario. In questo stile di sviluppo, non si creerebbe un interfacequando si dispone di una sola classe di implementazione. Dovresti semplicemente implementare la classe concreta. Se, in seguito, avessi bisogno di una seconda classe, rifaresti.

Alcune persone semplicemente non funzionano in questo modo. Creano interfacce (o, più in generale, classi base astratte) per qualsiasi cosa che possa mai essere usata più in generale; questo porta a un'esplosione di classe rapidamente.

Ancora una volta, ci sono argomenti a favore e contro, e non importa quale io o te preferiamo. Nella tua vita come sviluppatore di software, incontrerai tutti gli estremi, dai lunghi metodi di spaghetti, attraverso progetti di classe illuminati, appena abbastanza grandi, fino a schemi di classe incredibilmente esplosi che sono molto riprogettati. Man mano che diventerai più esperto, diventerai sempre più un ruolo "architettonico" e potrai iniziare a influenzarlo nella direzione che desideri. Scoprirai un mezzo d'oro per te stesso e scoprirai ancora che molte persone non saranno d'accordo con te, qualunque cosa tu faccia.

Quindi, mantenere una mente aperta è la parte più importante, qui, e questo sarebbe il mio consiglio principale per te, visto che sembri avere molto dolore per la questione, a giudicare dal resto della tua domanda ...


7

I programmatori esperti hanno imparato:

  • Perché quei programmi piccoli e il clasess iniziano a crescere, soprattutto quelli di successo. I semplici schemi che funzionavano a un livello semplice non si ridimensionano.
  • Perché può sembrare gravoso dover aggiungere / modificare diversi artefatti per ogni aggiunta / modifica, ma sai cosa aggiungere ed è facile farlo. 3 minuti di battitura a macchina 3 ore di programmazione intelligente.
  • Molte piccole classi non sono "disordinate" solo perché non capisci perché l'overhead sia in realtà una buona idea
  • Senza la conoscenza del dominio aggiunta, il codice "ovvio per me" è spesso misterioso per i miei compagni di squadra ... oltre al futuro me.
  • La conoscenza tribale può rendere i progetti incredibilmente difficili da aggiungere ai membri del team in modo facile e difficile affinché possano essere rapidamente produttivi.
  • La denominazione è uno dei due problemi più difficili nell'informatica è ancora vero e molte classi e metodi sono spesso un intenso esercizio di denominazione che molti trovano essere un grande vantaggio.

5
Ma è necessario il sovraccarico? In molti casi che vedo, i modelli di progettazione sono abusati. Il risultato dell'eccessiva complessità sono le maggiori difficoltà a comprendere, mantenere, testare e eseguire il debug del codice. Quando hai 12 classi e 4 moduli Maven attorno a una semplice classe di servizio (un vero esempio che ho appena visto), diventa rapidamente meno gestibile di quanto potresti pensare.
vikingsteve,

4
@vikingsteve Continui a fare riferimento a un singolo esempio di un'implementazione errata nella speranza che ciò provi che il codice strutturato, in generale, è una cattiva idea. Questo non tiene traccia.
MetaFight,

2
@MetaFight OP non sta parlando del codice della struttura. Sta parlando di ciò che vede come troppe astrazioni. Se hai troppe astrazioni, sostengo, otterrai rapidamente codice molto non strutturato e molti pezzi quasi identici, semplicemente perché le persone non riescono a far fronte alla quantità di cose che devono affrontare.
Più chiaro il

4
@Clearer Sono abbastanza sicuro che tutti qui siano d'accordo sul fatto che l'ipotetica errata applicazione del codice strutturato sia una cosa negativa. L'OP dice che sono Junior. Ecco perché le persone presumono che non abbia familiarità con i vantaggi del codice strutturato e che li ripetano.
MetaFight,

2

Le risposte finora, tutte buone, essendo iniziate con il ragionevole presupposto che al richiedente manca qualcosa, che anche il richiedente riconosce. È anche possibile che il richiedente abbia fondamentalmente ragione, e vale la pena discutere di come questa situazione possa verificarsi.

L'esperienza e la pratica sono potenti e se gli anziani acquisiscono la loro esperienza in progetti grandi e complessi in cui l'unico modo per tenere le cose sotto controllo è con un sacco di cose EntityTransformationServiceImpl, allora diventano veloci e a proprio agio con i modelli di progettazione e la stretta aderenza al DDD. Sarebbero molto meno efficaci usando un approccio leggero, anche per piccoli programmi. Come quello strano, dovresti adattarti e sarà una grande esperienza di apprendimento.

Mentre ti stai adattando, dovresti prenderlo come una lezione sull'equilibrio tra l'apprendimento profondo di un singolo approccio, al punto da poterlo far funzionare ovunque, piuttosto che rimanere versatile e sapere quali strumenti sono disponibili senza necessariamente essere un esperto con nessuno di essi. Ci sono vantaggi per entrambi ed entrambi sono necessari nel mondo.


-4

Rendere più classe e funzione secondo l'uso sarà un ottimo approccio per risolvere i problemi in un modo specifico che aiuterà in futuro a risolvere eventuali problemi.

Più classi aiutano a identificarsi come il loro lavoro di base e qualsiasi classe può essere chiamata in qualsiasi momento.

Tuttavia, se hai molte classi e funzioni dal loro nome ottenibile, sono facili da chiamare e gestire. Questo si chiama codice pulito.


9
Scusa, ma cosa stai dicendo?
Deduplicatore

@Deduplicator facciamo un esempio in java se progettiamo di usare thread e classi jframes per la loro eredità. Da una sola classe non siamo in grado di utilizzare alcune opere di java per la progettazione, quindi abbiamo bisogno di fare più lezioni
Sanjeev Chauhan

2
Questa risposta deve presentare l'idea / i che pretende di presentare in un inglese più chiaro. Sembra che l'idea alla base della risposta sia che classi più piccole, ognuna con una funzionalità ben definita, siano una buona idea, ma la terribile grammatica rende quasi impossibile la comprensione. Inoltre, di per sé, questa affermazione potrebbe non essere sufficiente.
Talonx,
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.