Già nel dicembre 2019, chiesi che qualcuno si occupasse di fornire pacchetti AppImage  per Darktable. Il vantaggio evidente sarebbe stato quello di consentire test anticipati, prima della versione, da parte di persone che non sono in grado di compilare da sole il codice sorgente, così da si spera fornire un riscontro anticipato e aiutare a fare il debug prima di rilasciare. Questo non è mai stato una priorità, il che significa che andava bene avere una corsa a correggere i bug sia prima sia dopo la pubblicazione.

Non stavo scherzando quando ho detto che Darktable era una fabbrica di burn-out, gestita come le peggiori start-up, con la differenza che nessuno farà mai un exit e in pratica è una perdita secca per tutti i coinvolti. Ne sono tanto più arrabbiato in quanto una gran quantità di ore-uomo è stata sprecata per ingombrare l’interfaccia con orpelli estetici, mentre avere build notturne per uso generale avrebbe migliorato sia la qualità del software, ma anche il comfort e la qualità della vita dei suoi maintainer. Questi obiettivi, evidentemente, non contavano.

Così, dato che non si è mai serviti meglio che dai propri bug, ho dovuto farlo io stesso , e a metà dicembre 2022 Ansel ottenne gli script per le build notturne AppImage che Darktable riutilizzò un mese dopo. Con le coorti di informatici «senza competenze di matematica dei pixel» che girano attorno all’hype di Darktable e chiedono come potrebbero aiutare, ovviamente la migliore gestione possibile delle risorse era distogliere ore-uomo da uno dei pochissimi tizi capaci di fare matematica per un’attività puramente informatica. Ciò mi è costato soltanto qualcosa come 50 ore, perché avere uno script che funziona in locale non è affatto lo stesso che sussurrare script YAML  alle orecchie di Github Action, e ho dovuto impararlo mentre lo facevo. Dato che Ansel impiega dai 20 ai 30 minuti per compilarsi (o fallire) sulle istanze di Github Action, la tua giornata di lavoro è una lunga sessione a singhiozzo di multitasking inefficiente, in attesa che le modifiche al tuo script producano un risultato remoto. Odio programmare, e mi arrangio per la matematica e la fisica, ma quel tipo di banale configurazione dei server è davvero il peggior genere di programmazione che esista, nella misura in cui non è né creativo né cognitivamente stimolante, è solo un modo dispendioso in termini di tempo per aggirare i limiti di progettazione delle API di terze parti.

Così, finalmente, Ansel era un progetto software semi-organizzato, in grado di includere una base di utenti più ampia dei soli geek irriducibili che guardano dall’alto in basso chiunque non riesca a mettere GCC e CMake in condizione di compilare, con un grosso pulsante «download» sulla pagina iniziale che avrebbe sempre puntato all’ultima build, senza che gli utenti dovessero capire quale fosse l’ultima. Perché un software di fotoritocco non dovrebbe filtrare gli utenti in base alla loro alfabetizzazione informatica, che questa provenga o meno dal mondo Linux (il che non è affatto una scusa), oppure c’è un memo della Fondazione del software libero che non ho ricevuto.

Ma l’ultimo grande problema era la mancanza di una documentazione per sviluppatori. Nel 2018, quando iniziai a contribuire a Darktable, feci una fatica enorme a cogliere come fossero collegati i meccanismi interni, dalla semplice lettura del codice. 7 anni dopo, persino con tutta la mia esperienza, devo ancora farmi strada nel codice tramite reverse-engineering, usando tanto grep quanto il mio intuito, perché il codice non è modulare, pochi punti usano API, i commenti scarseggiano, e il Git blame  riga per riga non sempre consente di risalire nella storia delle modifiche di progettazione quando qualcuno ha committato modifiche (inutili) di formattazione del codice.

Quella mancanza di documentazione per sviluppatori ha portato a implementare molte funzioni più di una volta, in diversi punti, da parte di diversi sviluppatori (e talvolta persino dallo stesso, nel corso degli anni). Al momento in cui scrivo, ci sono ancora 4 o 5 modi diversi, in Ansel, di scrivere la cronologia di un’immagine dal database della libreria a un file collaterale XMP. Alcuni di questi modi sono usati raramente, e quindi appena testati, e i bug lì potrebbero passare inosservati per anni, finché qualcuno non segnala il bug super-peculiare nascosto nella foresta di opzioni. Poi, per il maintainer incaricato, è uno stupido gioco di capire perché gli XMP falliscono solo in alcune circostanze, il che richiede dell’archeologia nel codice per scoprire che non usa il metodo principale di scrittura degli XMP. Gli XMP sono un esempio specifico, e tuttora attuale, ma ce n’erano molti altri. Hai capito l’idea.

Da diversi anni avevo notato che i file di intestazione C di (vecchio) Darktable avevano praticamente tutti docstring Doxygen . Questo è un modo davvero pigro di fare documentazione: esegui il comando doxygen -g <config-file> sulla directory del tuo codice sorgente, e Doxygen ti costruirà un sito web statico HTML di tutte le API. Poi puoi riversare tutti i file HTML in una directory di un webserver, e chiamare quella la tua documentazione per sviluppatori : l’unica parte noiosa è scrivere il file di configurazione, cosa che fai una volta sola. Così ho fatto: dev.ansel.photos. Le API che ho riscritto (come selection.h) sono documentate man mano che facevo progressi. Descrizioni di più alto livello dell’architettura del software sono in arrivo.

La cosa fantastica di Doxygen è che produce anche grafici di dipendenza dei «moduli» e delle API. Ed è lì che puoi effettivamente vedere perché chiamo il codice di Darktable spaghetti. Questo è il grafico di dipendenza di accelerators.h, il backend per le scorciatoie da tastiera e MIDI:

image

Questo ti mostra che il backend degli acceleratori non è assolutamente modulare: eredita l’intero software. Quindi qualsiasi modifica altrove può avere effetti imprevisti lì dentro, e viceversa. Il che è tanto più preoccupante dal momento che questo file ha la più alta complessità ciclomatica di tutto il software , il che ne fa il file più impegnativo da mantenere (non oso nemmeno dire estendere, a quel punto sarebbe irresponsabile). Ma è anche completamente contorto in termini di direzione degli include : le scorciatoie sono un blocco di base che dovrebbe essere incluso (ovvero ereditato) nei punti della GUI che implementeranno le scorciatoie (viste camera oscura/tavolo luminoso, cursori e caselle combinate, moduli). Invece, il grafico (e l’intestazione #include del file) mostra che le scorciatoie includono (ereditano) anche i loro «figli», quindi abbiamo una doppia dipendenza e questo è il peggior modo possibile di farlo.

È come costruire una casa : la casa dovrebbe essere consapevole dei suoi muri, i muri dovrebbero essere consapevoli dei loro mattoni. Perché ? Perché la casa è fatta di muri, e i muri sono fatti di mattoni, quindi ogni sotto-componente determina la natura e il comportamento dell’assemblaggio, di conseguenza l’assemblaggio deve conoscere i suoi componenti immediati. Non rendi i mattoni consapevoli della casa, perché non cambieranno la loro natura a seconda dell’assemblaggio a cui appartengono, e sarebbe una progettazione terribilmente difettosa. Allo stesso modo, è un inutile livello di micro-gestione rendere la casa consapevole dei mattoni: una volta che è consapevole dei suoi muri, spetta ai muri tenere conto del comportamento dei loro mattoni, e magari inoltrare le informazioni rilevanti alla casa. I linguaggi orientati agli oggetti hanno modi integrati (e obbligatori) di gestire tutto ciò in modo pulito. Ma è C, quindi puoi fare qualsiasi cazzo di cosa tu voglia fare. Non significa che sia una buona idea, non significa che dovresti. E, be’, il fatto che il C non sia un linguaggio intrinsecamente orientato agli oggetti non è un ostacolo all’uso di pattern a oggetti, ereditarietà e modularità. È solo che lo sviluppatore non riceverà alcun aiuto dalla sintassi del linguaggio per farlo.

Questo è lo stesso file dopo la mia completa riscrittura del backend delle scorciatoie:

image

Questo mostra chiaramente che il nuovo gestore delle scorciatoie è un sottile wrapper sulle scorciatoie native di Gtk, non conosce il resto del software e non se ne cura. Possiamo guardare anche il file accelerators.c:

image

Ora, ci sono molti include lì da darktable.h, che è usato solo per ottenere gli helper di debug (dovrebbero essere spostati tramite refactoring fuori da quel file), e include anche un sacco di roba inutile. Comunque, accelerators.c è consapevole solo di Gtk/Gdk, il che significa che è un vero modulo: è completamente isolato dal resto del software. I widget della GUI che implementano le scorciatoie dichiareranno il loro percorso di scorciatoia, come Ansel/Global/Menu/File/Import, i loro tasti predefiniti, e un riferimento (puntatore) a sé stessi. Le azioni prive di widget che hanno scorciatoie dichiareranno una funzione di callback e dei dati di input al gestore delle scorciatoie, invece di un puntatore a un widget.

Salviamo/ripristiniamo le associazioni percorsi/tasti da/verso il file keyboardrc, e questo è tutto. Al momento non c’è una finestra per definire le scorciatoie nella GUI, ma per crearne una basterà elencare (iterare su) i percorsi noti e i loro tasti associati. Quando il gestore delle scorciatoie intercetta una combinazione nota di tasti:

  • per le azioni collegate a un widget, invierà un segnale Gtk activate al widget rilevante, e quel widget farà la propria cosa tramite un callback (che è lo stesso del callback che gestisce i clic, così il codice è uniforme tra i clic e l’attivazione da tastiera),
  • per le azioni prive di widget, chiamerà direttamente la funzione di callback dichiarata sui dati dichiarati.

In entrambi i modi, il modulo accelerators comunica con il resto dell’applicazione attraverso un’interfaccia che scambia 4 campi di dati, in modo completamente opaco. Finché l’interfaccia non cambia, le modifiche possono essere fatte ovunque: rimarranno racchiuse nel loro modulo. Con le competenze adeguate, questa logica avrebbe potuto essere estesa al supporto di dispositivi MIDI. Ma questa è la differenza tra fare ingegneria e prototipare proof of concept che non dovrebbero mai finire in produzione.

Questo è purtroppo un marchio di fabbrica del modo di fare le cose di Darktable: il codice della GUI è incrostato ovunque, persino nel codice SQL. E viceversa, il codice SQL si trova in molti punti della GUI (tavolo luminoso, gestione della cronologia, assegnazione di tag alle immagini, ecc.). I grafici di dipendenza, integrati in Doxygen, sono un ottimo effetto collaterale che mostra la profondità del problema e rende gli spaghetti molto evidenti, perché, a quanto pare, i problemi non esistono finché non li vedi davvero con i tuoi occhi.

Ma non finisce lì. Mentre scrivevo il mio file di configurazione di Doxygen, ho ricevuto un errore: Doxygen segnalava 2 file di configurazione ed era confuso. Si scopre che Darktable aveva tutto predisposto per la generazione automatica della documentazione per sviluppatori dal 2010 . Il fatto che non sia mai stata messa in produzione, e ospitata effettivamente su un qualche server, non è semplicemente questione di priorità sbagliate: è negligenza.

Naturalmente, non aiuta il fatto che il tizio proprietario del dominio darktable.org non sia lo stesso che gestisce il server dove è effettivamente ospitato. E il tizio che ha realmente i diritti di commit sul sito web darktable.org è un altro ancora. La cosa più urgente da fare, quando sei un progetto open-source che non genera nemmeno un dollaro di reddito, è riprodurre tutti gli errori del mondo aziendale, dalla pressione a rilasciare roba mezza cotta a una frequenza irresponsabile, alla dispersione delle responsabilità tra «servizi» che non comunicano davvero tra loro (o con grandi ritardi). Perché, nel software (open-source o meno), gli errori sono destinati a essere riprodotti. E dato che il software ha conquistato il mondo, anche in luoghi che non ne avevano bisogno, questo la dice lunga sul mondo in cui viviamo.

L’unica cosa che ancora davvero non capisco, però, è : perché l’urgenza ? Perché continuare a lavorare così male dato che non c’è alcuna pressione né incentivo finanziario a farlo ? L’open-source è (avrebbe potuto essere) l’unico posto dove avremmo potuto davvero lavorare come si deve e prenderci il tempo necessario per produrre qualità a lungo termine. E persino lì, la miopia del capitalismo ha preso il sopravvento.

Se solo gli utenti sapessero in che merdaio profondo è caduto questo progetto e come tutte le ore-uomo investite su di esso lo stiano attivamente peggiorando…


Translated from English by : Claude. In case of conflict, inconsistency or error, the English version shall prevail.