Come possiamo evitare lo sviluppo guidato dall'IC ...?


45

Sto lavorando a un grande progetto open source guidato dalla ricerca, con un sacco di altri collaboratori regolari. Poiché il progetto ora è piuttosto grande, un consorzio (composto da due dipendenti a tempo pieno e pochi membri) è incaricato di mantenere il progetto, l'integrazione continua (CI), ecc. Non hanno tempo per l'integrazione di esterni contributi però.

Il progetto è composto da un framework "core", composto da circa mezzo milione di righe di codice, un gruppo di "plug-in" gestiti dal consorzio e diversi plug-in esterni, molti dei quali non sono ne sono nemmeno consapevole.

Attualmente, il nostro CI costruisce il core e i plugin gestiti.

Uno dei grandi problemi che affrontiamo è che la maggior parte dei contributori (e soprattutto quelli occasionali) non sta costruendo il 90% dei plugin mantenuti, quindi quando propongono di refactoring cambiamenti nel core (che in questi giorni avviene su base abbastanza regolare), hanno verificato che il codice si compili sulla propria macchina prima di effettuare una richiesta pull su GitHub.

Il codice funziona, sono contenti, quindi l'IC termina la compilazione e iniziano i problemi: la compilazione non è riuscita in un plug-in gestito dal consorzio, che il collaboratore non ha creato sulla propria macchina.

Tale plugin potrebbe avere dipendenze da librerie di terze parti, come ad esempio CUDA , e l'utente non vuole, non sa come, o semplicemente non può, per motivi hardware, compilare quel plugin rotto.

Allora - sia la soggiorni PR annuncio aeternam nel limbo di non-to-be-fuse PR - O il contribuente greps la variabile rinominato nel sorgente del plugin rotto, modificano il codice, spinge sul suo / la sua filiale, aspetta l'IC per completare la compilazione, in genere riceve più errori e reitera il processo fino a quando l'IC non è soddisfatto - O uno dei due permanenti già prenotati in eccesso nel consorzio dà una mano e cerca di riparare il PR sulla propria macchina.

Nessuna di queste opzioni è praticabile, ma non sappiamo come fare diversamente. Sei mai stato di fronte a una situazione simile dei tuoi progetti? E se sì, come hai gestito questo problema? C'è una soluzione che non vedo qui?


84
La regola più importante per fornire un'API plugin a un sistema è che sia mantenuta stabile o almeno retrocompatibile. Le modifiche al core senza intenzionalmente modifiche all'API dei plug-in non devono mai interrompere la compilazione di alcun plug-in (può accadere che interrompa accidentalmente la funzionalità, ma non la compilazione). Se una semplice modifica di un nome di variabile all'interno del core può portare a una compilazione interrotta di un plug-in , la separazione tra plug-in e core sembra essere completamente interrotta.
Doc Brown,


1
@KevinKrumwiede: sono sicuro che lo sanno già ;-) Se hai riscontrato incompatibilità, sono abbastanza sicuro che abbiano cambiato intenzionalmente l'API.
Doc Brown,

3
Vorrei riformulare la domanda, poiché è davvero fuorviante. Qualcosa di simile Come posso gestire i PR quando rompono il nostro attuale CI? cattura meglio la tua situazione, penso.
bracco23

2
Quanto è difficile / complesso il tuo processo di compilazione / test? Dovrebbe essere solo una questione di eseguire un singolo comando o fare clic su un singolo pulsante. A quel punto, diventa ragionevole aspettarsi che gli utenti eseguano tutti i test da soli prima di inviare un PR.
Alexander,

Risposte:


68

Lo sviluppo guidato da CI va bene! È molto meglio che non eseguire test e includere il codice non funzionante! Tuttavia, ci sono un paio di cose per rendere questo più facile per tutti i soggetti coinvolti:

  • Stabilisci le aspettative: disponi di una documentazione di contributo che spieghi che l'IC spesso rileva ulteriori problemi e che questi dovranno essere risolti prima di unire. Forse spiega che è più probabile che i piccoli cambiamenti locali funzionino bene, quindi può essere sensato suddividere un grosso cambiamento in più PR.

  • Incoraggia i test locali: semplifica l'impostazione di un ambiente di test per il tuo sistema. Uno script che verifica che tutte le dipendenze sono state installate? Un container Docker pronto per partire? Un'immagine di macchina virtuale? Il tuo runner di test ha meccanismi che consentono di dare la priorità ai test più importanti?

  • Spiega come usare la CI da soli: parte della frustrazione è che questo feedback arriva solo dopo aver inviato una PR. Se i contributori configurano CI per i propri repository, otterranno un feedback precedente e produrranno meno notifiche CI per altre persone.

  • Risolvi tutti i PR in entrambi i modi: se qualcosa non può essere unito perché è rotto e se non ci sono progressi verso la risoluzione dei problemi, chiudilo. Questi PR aperti abbandonati ingombrano tutto e qualsiasi feedback è meglio che ignorare il problema. È possibile esprimerlo molto bene e chiarire che ovviamente saresti felice di unirti quando i problemi saranno risolti. (vedi anche: The Art of Closing di Jessie Frazelle , Best Practices for Maintainers: Imparare a dire di no )

    Considera anche di rendere rilevabili questi PR abbandonati in modo che qualcun altro possa prenderli. Questo potrebbe anche essere un buon compito per i nuovi collaboratori, se i problemi rimanenti sono più meccanici e non richiedono una profonda familiarità con il sistema.

Per la prospettiva a lungo termine, i cambiamenti sembrano interrompere funzionalità non correlate così spesso che potrebbero significare che il tuo progetto attuale è un po 'problematico. Ad esempio, le interfacce dei plugin incapsulano correttamente gli interni del tuo core? Il C ++ semplifica la perdita accidentale di dettagli dell'implementazione, ma consente anche di creare astrazioni forti che sono molto difficili da utilizzare in modo improprio. Non puoi cambiarlo durante la notte, ma puoi guidare l'evoluzione a lungo termine del software verso un'architettura meno fragile.


13
"Questi PR aperti abbandonati ingombrano tutto" Vorrei che più manutentori avessero questo atteggiamento 😔
GammaGames

34

La creazione di un modello di plug-in sostenibile richiede che il framework principale esponga un'interfaccia stabile su cui i plug-in possono fare affidamento. La regola d'oro è che puoi introdurre nuove interfacce nel tempo ma non puoi mai modificare un'interfaccia già pubblicata. Se segui questa regola, puoi riformattare l' implementazione del framework di base tutto ciò che desideri senza timore di rompere accidentalmente i plug-in, sia esso gestito da un consorzio o esterno.

Da quello che hai descritto, sembra che tu non abbia un'interfaccia ben definita, e questo rende difficile dire se una modifica interromperà i plugin. Lavora per definire questa interfaccia e renderla esplicita nella tua base di codice, in modo che i partecipanti sappiano cosa non dovrebbero modificare.


20
CI dovrebbe avere test automatizzati. Se vuoi assicurarti che i plugin abbiano la stessa interfaccia, ogni plugin dovrebbe contribuire con test che esprimono l'interfaccia di cui hanno bisogno. Vieni in questo modo e quando l'interfaccia cambia, cosa che farà, saprai quali plugin stai rompendo. Dammi questi test da eseguire localmente e saprò cosa sto rompendo prima di pubblicare il PR.
candied_orange

1
La buona definizione di @lagarkane è più un problema politico che tecnico. Ci sono software là fuori che come il tuo, semplicemente abbandonano il comportamento precedente in un aggiornamento. Perl5 non è compatibile con Perl6, Python2.7 non è completamente compatibile con Python3.4 ecc. Quindi ci sono software che qualunque cosa accada supportano ancora il vecchio codice. Puoi ancora eseguire quasi tutto il codice javascript scritto per Netscape Navigator 4 nei browser moderni. Il linguaggio di programmazione Tcl è compatibile con le backwords rispetto alla versione originale ecc ...
slebetman

3
@lagarkane: formare il consorzio è stato un passo nella giusta direzione, e se i membri principali focalizzano la loro energia sulla creazione di queste interfacce, allora puoi sfruttare la potenza dei futuri dottorandi e stagisti per mantenere forte il tuo progetto minimizzando le rotture. :)
Casablanca

4
@Fattie: Funziona con Apple perché costruisce prodotti di successo rivolti ai consumatori e gli sviluppatori sono costretti a giocare se vogliono farne parte. È improbabile che a quegli sviluppatori piacciano davvero le modifiche, e sicuramente non è un buon modello per un progetto open source.
Casablanca,

1
@casablanca sia il lignaggio MacOS che quello WindowsOS hanno avuto un enorme successo. (Probabilmente, i due più grandi prodotti in termini di dollari nell'esistenza umana.) Nel corso dei decenni hanno avuto approcci assolutamente opposti. Apparentemente entrambi hanno avuto successo!
Fattie,

8

Ad essere sincero, non penso che tu possa gestirlo meglio - se i cambiamenti provocano la rottura di parti del tuo progetto mantenute, la CI dovrebbe fallire.

Il tuo progetto ha contributing.mdqualcosa o qualcosa di simile per aiutare i collaboratori nuovi e occasionali a preparare i loro contributi? Hai un elenco chiaro, quali plug-in fanno parte del core e devono rimanere compatibili?

Se è difficile costruire tutto su una macchina a causa di dipendenze, ecc., Potresti pensare di creare immagini docker pronte per l'uso come ambienti di compilazione utilizzabili dai tuoi collaboratori.


1
Grazie per la risposta! Sì, abbiamo linee guida per il contributo disponibili pubblicamente, ma non elenca i plug-in come suggerisci, il che sarebbe già una buona idea. Rendere le immagini docker sembra già un grande miglioramento rispetto all'attuale processo che contribuisce! Grazie per l'input
lagarkane,

8

quindi quando propongono cambiamenti di refactoring nel core (che in questi giorni avviene su base abbastanza regolare), hanno verificato che il codice si compili sulla loro macchina prima di fare una richiesta pull su github.

Quindi penso che sia qui che può cadere lo stile sciolto dei progetti open source; la maggior parte dei progetti organizzati a livello centrale sono diffidenti nei confronti del refactoring di base, soprattutto quando attraversa un confine API. Se eseguono il refactoring di un limite API, di solito è un "big bang" in cui tutte le modifiche sono pianificate contemporaneamente con un incremento alla versione principale dell'API e viene mantenuta la vecchia API.

Proporrei una regola "tutte le modifiche all'API devono essere pianificate in anticipo": se arriva un PR che apporta una modifica all'API incompatibile all'indietro, da qualcuno che non è stato in contatto con i manutentori per concordare in anticipo il loro approccio, esso viene semplicemente chiuso e il mittente indica la regola.

Sarà inoltre necessario il versioning esplicito dell'API del plug-in. Ciò consente di sviluppare v2 mentre tutti i plug-in v1 continuano a essere compilati e funzionanti.

Vorrei anche mettere in dubbio un po 'di più il motivo per cui vengono apportati così tanti refactoring di base e modifiche API. Sono davvero necessari o solo persone che impongono il loro gusto personale al progetto?


2

Sembra che il processo di CI debba essere più rigoroso, più completo e più visibile ai partecipanti prima che aumentino un PR. Ad esempio, BitBucket ha una funzionalità di pipeline che lo consente, in cui gli si fornisce un file che definisce in codice il processo di creazione dell'elemento della configurazione e, in caso contrario, il ramo viene impedito dall'unione.

Indipendentemente dalla tecnologia, fornire build automatiche quando un contributore spinge verso una filiale fornirà loro un feedback molto più rapido su ciò che i guardiani devono cercare quando apportano modifiche e porterà a PR che non devono essere riparati dopo il fatto.

I problemi di progettazione sarebbero utili da risolvere, ma sono ortogonali a questo problema.


2

Il codice funziona, sono contenti, quindi l'IC termina la compilazione e iniziano i problemi: la compilazione non è riuscita in un plug-in gestito dal consorzio, che il collaboratore non ha creato sulla propria macchina.

Tale plug-in potrebbe avere dipendenze da librerie di terze parti, come ad esempio CUDA, e l'utente non desidera, non sa come, o semplicemente non può, per motivi hardware, compilare quel plug-in rotto.

La tua soluzione è semplice: abbassa la barriera al contributo .

Il modo più semplice per (1) accelerare il ciclo di modifica-compilazione-test e (2) uniformare le differenze di ambiente è fornire server di build :

  • Prendi macchine robuste: 24, 48 o 96 core, 2 GB di RAM / core, SSD, per accelerare la compilazione.
  • Assicurati che abbiano l'hardware giusto: FPGA, scheda grafica, qualunque cosa sia necessaria.
  • Crea un'immagine Docker con tutte le librerie software necessarie preinstallate.

E quindi apri quei server di build ai collaboratori. Dovrebbero essere in grado di accedere in remoto in una nuova immagine Docker e modificare-compilare-test in remoto su questa macchina.

Poi:

  • Non hanno scuse per non creare / testare i plugin mantenuti: hanno tutto a disposizione.
  • Non devono attendere un lungo feedback con PR guidati da CI: hanno una compilazione incrementale e la possibilità di eseguire il debug (piuttosto che indovinare).

In generale, i server di compilazione possono essere condivisi tra più collaboratori, tuttavia quando sono coinvolte periferiche hardware speciali può essere necessario che un collaboratore utilizzi tali periferiche da soli.


Fonte: lavorando su software che utilizza FPGA, dato il prezzo degli animali e la varietà di modelli di cui abbiamo bisogno, non trovi ogni modello di FPGA installato su ogni macchina dello sviluppatore.


1

Se contribuire al core senza modificare alcun contratto può rompere il software dipendente, suggerisce che:

  • I contratti delle tue interfacce possono essere ambigui. Forse l'aggiunta di attributi alle funzioni e i parametri delle funzioni aiuterebbe ad esporre vincoli aggiuntivi al codice client per rendere più chiari i contratti. O se stai applicando modifiche che violano il contratto, forse l'adozione del controllo delle versioni semantico può aiutare.
  • I test unitari non coprono abbastanza dei possibili scenari di chiamata.

Entrambi i problemi dovrebbero essere facili da risolvere, ma dici che il core team potrebbe non avere la capacità di farlo. Un'opzione sarebbe quella di chiedere aiuto alla comunità per affrontare il problema.


1

Nessun altro sembra aver sollevato questo come una potenziale soluzione.

  • elenca tutti i plugin a cui puoi accedere.
  • eseguire tutti i test definiti da questi plugin
  • registra tutte le richieste / risposte / interazioni tra il core e tutti i plugin
  • memorizzare quelle registrazioni, ora si tratta di test di compatibilità approssimativi.

Quando si sviluppa il core, incoraggiare gli sviluppatori a eseguire questi test di compatibilità. In caso contrario, non effettuare il check-in.

Ciò non garantirà al 100% la compatibilità, ma colpirà molti più problemi e presto.

Un vantaggio secondario è che queste registrazioni possono evidenziare quali interfacce vengono utilizzate attivamente e quali funzionalità vengono utilizzate attivamente.


0

Ho difficoltà a comprendere la situazione così come sembra: l'IC crea un solo ramo?

C'è un motivo per cui non è possibile creare più di un ramo con l'elemento della configurazione?

La soluzione più semplice a questo problema sarebbe quella di consentire a qualsiasi collaboratore di eseguire la build CI sul proprio ramo di funzionalità .

Quindi è sufficiente una compilazione CI riuscita sul ramo della funzione per poter accettare la richiesta pull di quel ramo.


Questo sembra riassumere il problema.
Fattie,

1
La domanda dice "O il collaboratore [...] cambia il codice, spinge sul suo ramo, aspetta che l'IC finisca la compilazione, di solito ottenga più errori e ribadisce il processo fino a quando l'IC è felice" - quindi penso che questo è già il caso, ma il problema è che è piuttosto doloroso svilupparsi con un ciclo di modifica-debug così lungo.
npostavs,

@npostavs Grazie, immagino sia quello che mi sono perso la prima volta o due l'ho letto. Anche così ... Immagino di non sembrare il problema. Ci sono molte dipendenze, non possono essere interrotte, quindi un collaboratore deve rimanere compatibile con tutte. Questa è la natura del grande software. Certamente si potrebbe fare del lavoro per rendere la build più veloce, forse, ma per il resto, quale collegamento potrebbe esserci?
Kyralessa,
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.