3. Mantenere un progetto: interagire con gli sviluppatori

Una volta che il progetto è partito, sono stati superati gli ostacoli più insidiosi nel processo di sviluppo del programma. Porre delle fondamenta salde è essenziale, ma il processo di sviluppo in sé è ugualmente importante, e fornisce altrettante opportunità di fallimento. Nelle prossime due sezioni verrà descritta la conduzione di un progetto, discutendo il modo per sostenere uno sforzo di sviluppo costante attraverso le interazioni con gli sviluppatori e con gli utenti.

Al rilascio del programma, esso diventa software libero. Questa transizione è qualcosa di più che avere un'utenza più vasta: rilasciando il programma come software libero, il proprio software diventa software della comunità del software libero. Il corso degli sviluppi futuri sarà rimodellato, rediretto, e completamente determinato dagli utenti e, principalmente, dagli altri sviluppatori della comunità.

La differenza principale tra lo sviluppo di software libero e lo sviluppo di software proprietario è la base degli sviluppatori. Come leader di un progetto di software libero, sarà necessario attrarre e tenersi stretti gli sviluppatori, mentre i leader di progetti di software proprietario non devono preoccuparsi di queste cose nella stessa misura. Come persona che dirige lo sviluppo di un progetto di software libero, si dovrà controllare il lavoro dei colleghi sviluppatori prendendo decisioni responsabili, e scegliendo responsabilmente di non prendere decisioni. Gli sviluppatori dovranno essere diretti senza essere autoritari o dispotici. Si dovrà lottare per guadagnarne il rispetto, e averne sempre per loro.

3.1. Delegare il lavoro

A questo punto, avete ipoteticamente seguito i primi passi della programmazione di un software, la creazione di un sito web e di un sistema di documentazione, per poi procedere (come sarà descritto nella Sezione 4.3) al rilascio, a beneficio del resto del mondo. Il tempo passa, e se le cose andranno bene la gente sarà interessata e vorrà aiutare. Le patch cominceranno ad affluire.

Come il genitore di un figlio che cresce, è ora tempo di reprimere una smorfia di dispiacere, sorridere, e fare la cosa più difficile nella vita di un genitore: è tempo di lasciarlo andare via.

La delega è il modo politico di descrivere questo processo di "lasciare andare via": è il processo di affidare parte della responsabilità e del potere sul progetto ad altri sviluppatori responsabili e coinvolti. È difficile farlo, per chiunque abbia investito una grande quantità di tempo ed energie in un progetto, ma è essenziale per la crescita di qualsiasi progetto di software libero. Una persona da sola può seguire solo una quantità limitata di cose; un progetto di software libero è nulla senza il coinvolgimento di un gruppo di sviluppatori, che può essere mantenuto vivo solo attraverso una guida rispettosa e responsabile, e attraverso la delega.

Mentre il progetto procede, si noteranno persone che investono quantità significative di tempo e di sforzi nel progetto; saranno quelle che inviano più patch, che pubblicano più messaggi sulle mailing list, e che partecipano a lunghe discussioni via email. È responsabilità del manutentore del progetto contattare queste persone, e tentare di spostare un po' del potere e della responsabilità della posizione di manutentore su di loro (se lo vogliono). Ci sono diversi semplici modi per farlo.

Smentendomi un po', delegare non vuol dire necessariamente decidere in comitato. In molti casi sì, ed è provato che funziona; in altri casi ha creato dei problemi. Managing Projects the Open Source Way sostiene che "i progetti OSS funzionano bene quando una persona è il leader indiscusso di un team e prende le decisioni importanti (modifiche di progettazione, date di rilascio, e così via)." Questo spesso è vero, ma vorrei spronare gli sviluppatori a prendere in considerazione le idee che il leader del progetto non deve essere necessariamente il fondatore, e che questi importanti poteri non necessariamente devono essere tutti nelle mani di una stessa persona: il gestore dei rilasci può essere diverso dal capo sviluppatore. Queste situazioni sono politicamente delicate, perciò si faccia attenzione e ci si assicuri che sia inevitabile, prima di dare pieni poteri alle persone.

3.1.1. Come delegare

Si potrebbe scoprire che altri sviluppatori sono più esperti o competenti. Il lavoro come manutentori non significa dover essere il migliore o il più brillante; significa avere la responsabilità di mostrare buona capacità di giudizio, e di riconoscere quali soluzioni sono mantenibili e quali no.

Come ogni cosa, è più facile guardare gli altri delegare che farlo in prima persona. In una frase: essere sempre in cerca di altri sviluppatori qualificati che mostrino un interesse e un coinvolgimento continuato nel proprio progetto, e cercare di spostare la responsabilità verso di loro. Le idee seguenti potrebbero essere buoni punti di partenza o buone fonti di ispirazione.

3.1.1.1. Concedere ad un gruppo più ampio di persone il permesso di scrittura sul proprio repository CVS, e fare uno sforzo effettivo per promuovere la gestione in comitato

Apache è un esempio di progetto condotto da un piccolo gruppo di sviluppatori, che votano sulle principali problematiche tecniche e sull'ammissione di nuovi membri, ed hanno tutti accesso in scrittura al repository principale dei sorgenti. Il loro processo è descritto nei dettagli online.

Il Debian Project è un esempio estremo di gestione in comitato. Ad un conteggio aggiornato, più di 700 sviluppatori hanno piena responsabilità su qualche aspetto del progetto; tutti questi sviluppatori possono caricare file sul server FTP principale, e votare sulle problematiche principali. Il corso del progetto è determinato dal suo contratto sociale, e da una costituzione. Per facilitare questo sistema ci sono dei team speciali (ad esempio il team per l'installazione, quello per la lingua giapponese), ed anche un comitato tecnico ed un capo progetto. La responsabilità principale del capo progetto è di "nominare delegati o delegare decisioni al Comitato Tecnico."

Anche se entrambi questi progetti operano su una scala che il proprio progetto non avrà (almeno all'inizio), il loro esempio è utile. L'idea di Debian di un capo progetto che non fa niente altro che delegare serve da esempio portato all'estremo di come un progetto può coinvolgere e dar poteri ad un numero enorme di sviluppatori, e crescere sino ad una dimensione enorme.

3.1.1.2. Nominare pubblicamente qualcuno come gestore del rilascioper uno specifico rilascio

Un gestore del rilascio ha solitamente la responsabilità di coordinare il collaudo, imporre un congelamento del codice, controllarne la stabilità e la qualità, impacchettare il software, e metterlo nei posti appropriati per essere scaricato.

Quest'uso del gestore del rilascio è un buon modo per prendere una pausa e spostare su qualcun altro la responsabilità di accettare e rifiutare patch. È un buon modo di definire molto chiaramente un segmento di lavoro del progetto come appartenente ad una certa persona, ed è un ottimo modo di concedere a se stessi lo spazio per respirare.

3.1.1.3. Delegare il controllo di un intero ramo

Se il proprio progetto sceglie di avere rami (come descritto nel la Sezione 3.3), potrebbe essere una buona idea nominare qualcun altro responsabile di un ramo. Se si preferisce concentrare le proprie energie sui rilasci di sviluppo e sull'implementazione di nuove funzionalità, si lasci il controllo totale sui rilasci stabili ad uno sviluppatore adatto al compito.

L'autore di Linux, Linus Torvalds, incoronò pubblicamente Alan Cox come "l'uomo dei kernel stabili": tutte le patch per i kernel stabili vanno ad Alan, e se Linus fosse per qualsiasi ragione strappato via dal suo lavoro su Linux, Alan Cox sarebbe più che adeguato a prendere il suo posto, in quanto erede riconosciuto per la manutenzione di Linux.

3.2. Accettare e rifiutare patch

Questo HOWTO ha già accennato al fatto che come manutentori di un progetto di software libero, una delle primarie e più importanti responsabilità sarà accettare e rifiutare patch inviate da altri sviluppatori.

3.2.1. Incoraggiare un buon patching

Come persone che gestiscono o curano la manutenzione del progetto non si realizzeranno materialmente molte patch. Comunque val la pena di conoscere la sezione di ESR sulle Buone pratiche di patching nel Software Release Practices HOWTO[ESRHOWTO]. Non sono d'accordo con la sua affermazione che le patch bruttissime da vedere o non documentate meritino probabilmente di essere gettate via alla prima occhiata: semplicemente, questa non è stata la mia esperienza, specialmente avendo a che fare con correzioni di bug che spesso non sono affatto nella forma di patch. Naturalmente, questo non vuol dire che mi piace ricevere patch fatte malamente: se si ricevono brutte patch, se si ricevono patch senza alcuna documentazione, specialmente se sono qualcosa di più di correzioni di bug banali, potrebbe valer la pena di giudicare la patch secondo qualcuno dei criteri spiegati nell'HOWTO citato, e poi inviare alla gente il link al documento cosicché possano rifarla nel "modo giusto."

3.2.2. Giudizio tecnico

In Open Source Development with CVS, Karl Fogel sostiene in modo convincente che le cose più importanti da ricordare quando si rifiutano o accettano patch sono:

  • una solida conoscenza dello scopo del programma (è l' "idea" di cui si parlava in la Sezione 2.1);

  • la capacità di riconoscere, facilitare, e dare una direzione all'"evoluzione" del programma, cosicché esso possa crescere e cambiare e incorporare funzionalità che non erano state originariamente previste;

  • la necessità di evitare divagazioni che possano espandere troppo la portata del programma, divagazioni che spingerebbero il progetto verso una morte prematura sotto il peso della propria ingestibilità.

Questi sono i criteri che, come manutentori del progetto, si dovrebbero tenere in conto ogni volta che si riceve una patch.

Fogel approfondisce la questione, ed afferma che "le domande da porsi quando si deve decidere se implementare (od approvare) un cambiamento sono:"

  • porterà benefici ad una percentuale significativa della comunità di utenti del programma?

  • si adatta bene al dominio del programma, o ad una estensione naturale ed intuitiva di tale dominio?

Le risposte a queste domande non sono mai semplici, ed è sicuramente possibile (e persino probabile) che la persona che ha inviato la patch possa avere opinioni diverse dalla propria su tali risposte. Tuttavia, se la risposta ad almeno una di queste domande è "no," è proprio dovere rifiutare il cambiamento: contrariamente, il progetto diventerà ingestibile e non mantenibile, e potrà alla lunga fallire.

3.2.3. Rifiutare delle patch

Rifiutare una patch è probabilmente il lavoro più difficile e delicato che il manutentore di un qualsiasi progetto di software libero deve affrontare; ma qualche volta deve essere fatto. Come accennato prima (nel la Sezione 3 e nel la Sezione 3.1), si dovrà cercare di bilanciare le proprie responsabilità e i propri poteri nel prendere quelle che si pensa siano le migliori decisioni tecniche, con il fatto che si potrà perdere supporto dagli altri sviluppatori sembrando ubriachi di potere o troppo autoritari o possessivi verso il progetto, che dopotutto appartiene alla comunità. Si consiglia di tenere a mente questi tre concetti principali quando si rifiutano delle patch (o altri cambiamenti).

3.2.3.1. Proporlo alla comunità

Uno dei modi migliori di giustificare una decisione di rifiutare una patch, cercando di non far sembrare di mantenere una presa ferrea sul proprio progetto, è di non prendere la decisione completamente da soli. Potrebbe aver senso redirigere le proposte di cambiamenti e le decisioni più difficili verso una mailing list di sviluppo dove possano essere discussi e dibattuti. Ci saranno alcune patch (correzione di bug, etc.) che saranno sicuramente accettate, ed alcune che saranno ritenute così fuori posto da non meritare neanche un'ulteriore discussione: sono quelle che rientrano nella zona grigia tra questi due gruppi a poter meritare un rapido inoltro ad una mailing list.

Si consiglia caldamente di seguire questo processo. Come manutentore del progetto si avrà la preoccupazione di prendere la decisione migliore per il progetto, per gli utenti e gli sviluppatori del progetto, e per voi stessi come capi progetto responsabili: redirigere le cose ad una mailing list dimostrerà il proprio senso di responsabilità e la propria conduzione attenta, poiché chiede lumi sugli interessi della comunità per poter meglio porsi al suo servizio.

3.2.3.2. I problemi tecnici non sono sempre una buona giustificazione

Specialmente all'inizio della vita del progetto, si scoprirà che molti cambiamenti sono difficili da implementare, introducono nuovi bug, o hanno altri problemi tecnici. Si cerchi di vedere oltre: specialmente per le funzionalità aggiunte, le buone idee non sempre vengono da buoni programmatori. Il valore tecnico è una ragione valida per rimandare l'applicazione di una patch, ma non è sempre una buona ragione per rifiutare un cambiamento immediatamente. Anche i cambiamenti piccoli valgono lo sforzo di lavorare insieme allo sviluppatore per risolvere i bug ed incorporare il cambiamento, se si pensa che sia una buona aggiunta al progetto: questo sforzo contribuirà a rendere il proprio progetto un progetto della comunità, attirerà uno sviluppatore nuovo o con meno esperienza nel progetto, ed insegnerà perfino ai suoi membri qualcosa che potrebbe tornare utile nel preparare la prossima patch.

3.2.3.3. Buone maniere

Dovrebbe essere superfluo dirlo, ma prima di tutto, in ogni occasione, essere cortesi. Se qualcuno ha un'idea, e ci tiene a sufficienza da scrivere del codice ed inviare una patch, significa che ci tiene davvero, è motivato, ed è già coinvolto: il proprio obiettivo come manutentore è assicurarsi che ne invii altre. Può aver fatto cilecca questa volta, ma la prossima volta la sua potrà essere l'idea o la funzionalità che rivoluzionerà il progetto.

Per prima cosa, è proprio dovere giustificare con chiarezza e concisione la scelta di non incorporare un cambiamento, e ringraziare; far capire che l'aiuto è stato molto apprezzato, e che dispiace davvero non poter incorporare i cambiamenti. Poi far capire che si desidera che l'autore resti coinvolto, e che si spera che la prossima patch o idea si integri meglio col progetto, perché il suo lavoro è stato apprezzato e si vorrebbe vederlo nella propria applicazione. Se mai è capitato di veder rifiutata una propria patch dopo avervi investito una grossa quantità di tempo, riflessione, ed energie, si cerchi di ricordare come ci si sente: non è piacevole; tenerlo a mente quando si dovrà deludere qualcuno. Non è mai facile, ma è necessario fare tutto il possibile per renderlo il meno spiacevole possibile.

3.3. Rami stabili e rami di sviluppo

L'idea di avere rami stabili e rami di sviluppo è stata già descritta brevemente nel la Sezione 2.4 e nel la Sezione 3.1.1.3; questi cenni testimoniano alcuni dei modi in cui i rami multipli possono influenzare il software. I rami possono far evitare (in qualche misura) alcuni dei problemi legati al rifiuto delle patch (descritti nel la Sezione 3.2), in quanto permettono di compromettere temporaneamente la stabilità del progetto senza incidere sugli utenti che hanno bisogno di quella stabilità.

Il modo più comune di dividere in rami il progetto è avere un ramo stabile e uno per lo sviluppo. Questo è il modello seguito dal kernel Linux, ed è descritto nel la Sezione 2.4. In questo modello, c'è sempre un ramo stabile ed un ramo in sviluppo. Prima di ogni nuovo rilascio, il ramo di sviluppo entra in un "blocco delle funzionalità", come descritto nel la Sezione 3.4.1, in cui i cambiamenti principali e le funzionalità aggiunte sono rifiutati o messi in attesa fino a che il kernel di sviluppo viene rilasciato come nuovo ramo stabile, e gli sviluppi principali riprendono sul nuovo ramo di sviluppo. Le correzioni di bug e i piccoli cambiamenti che presumibilmente non avranno grandi ripercussioni negative, vengono incorporati sia nel ramo stabile che nel ramo di sviluppo.

Il modello di Linux fornisce un esempio estremo. In molti progetti non c'è bisogno di avere costantemente disponibili due versioni: può avere senso avere due versioni solo in prossimità di una release. Il progetto Debian ha sempre storicamente reso disponibili sia una distribuzione stabile che una instabile, ed ha allargato l'insieme sino ad includere: versione stabile, instabile, di collaudo, sperimentale, e (intorno alla data di rilascio) una distribuzione congelata che incorpora solo correzioni di bug nella transizione da instabile a stabile. Ci sono pochi progetti la cui dimensione avrebbe bisogno di un sistema come quello di Debian; tuttavia, questo uso dei rami dimostra come essi possano essere usati per far coesistere uno sviluppo coerente ed efficace con il bisogno di produrre rilasci regolari ed utilizzabili.

Nel cercare di impostare un albero di sviluppo, può essere utile tenere a mente alcune cose.

Minimizzare il numero di rami

Debian può riuscire a fare buon uso di quattro o cinque rami, però contiene dei gigabyte di software, in più di 5000 pacchetti, compilati per 5 o 6 diverse architetture. Due è probabilmente un buon limite superiore. Troppi rami confonderanno i propri utenti (non si possono contare le volte che ho dovuto descrivere il sistema di Debian, quando ancora aveva solo due o certe volte tre rami!), i potenziali sviluppatori, ed anche voi stessi. I rami possono aiutare, ma hanno un costo, perciò vanno usati con molta parsimonia.

Assicurarsi che tutti i diversi rami abbiano una spiegazione

Come accennato nel paragrafo precedente, rami differenti confonderanno gli utenti. Si faccia tutto il possibile per evitarlo, spiegando chiaramente i diversi rami in una pagina ben visibile sul proprio sito, ed in un file README nella directory FTP o web.

Si potrebbe anche mettere in guardia da un errore che Debian potrebbe aver fatto: i termini "instabile," "in collaudo," e "sperimentale" sono vaghi, e difficili da classificare in ordine di stabilità (o di instabilità, secondo le circostanze); si cerchi di spiegare a qualcuno che "stabile" significa in realtà "ultra stabile", e che "instabile" non comprende in realtà alcun software instabile, ma è in realtà software stabile non collaudato come distribuzione.

Se si ha l'intenzione di usare dei rami, specialmente nelle prime fasi, si ricordi che le persone sono abituate a comprendere i termini "stabile" e "di sviluppo", e con questa semplice e comune divisione dei rami probabilmente non si sbaglierà.

Assicurarsi che tutti i rami siano sempre disponibili

Come molte delle cose scritte in questo documento, probabilmente non dovrebbe essere necessario dirlo ma l'esperienza insegna che non è sempre ovvio per tutti: è una buona idea separare fisicamente rami diversi in directory, o alberi di directory diversi sul proprio sito FTP o web. Linux lo realizza mantenendo i kernel in sottodirectory v2.2, v2.3, ecc., così è immediatamente ovvio (una volta che si conosce il loro schema di numerazione delle versioni) quale directory è per il più recente rilascio stabile, e quale per lo sviluppo corrente. Debian lo realizza dando a tutte le distribuzioni dei nomi (ad esempio woody, potato, etc.) e modificando i collegamenti simbolici chiamati "stable," "unstable" e "frozen" per puntare (per nome) a quella certa distribuzione che si trova in quel certo stato. Entrambi i metodi funzionano, e ce ne sono altri: in ogni caso, è importante che i diversi rami siano sempre disponibili, siano accessibili da posizioni coerenti, e che i diversi rami siano chiaramente distinguibili l'uno dall'altro, cosicché gli utenti sappiano esattamente cosa vogliono e dove trovarlo.

3.4. Altri problemi nella gestione dei progetti

In un progetto di software libero possono sorgere altri problemi nell'interazione con gli sviluppatori, ma non è possibile trattarli in dettaglio in un HOWTO di queste dimensioni, e con questi obiettivi. Vi prego di non esitare a contattarmi se scoprite delle omissioni importanti.

Altre più piccole questioni che vale la pena di menzionare sono:

3.4.1. Congelamento

Per quei progetti che scelgono di adottare un modello di sviluppo suddiviso (la Sezione 3.3), il congelamento è un concetto con cui vale la pena di familiarizzare.

I congelamenti possono avere due forme principali. Un "congelamento delle funzionalità" è un periodo in cui al programma non vengono aggiunte funzionalità significative. Le funzionalità esistenti (anche ossature di funzionalità a malapena funzionanti) possono essere migliorate e perfezionate, ed è un periodo in cui si correggono i bug. Questo tipo di congelamento viene solitamente messo in atto qualche tempo (un mese o due) prima di un rilascio: è facile rimandare un rilascio in attesa di "ancora una sola funzionalità", e un congelamento aiuta ad evitare questa situazione, piantando i paletti che servono; dà agli sviluppatori lo spazio di cui hanno bisogno per rendere un programma pronto per il rilascio.

Il secondo tipo di congelamento è il "congelamento del codice", che è molto più simile al rilascio di un software: una volta che un software è entrato in un "congelamento del codice", tutti i cambiamenti al codice sono scoraggiati e sono consentite solo le modifiche volte a correggere bug noti. Questo tipo di congelamento di solito segue un "congelamento delle funzionalità", e precede di poco un rilascio. La maggior parte del software rilasciato è in quello che potrebbe essere interpretato come una sorta di "congelamento del codice" di alto livello.

Anche si sceglie di non nominare mai un gestore dei rilasci (la Sezione 3.1.1.2), se è in atto un congelamento dichiarato pubblicamente sarà più agevole giustificare il rifiuto o lo slittamento di patch (la Sezione 3.2) prima di un rilascio.

3.5. Forks

Non ero sicuro sul modo di trattare il forking in questo documento (o se dovessi davvero trattarlo). Un "fork" si ha quando un gruppo di sviluppatori prende del codice da un progetto di software libero e lo usa per iniziare un progetto di software libero completamente nuovo. L'esempio più famoso di fork fu quello tra Emacs and XEmacs: i due emacs sono basati sulla stessa base di codice, ma per ragioni tecniche, politiche e filosofiche lo sviluppo fu spezzato in due progetti, che ora sono in competizione.

La versione breve della sezione sul fork è: non lo si faccia. I fork costringono gli sviluppatori a scegliere di lavorare con uno solo dei due progetti, causando divisioni politiche molto spiacevoli, e lavoro ridondante. Fortunatamente, di solito la sola minaccia di un fork è sufficiente a spaventare il manutentore o i manutentori del progetto, al punto di convincerli a correggere il loro modo di condurlo.

Nel suo capitolo su "The Open Source Process", Karl Fogel descrive il modo migliore di fare un fork, se proprio è necessario; se si è stabilito che è assolutamente necessario, e che le divergenze con le persone che minacciano il fork sono assolutamente senza soluzione, il libro di Fogel sarà buon punto di partenza.