Domanda

Accoppiamento lasco è, per alcuni sviluppatori, il Santo Graal di software bene-costruito. E 'certamente una buona cosa quando si rende il codice più flessibile di fronte a cambiamenti che possono verificarsi in un prossimo futuro, o evita la duplicazione del codice.

D'altra parte, gli sforzi per componenti liberamente paio di aumentare la quantità di indirezione in un programma, aumentando così la sua complessità, spesso rendendo più difficile da capire e rendendo spesso meno efficiente.

Ti consideri un focus su accoppiamento lasco, senza casi di utilizzo per l'accoppiamento lasco (come ad esempio evitare la duplicazione del codice o di pianificazione per i cambiamenti che possono verificarsi in un prossimo futuro) di essere un anti-modello? Può perdere l'accoppiamento caduta sotto l'ombrello di YAGNI?

È stato utile?

Soluzione

Un po '.

A volte accoppiamento sciolto che viene senza troppo sforzo va bene, anche se non si dispone di specifici requisiti esigenti che qualche modulo essere disaccoppiato. Il low-hanging fruit, per così dire.

D'altra parte, overengineering per quantità ridicola di cambiamento sarà un sacco di complessità e sforzi inutili. YAGNI, come dici tu, lo colpisce sulla testa.

Altri suggerimenti

La pratica è la programmazione X bene o un male? Chiaramente, la risposta è sempre "dipende".

Se stai guardando il codice, chiedendosi cosa "pattern" è possibile iniettare, allora si sta facendo male.

Se si sta costruendo il vostro software in modo che gli oggetti estranei fanno in giro non violino con l'altro, allora si sta facendo bene.

Se stai "ingegneria" la soluzione in modo che possa essere infinitamente esteso e cambiato, allora si sta effettivamente rendendo più complicato.

Penso che alla fine della giornata, si è lasciato con la sola verità: è più o meno complicato di avere gli oggetti disaccoppiati? Se è meno complicato paio di loro, allora questa è la soluzione corretta. Se è meno complicato per disaccoppiare loro, allora questa è la soluzione giusta.

(Attualmente sto lavorando in un abbastanza piccola base di codice che fa un lavoro semplice in modo molto complicato, e parte di ciò che rende così complicata è la mancanza di comprensione dei termini "accoppiamento" e "coesione" da parte degli sviluppatori originali.)

Penso che quello che stai ricevendo in qui è il concetto di coesione . Questo codice ha uno scopo buono? Posso interiorizzare tale scopo e comprendere il "quadro generale" di quello che sta succedendo?

Si potrebbe portare a codice difficile da seguire, non solo perché ci sono molti file di origine più (ammesso che queste sono classi separate), ma perché nessuno singola classe sembra avere uno scopo.

Dal punto di vista agile, mi potrebbe suggerire che tale accoppiamento lasco sarebbe un anti-modello. Senza la coesione, o utilizzare anche i casi per esso, non è possibile scrivere unit test sensibili, e non possibile verificare lo scopo del codice. Ora, il codice agile può portare a perdere accoppiamento, per esempio quando si usa sviluppo test-driven. Ma se sono stati creati i test giusti, nel giusto ordine, allora è probabile che ci sia una buona coesione e accoppiamento lasco. E si sta parlando solo i casi in cui chiaramente non la coesione c'è.

Anche in questo caso dal punto di vista agile, non si vuole questo livello di indirezione artificiale perché è fatica sprecata su qualcosa che probabilmente non sarà necessario in ogni caso. E 'molto più facile da refactoring quando il bisogno è reale.

Nel complesso, si desidera ad alta accoppiamento entro i moduli, e accoppiamento lasco tra di loro. Senza l'alta accoppiamento, probabilmente non si dispone di coesione.

Per la maggior parte delle domande di questo tipo, la risposta è "dipende". Nel complesso, se posso fare un disegno logico debolmente accoppiati in modo che abbiano un senso, senza un grande testa a farlo, lo farò. Evitando inutili accoppiamento in codice è, a mio avviso, un obiettivo di progettazione del tutto utile.

Una volta che si tratta di una situazione in cui sembra che i componenti devono logicamente essere strettamente accoppiati, sarò alla ricerca di un argomento convincente prima di iniziare loro rottura.

Credo che il principio di lavoro che per la maggior parte di questi tipi di pratica è uno di inerzia. Ho un'idea di come vorrei il mio codice di lavoro e se posso farlo in questo modo, senza rendere la vita più dura, allora lo farò. Se facendo renderà sviluppo più difficile, ma la manutenzione e il futuro lavoro più facile cercherò di capire una congettura a se sarà più lavoro in tutto il ciclo di vita del codice e l'uso che, come la mia guida. Altrimenti sarebbe bisogno di essere un punto di progettazione deliberata di essere la pena di andare con.

La risposta è semplice accoppiamento lasco è buono quando fatto correttamente.

Se il principio di una funzione, uno scopo è seguita quindi dovrebbe essere abbastanza facile da seguire che cosa sta succedendo. Inoltre, il codice paio sciolto segue come una questione di corso, senza alcuno sforzo.

disegno semplici regole: 1. non costruiscono la conoscenza di più elementi in un unico punto (come sottolineato in tutto il mondo, dipende) a meno che non si sta costruendo un'interfaccia facciata. 2. una funzione - uno scopo (tale scopo può essere multiforme come in una facciata) 3. un modulo - una serie ben definita di funzioni interrelati - uno scopo chiaro 4. se non si può semplicemente prova di unità che allora non avere uno scopo semplice

Tutti questi commenti su più facile refactoring in seguito sono un carico di merluzzi. Una volta che la conoscenza viene costruita in tanti luoghi, in particolare nei sistemi distribuiti, il costo del refactoring, la sincronizzazione rollout, e quasi tutti gli altri colpi di costo è così lontano dalla considerazione che nella maggior parte dei casi, le estremità del sistema per essere cestinato a causa di esso.

La cosa triste di sviluppo del software in questi giorni è il 90% delle persone di sviluppare nuovi sistemi e non hanno alcuna capacità di comprendere i vecchi sistemi, e non sono mai in giro quando il sistema ha avuto modo di un cattivo stato di salute, quali a causa di un continuo refactoring di bit e pezzi.

Non importa quanto strettamente accoppiati una cosa è altro se quell'altra cosa non cambia mai. Ho trovato generalmente più produttivo nel corso degli anni a concentrarsi sulla ricerca di un minor numero di motivi per cambiare le cose, di cercare la stabilità, oltre a renderli più facili da cambiare, cercando di raggiungere la forma loosest di accoppiare possibile. Il disaccoppiamento che ho trovato per essere molto utile, al punto che a volte sono a favore del codice modesta la duplicazione di pacchetti DECOUPLE. Come esempio di base, ho avuto una scelta di usare la mia libreria matematica per implementare una libreria di immagini. Non solo e ho duplicato alcune funzioni matematiche di base che erano banali da copiare.

Ora la mia libreria di immagini è completamente indipendente dalla libreria matematica in un modo in cui non importa che tipo di cambiamenti che faccio alla mia matematica lib, non influenzerà la libreria di immagini. Questo è mettere prima di tutto la stabilità. La libreria di immagini è più stabile ora, come nell'avere drasticamente meno ragioni per il cambiamento, dal momento che è disaccoppiato da qualsiasi altra libreria che potrebbe cambiare (oltre alla libreria standard C che si spera non dovrebbero mai cambiare). Come bonus è anche facile da implementare, quando è solo una libreria autonoma che non richiede tirando in un mucchio di altre librerie per costruirlo e utilizzarlo.

La stabilità è molto utile per me. Ho come la costruzione di una collezione di codice ben collaudato che ha sempre meno motivi per cambiare mai in futuro. Questo non è un sogno irrealizzabile; Ho codice C Sto usando e usare di nuovo dal fine degli anni '80, che non è cambiato affatto da allora. E 'certamente roba di basso livello come il codice di pixel-oriented e la geometria correlata, mentre un sacco di mia roba di livello superiore è diventato obsoleto, ma è qualcosa che aiuta ancora molto da avere intorno. Ciò significa che quasi sempre una libreria che si basa su sempre meno cose, se nulla di esterno a tutti. L'affidabilità va su e se il vostro software dipende sempre più su basi stabili che trovano pochi o nessun motivo per cambiare. Meno parti mobili è veramente bello, anche se in pratica le parti in movimento sono molto più numerosi rispetto alle parti stabili. Aiuta ancora la mia sanità mentale molto da sapere che la totalità di una base di codice non consiste di parti in movimento.

Accoppiamento lasco è nella stessa vena, ma trovo spesso che accoppiamento lasco è molto meno stabile di quanto non accoppiamento. A meno che non si sta lavorando in team con progettisti di interfacce di gran lunga superiore e clienti che non cambiano la loro mente quanto io abbia mai lavorato, anche le interfacce puri spesso trovare ragioni per il cambiamento in modi che ancora provoca a cascata rotture tutto il codice. Questa idea che la stabilità può essere raggiunta indirizzando le dipendenze verso l'astratto, piuttosto che il calcestruzzo è utile solo se il design di interfaccia è più facile da ottenere per la prima volta intorno che l'attuazione. Spesso mi trovo invertita in cui uno sviluppatore potrebbe aver creato un ottimo, se non meraviglioso, implementazione dato i requisiti di progettazione hanno pensato che dovrebbero compiere, solo per trovare in futuro che i requisiti di progettazione cambiano completamente. Il design è molto più difficile da ottenere il diritto di implementazione, se mi chiedete con basi di codice su larga scala cercando di soddisfare le esigenze in continua evoluzione, e in quel caso la separazione disegni astratti da implementazioni concrete non aiuta più di tanto se il disegno astratto è la cosa che è più incline a essere cambiato.

Così come favorire la stabilità e completo disaccoppiamento in modo che posso almeno dire con fiducia: "Questa piccola biblioteca isolato che è stato usato per anni e garantiti da test approfonditi ha quasi nessuna probabilità di richiedere modifiche non importa ciò che accade nel caotico mondo esterno." Mi dà una piccola fetta di sanità mentale, non importa che tipo di modifiche di progettazione sono chiamati per la parte esterna.

accoppiamento e di stabilità, ECS Esempio

Mi piace anche i sistemi di entità componenti e introducono un sacco di accoppiamento stretto perché il sistema per le dipendenze dei componenti tutti access e manipolare direttamente i dati grezzi, in questo modo:

entrare descrizione dell'immagine qui

Tutte le dipendenze qui sono abbastanza stretti in quanto componenti di esporre solo i dati grezzi. Le dipendenze non scorrono verso astrazioni, stanno fluisce verso dati grezzi che significa che ogni sistema ha la massima quantità di conoscenza possible su ciascun tipo di componente essi richiesta di accesso. Components ha alcuna funzionalità di tutti i sistemi di accesso e manomissione dei dati grezzi. Tuttavia, è molto facile ragionare su un sistema come questo dal momento che è così piatto. Se una texture viene fuori irregolare, poi si sa con questo sistema subito che solo il rendering e la pittura componenti di struttura di accesso al sistema, e probabilmente si può rapidamente escludere il sistema di rendering in quanto legge solo dalla texture concettualmente.

Nel frattempo un'alternativa loosely coupled potrebbe essere questo:

entrare descrizione dell'immagine qui

... con tutte le dipendenze che scorre verso funzioni astratti, non i dati, e ogni singola cosa in quel diagramma esporre un'interfaccia pubblica e la funzionalità del proprio. Ecco tutte le dipendenze potrebbero essere molto sciolto. Gli oggetti non possano dipendere anche direttamente a vicenda e interagiscono tra loro attraverso interfacce puri. Ancora è molto difficile a causa di questo sistema, soprattutto se qualcosa va storto, dato il complesso groviglio di interazioni. Ci saranno anche più interazioni (più di accoppiamento, seppur perdente) rispetto al ECS perché le entità devono conoscere i componenti che aggregano, anche se sanno solo di ogni altra interfaccia public abstract.

Anche se ci sono modifiche di progettazione a tutto ciò, si ottiene più Cascading rotture rispetto alla ECS, e non ci saranno tipicamente più motivi e le tentazioni per modifiche di progetto in quanto ogni singola cosa sta cercando di fornire una bella interfaccia orientata agli oggetti e astrazione. Che viene subito con l'idea che ogni singolo piccola cosa cercherà di imporre vincoli e limitazioni alla progettazione, e questi vincoli sono spesso ciò che garantisce modifiche di progettazione. La funzionalità è molto più vincolato e deve fare tante ipotesi più di progettazione di dati grezzi.

Ho trovato, in pratica, il tipo di "flat" sistema ECS sopra per essere molto più facile ragionare su che persino i sistemi più loosely-coupled con una ragnatela complessa delle dipendenze sciolti e, cosa più importante per me, ho trovato così pochi motivi per la versione ECS al bisogno sempre di cambiare i componenti esistenti in quanto i componenti dipendevano non hanno alcuna responsabilità se non per fornire i dati appropriati necessari per i sistemi di operare. Confrontare la difficoltà di progettare un'interfaccia IMotion pura e movimento oggetto concreto attuazione di tale interfaccia che fornisce sofisticate funzionalità durante il tentativo di mantenere invarianti oltre i dati privati ??contro un componente di movimento che ha bisogno solo di fornire i dati grezzi rilevanti per risolvere il problema e non si preoccupa con la funzionalità.

La funzionalità è molto più difficile da ottenere rispetto ai dati, ed è per questo penso che sia spesso preferibile per dirigere il flusso delle dipendenze nei confronti dei dati. Dopo tutto, quante librerie vettore / matrice sono là fuori? Quanti di loro usano la stessa esatta rappresentazione dei dati e solo differiscono leggermente in termini di funzionalità? Innumerevoli, eppure abbiamo ancora tanti a dispetto di rappresentazioni di dati identici perché vogliamo sottili differenze di funzionalità. Quante librerie di immagini sono là fuori? Quanti di loro rappresentano pixel in un modo diverso e unico? Quasi nessuna, e ancora una volta dimostra che la funzionalità è molto più instabile e soggetta al designcambiamenti di dati in molti scenari. Naturalmente ad un certo punto abbiamo bisogno di funzionalità, ma è in grado di progettare sistemi in cui la maggior parte delle dipendenze flusso verso i dati, e non verso astrazioni o funzionalità in generale. Tale sarebbe Prioritizzazione stabilità sopra accoppiamento.

Le funzioni più stabile che abbia mai scritto (il genere che ho usato e riutilizzando dal fine degli anni '80, senza dover cambiare loro a tutti) sono stati tutti quelli che si basavano su dati grezzi, come una funzione geometrica che ha appena accettato un array di carri e interi, non quelli che dipendono da una complessa interfaccia oggetto Mesh o IMesh, o vettore / matrice moltiplicazione che appena dipendeva float[] o double[], non uno che dipendeva FancyMatrixObjectWhichWillRequireDesignChangesNextYearAndDeprecateWhatWeUse.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
scroll top