Come posso utilizzare versioni diverse di una libreria in evoluzione in diversi progetti?

3

Il problema

Scrivo un sacco di codice esplorativo nella mia ricerca. Mentre procedo, inserisco funzionalità che mi piacerebbe riutilizzare in una posizione centrale. Un progetto potrebbe assomigliare a questo:

./mylib
./exploration
    /experiment_1
    /experiment_2
    /experiment_3

Dove ogni esperimento utilizza alcune funzionalità da mylib .

Ora vengo e inizio il mio quarto esperimento. Nel processo, potrei aver bisogno di cambiare la mia libreria in qualche modo incompatibile all'indietro. Ora non riesco a rieseguire i miei primi tre esperimenti senza aggiornare i loro codici per essere compatibili con la nuova libreria.

Nota : A partire da ora, manterrò mylib nel controllo versione e exploration nel controllo versione, utilizzando git. Ciò significa che tutti gli esperimenti si trovano nello stesso repository. Questo è fatto in modo che un singolo push o fetch e merge in experiments sincronizzi tutti i miei esperimenti tra computer. Sento che potrebbe esserci un modo migliore, ma potrebbe essere per un'altra domanda ...

Possibili soluzioni

  • Potrei mordere il proiettile e aggiornare manualmente i vecchi esperimenti ogni volta che ho bisogno di eseguirli (male, noioso, ma semplice).
  • Potrei "vendorizzare" la mia libreria copiandola ogni volta che faccio un nuovo esperimento. (Cattivo, i bugfix devono essere inseriti in ogni copia).
  • Dato che mantengo la mia libreria nel controllo della versione, potrei taggare i punti nella cronologia della libreria con qualsiasi cosa sia richiesta da un esperimento. Quando voglio eseguire l'esperimento n , eseguo il checkout del tag n . (Meglio, ma se volessi eseguire due esperimenti contemporaneamente? Sembra anche che ci dovrebbe essere un modo per utilizzare automaticamente una versione specifica della libreria.)
  • Ogni volta che avvio un esperimento, creerò un nuovo ramo nella libreria. In ogni cartella dell'esperimento, clonerò il repository della libreria e verificherò il ramo corretto. (Questo sembra ragionevole, anche se forse è uno spreco di spazio, dal momento che ho duplicato tutti i rami durante la clonazione. Inoltre, potrei avere molti esperimenti, il che significa che ci saranno un sacco di rami nel mio repository, cose ingombranti inutilmente.)

Devo riconsiderare una di queste soluzioni sopra?

Ho anche ascoltato sui sottotitoli e sottomodelli di git, e mentre loro suonano come potrebbero essere la risposta al mio problema, voglio ottenere l'input di più esperto programmatori prima di affondare il tempo in una tana del coniglio.

    
posta jme 25.03.2014 - 16:21
fonte

7 risposte

2

Dopo aver passato la lettura del pomeriggio, sembra che git subtree sia ciò che sto cercando. Con questo approccio, mantengo la mia libreria in controllo della versione con git, e ogni esperimento va in un repository separato. Quando avvio un esperimento, inserisco l'ultima versione della libreria con git subtree add . Ogni esperimento ha la sua versione della libreria. Se voglio aggiornare un esperimento per utilizzare una nuova versione della libreria, posso creare un ramo, eseguire un git subtree pull , correggere il codice dell'esperimento per lavorare con la nuova interfaccia e unirmi al master.

Il bello di git subtree è che la cronologia dell'esperimento è legata alla cronologia della libreria che sto utilizzando. Questo è incredibilmente utile nella ricerca esplorativa in cui la riproducibilità è fondamentale. Ad esempio, potrei eseguire un esperimento con la versione 1 di una libreria e ottenere un determinato risultato. Successivamente, dopo aver aggiornato il codice dell'esperimento e spostato alla versione 2 della libreria, potrei rieseguire l'esperimento e scoprire, con mia sorpresa, che il risultato è diverso. Con i sottoalberi, se ho l'hash di commit che ha prodotto il mio risultato originale, posso ripristinare il mio esperimento allo stato esatto in cui era quando l'ho eseguito originariamente, libreria e tutto, semplicemente verificando che il commit.

    
risposta data 25.03.2014 - 22:05
fonte
5

Non si tratta tanto del sistema di controllo della versione che si sta utilizzando, quanto piuttosto della strategia generale di gestione della configurazione. Innanzitutto pensa alla tua strategia, quindi controlla come mappare questo al tuo VCS.

Ogni versione della libreria che pubblichi in "produzione" dovrebbe avere un numero di versione univoco. Dovresti tenere traccia di quale dei tuoi "esperimenti" usa quale versione della lib e quali esperimenti hai ancora "in manutenzione". Questo ti permette di scoprire per quali versioni precedenti della tua lib potresti aver bisogno di "release di manutenzione", e per le quali puoi ometterle. I diversi numeri di versione possono essere inclusi nel nome file della tua lib se ti aiuta ad usarli in parallelo (se ciò è necessario dipende dalla tua strategia di gestione / risoluzione delle librerie fisiche).

Diciamo che hai 3 versioni lib_v1.0, lib_v2.0 e lib_v3.0, ognuna usata da experiment1, experiment2 e experiment3. Ora, durante lo sviluppo di experiment4, hai apportato modifiche incompatibili a lib_v4 e trovato un bug che riguarda tutte le precedenti versioni. Supponiamo inoltre di correggere immediatamente il bug in V4. Ora hai le seguenti alternative

  • non aggiustare il bug nelle versioni precedenti. Ad esempio, experiment1 non è più "in produzione", quindi non è necessario correggere il bug in V1.0. O sai per certo che experiment1 non è influenzato dal bug e sai che "experiment1" è l'unico programma che usa la tua lib, quindi non c'è bisogno di correggere il bug nella V1.0

  • aggiorna tutti gli esperimenti interessati alla tua attuale lib_v4. Questo può diventare noioso, ma con il suggerimento di @RobertHarveys che utilizza un adattatore (o per evitare di rompere le modifiche) potrebbe essere una soluzione fattibile

  • se l'aggiornamento degli esperimenti interessati è troppo impegnativo, considera di portare il bugfix alle versioni di lib più vecchie (quindi creare lib V1.1, V2.1, V3.1)

Ovviamente, puoi combinare queste strategie: gli esperimenti 2 e 3 possono essere facilmente convertiti in V4, mentre esperimento1 deve attenersi a lib V1, quindi dovrai solo portare il bugfix in V1. Questo ti lascia con lib_V1.1 in manutenzione e lib V4 in sviluppo attivo, ma non è più necessario mantenere V2 e V3.

Quello che dovresti evitare è avere più di un albero versione della tua lib sotto "lo sviluppo attivo". Quando decidi di migliorare un esperimento precedente, rimani con la versione della libreria a cui è attualmente collegato o passa alla versione più recente della libreria per questo esperimento precedente.

Un'osservazione sul controllo della versione: questo modello di sviluppo si associa facilmente a ciascun VCS che supporta i rami di tagging e manutenzione (in altre parole: le funzionalità di base fornite da qualsiasi software decente vale il titolo "VCS").

    
risposta data 25.03.2014 - 17:17
fonte
1

Utilizza un adattatore .

Un adattatore è una classe che converte da una versione di un'API a un'altra. Su un lato dell'adattatore c'è l'API originale. Dall'altra parte c'è l'API per la versione più recente della tua libreria.

Potresti, naturalmente, semplicemente rendere la libreria compatibile all'indietro, mantenendo le vecchie chiamate API a beneficio dei tuoi esperimenti esistenti.

    
risposta data 25.03.2014 - 16:27
fonte
1

Penso che ciò di cui hai bisogno è un posto dove archiviare e gestire gli artefatti versionati. Come hai notato, questo è leggermente diverso dal mantenere la libreria sotto il controllo del codice sorgente. Come farlo dipende dalla lingua: di solito tutte le comunità linguistiche tendono a reinventare questo genere di cose. Ad esempio, vorrei usare:

  • SBT per Scala
  • Maven per Java
  • Bower per JavaScript o CoffeeScript lato client
  • NPM per il nodo JavaScript o CoffeeScript

Tutti questi strumenti funzionano sia con un repository remoto che in modalità locale, dove i pacchetti sono memorizzati in cache da qualche parte sul tuo filesystem. Bower funziona con git e tag, ma esegue checkout locali su ciascun progetto.

Dato che parli di Python, l'equivalente più simile a cui riesco a pensare è Pip, ma non sono sicuro che Pip ti permetta di usare i pacchetti locali.

    
risposta data 25.03.2014 - 17:05
fonte
0

Mi piace il modo in cui link lo fa. Può essere usato pubblicamente o in privato.

Abbiamo un problema simile in cui sviluppiamo più controlli obiettivo-c che verranno utilizzati in molte applicazioni. Non siamo riusciti a fare cambi di rottura perché ciò significherebbe forse rompere un progetto di cui non sai nulla. Ciò ostacola seriamente il progresso / l'innovazione.

Quindi con i cocoapod abbiamo fondamentalmente un repository che elenca i nomi / le versioni e le posizioni di tutti i nostri controlli (un elenco di podspec). Dentro i cocoapodi diciamo, per questo progetto usiamo

  1. control1 - v0.0.1
  2. control4 - v0.0.7
  3. control5 - v0.0.2

Quindi i cocoapodi andranno a ciascun repository di controlli e estraggono un tag con il nome del numero di versione specificato, ad es. "0.0.1".

Funziona abbastanza bene per noi essere in grado di utilizzare versioni specifiche di più librerie in molti progetti diversi.

Non sei sicuro che se i cocoapod supportano la tua piattaforma, potresti dover creare qualcosa da te o semplicemente elaborare il tuo processo, ma l'idea funziona bene.

    
risposta data 25.03.2014 - 16:43
fonte
0

Mantieni la tua libreria in un repository git e i tuoi esperimenti in un altro. Utilizzare i sottomoduli git per tenere traccia delle versioni della libreria. In realtà è costruito per questo ...

    
risposta data 25.03.2014 - 16:55
fonte
0

Potresti conservare i binari per ogni libreria con un nome di versione in ciascuno, ad es.

mylib/thelibname-alpha.dll
mylib/thelibname-beta.dll

I test quindi fanno riferimento alla versione pertinente. Se è necessario applicare una patch a una libreria, tutti i test che la utilizzano ne trarranno vantaggio, ma gli altri test non saranno interessati.

La ragione per fare ciò è la stessa di incorporare una stringa di versione in qualsiasi libreria - puoi controllare con precisione quale stai usando e controllare quale sia la versione "attiva" usando i link simbolici se vuoi. Dai un'occhiata a /lib su un host Linux e vedrai esattamente questa disposizione in uso:

$ ls -l /lib/libaudit.so.*
lrwxrwxrwx 1 root root     17 Feb  8 14:24 /lib/libaudit.so.1 -> libaudit.so.1.0.0
-rwxr-xr-x 1 root root 112224 Mar 14  2012 /lib/libaudit.so.1.0.0
    
risposta data 25.03.2014 - 17:31
fonte