Best practice per la condivisione di piccoli frammenti di codice tra progetti


102

Cerco sempre di seguire il principio DRY rigorosamente al lavoro; ogni volta che ho ripetuto il codice per pigrizia, questo morde più tardi quando devo mantenere quel codice in due punti.

Ma spesso scrivo piccoli metodi (forse 10-15 righe di codice) che devono essere riutilizzati in due progetti che non possono fare riferimento a vicenda. Il metodo potrebbe avere a che fare con la rete / stringhe / MVVM ecc. Ed è un metodo generalmente utile non specifico per il progetto in cui si trova originariamente.

Il modo standard di riutilizzare questo codice sarebbe quello di creare un progetto indipendente per il codice riutilizzabile e fare riferimento a quel progetto quando ne hai bisogno. Il problema è che finiamo in uno dei due scenari tutt'altro che ideali:

  1. Finiamo con decine / centinaia di piccoli progetti, ognuno per ospitare le piccole classi / metodi che dovevamo riutilizzare. Vale la pena crearne uno nuovo .DLLsolo per un po 'di codice?
  2. Finiamo con un singolo progetto che contiene una raccolta crescente di metodi e classi non correlati. Questo approccio è quello che ha fatto un'azienda per cui lavoravo; avevano un progetto chiamato base.commonche aveva cartelle per cose come ho menzionato sopra: networking, manipolazione di stringhe, MVVM ecc. Era incredibilmente utile, ma fare riferimento a esso trascinava inutilmente con esso tutto il codice irrilevante che non ti serviva.

Quindi la mia domanda è:

Come fa un team di software a riutilizzare meglio piccoli frammenti di codice tra progetti?

Sono particolarmente interessato se qualcuno ha lavorato in una società che ha delle politiche in questo settore o che si è imbattuto personalmente in questo dilemma.


nota: il mio uso delle parole "Progetto", "Soluzione" e "Riferimento" proviene da un background nello sviluppo di .NET in Visual Studio. Ma sono sicuro che questo problema è indipendente dalla lingua e dalla piattaforma.


21
+1, anche se penso che ci sia un elemento di umorismo in qualcuno che lavora con .NET preoccupato di trascinare codice irrilevante tramite un riferimento DLL.
JDB,

2
@ColeJohnson .NET in sé è un riferimento enorme! Probabilmente molto più grande delle dll che mi sarei fatto.
George Powell,

2
Capisco quello. Tuttavia, il compilatore JIT di .NET carica solo i metodi richiesti nella RAM (quando vengono chiamati)
Cole Johnson,

1
Vero. Sebbene sia ancora necessario distribuire l'intero framework .NET a chiunque desideri utilizzare il prodotto, i grandi progetti e le soluzioni complesse sono più difficili da gestire.
George Powell,

Risposte:


75

Se sono davvero metodi / classi riutilizzabili, potresti scriverli in un numero limitato di librerie "Swiss Army Knife". Lo facciamo abbastanza spesso presso la mia azienda; le chiamiamo librerie di framework:

  • Framework.Data - Utilità per lavorare con le query del database.
  • Framework.ESB - Metodi standard per l'interazione con il nostro bus di servizio aziendale
  • Framework.Logging - Sistema di registrazione unificato
  • Framework.Services - Utilità per l'interazione con i servizi web
  • Framework.Strings - Utilità per la manipolazione avanzata delle stringhe / la ricerca di stringhe fuzzy ecc.
  • ...

In tutto, ci sono circa una dozzina di biblioteche. Puoi davvero distribuire il codice come preferisci, quindi non devi finire con centinaia o scaricare tutto in un gigantesco assembly. Trovo che questo approccio sia adatto perché solo alcuni dei nostri progetti avranno bisogno Framework.Datae solo pochi ne avranno mai bisogno Framework.Strings, quindi i consumatori possono selezionare solo quelle parti del framework che sono rilevanti per il loro particolare progetto.

Se si tratta in realtà solo di frammenti e non di metodi / classi reali che possono essere facilmente riutilizzati, è possibile provare a distribuirli come frammenti di codice nell'IDE (ad esempio frammenti di codice di Visual Studio ). I team con cui ho lavorato in passato avevano una libreria di frammenti comune che ha reso più facile per tutti seguire le nostre pratiche di codifica standard anche con codice interno.


4
+1 Questo sarebbe anche il mio approccio. Interessato a sapere come hai deciso dove inserire il codice che si occupa di cose da due o più aspetti. Ad esempio IPAddressToString. E se permetti a queste librerie di usarsi a vicenda. Ad esempio, servizi e dati possono probabilmente trarre molti benefici dalla registrazione ...
Marjan Venema

5
@MarjanVenema Per il codice trasversale, dipende da quali consumatori troveranno il metodo più utile. Perché IPAddressToString, è probabile che i consumatori che si occupano dei protocolli di rete debbano usarlo, ma i consumatori che fanno molta manipolazione con le stringhe potrebbero non interessarsi affatto degli indirizzi IP. Ciò sarebbe probabilmente finito in un pacchetto di rete piuttosto che Framework.Strings.
pswg

@MarjanVenema Cerchiamo di evitare le interdipendenze. I nostri servizi e framework di dati sono scritti in modo tale da non effettuare alcuna registrazione da soli, ma per facilitare al consumatore la scrittura di un codice di registrazione adeguato. Le librerie di framework possono fare riferimento a vicenda, ma solo per estensione, ad esempio Framework.Logging.Gibraltarè un componente aggiuntivo specifico del sistema di registrazione.
pswg

5
+1 Potresti prendere queste librerie di framework e distribuirle in un repository NuGet interno (semplice come una cartella di rete) e hai un bel modo di gestirlo.
Steven Evers,

2
@SteveEvers In questo momento sto lavorando per configurarlo. : P
pswg

21

Non sono d'accordo con la risposta accettata per molte ragioni.

Nella mia esperienza, quando vedo librerie "varie" come la risposta accettata, sono una scusa per reinventare la ruota (o non inventata qui (NIH) ) - un peccato molto più grande della violazione Dont Repeat Yourself (DRY) .

A volte la violazione di DRY può essere un compromesso ragionevole, è meglio che introdurre un accoppiamento stretto. Il riutilizzo è una preoccupazione secondaria rispetto al buon design orientato agli oggetti. Un po '(intendo una piccola quantità, applico la Regola del Tre ) di duplicazione è più facile da capire di una base di codice spaghetti.

L'approccio di numerose biblioteche di uso generale dà un cattivo esempio. Porta a una fine granularità dell'assemblaggio e troppi assemblaggi sono dannosi. Di recente ho ridotto internamente da 24 biblioteche a 6 biblioteche. Ha migliorato il tempo di compilazione da diversi minuti a ~ 20 secondi. Visual Studio è anche più lento da caricare e meno reattivo con più assembly. Avere troppe librerie porta anche a confusione su dove dovrebbe vivere il codice; preferire meno regole, più semplici.

Perché le cose in .Net Framework non sono abbastanza buone? Il Framework è piuttosto grande; molte volte ho visto codice che reimplementa cose che già esistono lì. Assicurati davvero che i tuoi framework stiano colmando le lacune nel framework .Net e non esistano solo per motivi estetici (ad esempio "Non mi piace il framework .Net qui" o forse qualche ottimizzazione prematura )

L'introduzione di un altro livello nell'architettura ha un costo di complessità significativo. Perché esiste il layer? Ho visto un falso riutilizzo, nel senso che intendo dire che il codice è costruito su un framework interno. Sarebbe stato molto più efficiente implementarlo direttamente sulle librerie standard.

L'uso di tecnologie standardizzate (come il framework .Net e le famose librerie di terze parti / open source) presenta vantaggi che spesso superano i vantaggi tecnologici comparativi della costruzione da soli. È più facile trovare talenti che conoscano queste tecnologie e i tuoi sviluppatori esistenti investiranno di più nell'apprendimento.

I miei consigli:

  • Non condividere questo codice.
  • Crea una nuova libreria se ha uno scopo coerente, non utilizzare la sfera del modello di disegno del fango .
  • Riutilizzare le librerie di terze parti esistenti ove possibile.
  • Preferisci un numero minore di assembly, con regole più semplici su dove dovrebbe vivere il codice.

1
Un vantaggio marginale nell'utilizzare le librerie Open Source ove disponibili: se si presentano alcuni miglioramenti, è possibile condividerli nuovamente con la comunità! Ad esempio con .Net MS ha pubblicato un EnterpriseLibrary (ora Open Source) che offre un set di strumenti abbastanza buono per scenari comuni, trova qualcosa che può essere migliorato e hey presto! Tutti ne beneficiano!
glenatron,

2
Non vedo davvero un disaccordo con la risposta accettata qui :-). "un minor numero di assemblee, con regole più semplici su dove il codice dovrebbe vivere" non è una contraddizione alla risposta accettata. La risposta sostiene inoltre di utilizzare solo quanti assiemi diversi sembra ragionevole.
sleske,

Cinque anni dopo anche la guida ai microservizi si è convertita a questa pratica: medium.com/standard-bank/…
Dave Hillier il

11

Per piccoli frammenti di codice, ad esempio una singola classe senza dipendenze, tendiamo semplicemente a copiare e incollare il codice in progetti. Sembra una violazione di DRY, e ammetto che a volte può esserlo. Ma a lungo termine è stato molto meglio che avere una sorta di progetto comune comune a più teste per alcuni motivi.

Innanzitutto, è solo più semplice avere il codice a portata di mano, soprattutto durante la creazione e il debug di elementi.

In secondo luogo, invariabilmente vorrai apportare qualche piccola modifica al codice comune per quel progetto. Se hai una copia locale della fonte, puoi semplicemente apportare la modifica e chiamarla un giorno. Se esiste una libreria condivisa, potresti voler modificare tale libreria e assicurarti di non interrompere tutte le altre app o creare un incubo per il controllo delle versioni.

Quindi, se non è abbastanza robusto per il suo spazio dei nomi, tendiamo a inserirlo nei bit appropriati del progetto e chiamarlo un giorno.


5
Non sono d'accordo con questo approccio. Apprezzo i problemi di manutenzione con la gestione di piccoli pezzi di codice, ma direi che alcune librerie comuni potrebbero essere create da tutte come suggerisce @psw. Avere copie duplicate del codice con piccole modifiche in esso sta chiedendo problemi. Verranno fatte ipotesi e mancheranno correzioni di errori.
Andrew T Finnell,

2
-1 (alla risposta). È certamente più facile avere tutti le proprie copie delle proprie versioni dei programmi. Ecco come è stato sviluppato il software negli anni '80. Da allora ho imparato che - a lungo termine - questo porta a un disastro. È più difficile fare la cosa giusta e avere una biblioteca comune poiché le persone dovranno comunicare molto di più sul loro lavoro. Bene, dovrebbero.
Michael Durrant,

3
+1 - Penso che valga la pena menzionare questo approccio anche se non è uno che vuoi usare molto spesso. Alcuni frammenti sono più simili a modelli di progettazione: li riutilizzerai, ma in modo leggermente diverso ovunque, e forse in lingue diverse, e forse vorrai cambiarli. Inoltre, una libreria ampiamente riutilizzata non è flessibile in quanto le modifiche alla sua API sono molto rischiose. Infine, avere questo approccio come fallback aumenta la qualità delle librerie condivise mantenendo un po 'più a lungo le cose sperimentali.
Eamon Nerbonne,

6

La seconda soluzione che descrivi non è poi così male. In .NET fai anche riferimento a un assembly dal GAC anche se ne usi solo una singola classe. "Trascinare il codice irrilevante" non è un problema come potresti pensare. In questo caso è vitale almeno mantenere i metodi e le classi correlati ben organizzati in spazi di nomi diversi. Inoltre, è necessario applicare le buone pratiche per la progettazione dell'API per evitare che questa soluzione diventi un disastro.

Se si tratta di frammenti di codice molto piccoli, penso che il seguente approccio sia un buon complemento di un progetto comune: consentire loro di essere duplicati in diverse soluzioni. Affrontali come best practice: documentali e comunicali al team.


1
Tranne che per le librerie non standard, ciò significa che dovrai spedire un assembly di grandi dimensioni solo per un singolo (o pochi) usi. Questo non è un problema per roba standard poiché è comunque disponibile, ma eviterei sicuramente di spedire assiemi di grandi dimensioni ma per lo più inutilizzati se potessi dividerli in un buon modo.
colpì il

6

Ho sempre lavorato in ambienti "enterprise" in cui questo genere di cose è stato un problema e ogni volta è stata adottata la seconda opzione. Per la maggior parte ha funzionato bene perché non c'è stato alcun vincolo sull'impronta dell'applicazione.

Tuttavia, dopo aver trascorso l'ultima settimana con una start-up che esegue il proprio server Nuget, sono propenso a suggerirlo come alternativa praticabile. Naturalmente i problemi che mi aspetto di emergere riguarderanno la capacità di scoprire.

Se i progetti sono opportunamente granulari e gli spazi dei nomi sono sensibili, allora vedo che questo sta diventando un approccio popolare in alcuni luoghi.


In che senso ti aspetti che non siano rilevabili? In questo modo utilizziamo un numero elevato e crescente di pacchetti nuget. Il problema più grande che abbiamo è la gestione del controllo delle versioni e delle dipendenze.
pdr

Ah sì. Anche quelli. Per problemi relativi alla capacità di scoperta intendo che, dato un numero sufficiente di piccoli pacchetti con funzione specifica, forse diventa più difficile catalogare (e trovare) ciascuno. Ad esempio, come fa il tuo team a far conoscere quali pacchetti contengono varie funzioni? (mostrando qui l'ignoranza della ricerca di nuget)
Kofi Sarfo,

Oh, capisco. Sì, puoi sicuramente inserire quello che ti piace nella descrizione e questo diventa ricercabile, ma penso che abbiamo raggruppato i pacchetti abbastanza bene da non sembrare un problema.
pdr

@sarfeast Sarebbe bello se potessi condividere un link a qualunque server Nuget, e parlarne un po '.
Hans-Peter Störr,

6

Di recente ho pensato a questo e quello che mi è venuto in mente è stata una vasta libreria di metodi comuni, come è stato menzionato finora, ma con una svolta. Il progetto della libreria ti permetterebbe di configurare in fase di compilazione quali pezzi sono inclusi in qualche modo come il progetto BusyBox . Con questo approccio, puoi avere un repository di librerie in stile lavello da cucina, ma prendi solo gli strumenti di cui hai bisogno durante la compilazione.


5

GitHub ha uno strumento abbastanza utile per salvare frammenti di codice https://gist.github.com/

Memorizza i tuoi snippet come repository git che puoi mantenere privati ​​o utilizzare per condividere snippet con altre persone.


3

A seconda delle dimensioni del team / progetto / azienda, questa sarà una cosa piuttosto difficile da eseguire in modo efficace, a meno che non sia già in qualche modo integrata nel tuo ambiente e ogni soluzione che troverai (se implementata) avrà un costo in denaro. (Potrebbe proteggerti di più, ma non sarai in grado di misurare facilmente). Dovrai verificare se vale il prezzo. Ricorda anche che le soluzioni riutilizzabili tendono a diventare astratte e spesso si adattano a molte situazioni, ma senza essere ottimali.

In ogni caso, se vuoi farlo per il codice prodotto da più di una persona, all'inizio avrai bisogno di consapevolezza di tutti e cooperazione. Ciò include sviluppatori e gestori.

Quindi dovrai assicurarti di conoscere l'ambito in cui vuoi farlo. Squadra? Progetto? Dipartimento? Azienda? A seconda della risposta, il tipo di codice che inserirai in tali soluzioni varierà, così come la granularità con cui personalizzi le dll. Una volta che hai deciso su questo qualcuno (preferibilmente con un po 'di entusiasmo per l'idea - tu?) Dovresti sederti e iniziare a mettere una struttura in questo.

Solo la creazione di tali DLL non sarà sufficiente per fare il trucco, però. Per renderli utili dovrai pubblicizzarli (per utenti e collaboratori) e mantenerli come qualsiasi altro software, il che di solito significa che devi incaricarne qualcuno a lungo. Avrai anche bisogno di una documentazione affidabile, che richiederà anche manutenzione. Con un po 'di fortuna e cooperazione, potresti finire con alcune buone pratiche, ma può anche facilmente evolversi in un progetto a sé stante, a seconda delle dimensioni e del numero di squadre coinvolte. E per questo avrai ancora bisogno del supporto di gestione.


3

ho riscontrato un grosso problema e la mia soluzione preferita è pubblicare il codice in un repository abilitato per il web github / pubic. risolve molti problemi -

  1. facile accesso e facile condivisione. cvs / svn / enterprise-repos significa controllare il progetto in più aree di lavoro IDE e talvolta dover cambiare area di lavoro o computer solo per fare riferimento a un piccolo frammento di codice.
  2. supponendo che questi frammenti di codice non siano parti di codice proprietarie / classificate e siano variazioni delle conoscenze pubblicamente disponibili, pubblicarle su un repository pubblico come github significa che altri lo guarderanno e potrebbero persino contribuire.
  3. pubblicare qualcosa di dominio pubblico sotto il tuo nome ha l'ulteriore pressione della reputazione. controllerai e aggiornerai le cose, poiché si riflettono sulle tue capacità di programmatore.
  4. aggiornamenti. il vantaggio del mantenimento degli snippet di codice in un repository è che, se uno snippet non viene utilizzato da molto tempo, potrebbe diventare obsoleto (contenere apis / libs obsoleti). esempio: frammento di codice java per leggere un file. potresti aver trovato il modo migliore per farlo nel 2009, ma nel 2014 esce un nuovo file api che cambia tutto. il tuo frammento? ancora bloccato nel 2009. in un repository pubblico, le cose verranno aggiornate da te (perché proiettile 3), dai tuoi compagni di squadra o da alcuni membri della popolazione generale del programmatore e, nel frattempo, potresti persino ricevere suggerimenti per risolvere qualcosa che potresti aver sbagliato per molto tempo.

Una cosa che consiglierei, indipendentemente da dove conservi i tuoi frammenti, cerca sempre su Google prima di usarlo. le cose cambiano continuamente. i frammenti salvati fanno risparmiare tempo, ma generano anche compiacenza .


2

Abbiamo un "programma di utilità" separato per il progetto in cui archiviamo tutti questi piccoli metodi insieme ai test.

Quando un progetto necessita di qualche utilità, aggiunge semplicemente il file di origine con il metodo richiesto con "aggiungi come collegamento".

Ciò significa che non sono state aggiunte dipendenze di runtime (a meno che il file incluso non ne abbia bisogno).

Il sistema ha funzionato bene, ma come tutti gli altri ha bisogno di diciplin su ciò che è un'utilità. Richiedere un'elevata copertura dei test ha funzionato bene per noi e i test sono anche una buona documentazione di utilizzo. La scoperta è ancora un problema irrisolto per noi.

Una complessità con il progetto di utilità è decidere il livello di visibilità sugli articoli. Una regola empirica è che i metodi dovrebbero essere interni e le strutture di dati pubbliche.


2

La mia azienda utilizza servizi Web intranet-locali. Abbiamo alcuni servizi Web configurati come servizi Web interni comuni e quando un altro progetto ha bisogno di accedere a uno dei servizi invia una richiesta http con un'interfaccia definita. Poiché si trova sull'Intranet, ospitato nella stessa server farm, queste richieste sono molto veloci.

Ovviamente questo funziona solo con le app Internet (e funziona solo in millisecondi quando si trova sulla stessa rete locale), ma presenta alcuni vantaggi davvero interessanti.


0

Di recente ho trovato questo servizio: Snip2Code ( http://www.snip2code.com ).

È un modo interessante di condividere solo i tuoi snippet (non interamente le librerie) con il tuo team. Si rompe il solito punto per creare librerie comuni che dovrebbero essere citate in altri progetti, e secondo me questa è una visione preziosa.

Inoltre, ci sono molti scenari in cui l'uso di una libreria comune semplicemente non si applica: consideriamo ad esempio alcuni Pattern di Design come Singleton, Strategy o Observer. È possibile creare librerie per supportare tali modelli, ma non esiste ancora una copertura del 100%.

La vera necessità è disporre di uno strumento per condividere pratiche comuni tra il team. Ho provato a usare le idee di Github ma sono bloccato con la loro ricerca (davvero scadente) e con il fatto che non posso condividerle solo con la mia squadra e non con altri ...

(Dichiarazione di non responsabilità: sono uno dei fondatori di Snip2Code ed ero - insieme ai miei co-fondatori - nella tua stessa mentalità qualche tempo fa: è per questo che abbiamo deciso di iniziare questo progetto !!)

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.