W moim przełomowym wpisie, Darktable: crashing into the wall in slow-motion, przedstawiłem katastrofę, jaką był nowy „Wielki turducken MIDI". Celem tego turduckena1 było przepisanie systemu skrótów klawiszowych, aby rozszerzyć go o urządzenia MIDI.
Do dziś jestem wściekły na to przedsięwzięcie masowego niszczenia, oto podsumowanie powodów:
- w 2021 roku zastąpił system skrótów klawiszowych, który był całkiem dobry, kompletny funkcjonalnie, dobrze przetestowany, stabilny i zakodowany w mniej niż 1500 liniach (łącznie z komentarzami),
- …aby dodać obsługę urządzeń MIDI i gamepadów PlayStation (!?!)…
- …ale w moim ankiecie Darktable z 2022 roku, rok po tej nowej funkcji, spośród ponad 1251 użytkowników, którzy wzięli udział:
- 81% użytkowników nie miało urządzenia MIDI i nie planowało go kupić,
- 2% nawet nie wiedziało, czym jest urządzenie MIDI.
- 8% użytkowników miało urządzenie MIDI, ale nie używało go z Darktable,
- 6% rozważało może kupno urządzenia MIDI w przyszłości,
- 2% użytkowników miało urządzenie MIDI, którego faktycznie używało w Darktable,
- kod był absolutnie okropny pod względem:
- jakości kodu: nieczytelne instrukcje
if/switch-casezagnieżdżone na 4 poziomach, w środku funkcji liczących 1000 linii (przykładowe fragmenty zamieściłem w moim artykule), - objętości kodu:
- 3546 linii kodu dla Darktable 4.0,
- 4397 linii kodu dla Darktable 5.0,
- wzrost objętości jest bezpośrednim skutkiem prób naprawiania błędów w architekturze, której nie da się naprawić, ponieważ jej złożoność sprzyja jeszcze większej złożoności. Wszystko to wynika z projektu, ale rozwiązywanie problemów stworzonych przez złożoność poprzez dodawanie kolejnej złożoności nie jest rozwiązaniem.
- złożoności kodu:
- złożoność cyklomatyczna :
- 1088 dla Darktable 4.0,
- 1245 dla Darktable 5.0 (szczegóły ),
- złożoność poznawcza :
- 1885 dla Darktable 4.0,
- 2098 dla Darktable 5.0 (szczegóły ).
- jest to zdecydowanie najbardziej złożona funkcja oprogramowania, mimo że nie operuje na obrazach. Dla porównania, drugą najbardziej złożoną funkcją jest dekodowanie metadanych EXIF, którego złożoność poznawcza wynosi 1348.
- złożoność cyklomatyczna :
- jakości kodu: nieczytelne instrukcje
- z założenia nie dekoduje modyfikatorów klawiszy, lecz zajmuje się wyłącznie sprzętowymi naciśnięciami klawiszy, co oznacza, że:
- wejście „1" z klawiatury numerycznej jest dekodowane jako
Keypad End, - wejście „1" z francuskiej klawiatury AZERTY jest dekodowane jako
Shift+&lubShift+"na BÉPO, - musisz zatem zduplikować wszystkie swoje skróty oparte na cyfrach dla każdego sposobu wprowadzania cyfry i przygotować się na to, że okno ustawień skrótów nie będzie zawierać żadnej faktycznej cyfry w kombinacjach klawiszy.
- wejście „1" z klawiatury numerycznej jest dekodowane jako
- projekt od strony użytkownika jest absolutnie okropny, ze zdecydowanie zbyt wieloma akcjami i emulacjami do skonfigurowania („efektami"), które nawet 4 lata później nie są w pełni udokumentowane (czym jest „ctrl-toggle"? „right-activate"?), a konfiguracja skrótów używa dziwnego podzielonego okna, które nie ma żadnego sensu,
- implementacja jest równie okropna: funkcja jest świadoma całego GUI oprogramowania, a GUI oprogramowania jest świadome kodu skrótów. Nie ma tu żadnej modularności, a zmiana czegokolwiek w kodzie skrótów może mieć nieoczekiwane i niepożądane skutki gdziekolwiek w oprogramowaniu.2 Spójrz tylko na graf zależności poniżej,
- kilka „skrótów" (lub powiązań MIDI) może być przypisanych do tej samej akcji, co oznacza, że każda interakcja użytkownika musi przeszukać całą listę dostępnych akcji, powodując bardzo nieefektywną obsługę skrótów, w niektórych przypadkach opóźnienia GUI oraz fałszywe alarmy „nieznana kombinacja klawiszy" w szczególnych przypadkach.


Graf zależności src/gui/accelerators.c (Wielki turducken MIDI) przed przepisaniem. Zgadnij, dlaczego nazywamy to „kodem spaghetti "… Widać wyraźnie, że istnieje dwustronna zależność między kodem akceleratorów a resztą kodu GUI. Utrzymanie tego to koszmar.
Zatem, mówiąc inaczej, jeden (bardzo zły) programista zastąpił działającą i prostą funkcję potworkiem, za aprobatą opiekuna (który sam nigdy nie napisałby tak złego kodu, ale jest zdeterminowany, by „nie tracić rozpędu" we wkładach, bez względu na cenę), aby zadowolić 2% bazy użytkowników. Wszystko to dla drugorzędnej (trzeciorzędnej?) funkcji.
Nazywam to złymi priorytetami. Zwłaszcza że zajęło to kilka miesięcy ciężkiej pracy jednego programisty i wielu beta-testerów, tylko po to, by pogorszyć sytuację, a potem ta ciężka praca stała się usprawiedliwieniem, by nigdy nie wycofać zmiany, co jest znane jako błąd utopionych kosztów .
Jestem użytkownikiem, nie obchodzi mnie kod
Dbanie o kod aplikacji, których używasz, jest jak dbanie o to, czy rury doprowadzające wodę do Twojego domu są z ołowiu. To nie Twoje zadanie, rury są zakopane poza zasięgiem wzroku, więc masz wszelkie powody, by się tym nie przejmować — a ludzie odpowiedzialni za sieć wodociągową mają wszelkie powody, byś się tym nie przejmował — ale będą one miały wpływ na Twoje zdrowie, a te skutki będą niewidoczne, dopóki nie będzie za późno. Oprogramowanie może nie mieć bezpośredniego wpływu na Twoje zdrowie,3 ale sposób, w jaki jest wykonane, będzie miał długoterminowy wpływ na Ciebie.
Znajduję się w niewygodnej pozycji – Kasandry — muszącej tłumaczyć użytkownikom, że problemy, których nie znają, nie widzą i które ich nie obchodzą, bardzo mocno wpływają na codzienną użyteczność i stabilność narzędzi, których używają, ale w nieoczywisty sposób. W każdym razie problemy te bezpośrednio wpływają na prawdopodobieństwo, że jakikolwiek opiekun któregoś dnia rozwiąże błędy, z którymi się mierzy.
Przynoszenie złych wieści czyni cię złą wieścią, ale przynoszenie złych wieści, które nikogo nie obchodzą, czyni cię dupkiem, mimo że te złe wieści wyjaśniają dziwne i losowe problemy, które stają się coraz powszechniejsze w systemach śledzenia błędów Darktable od 2021 roku, a które nie są rozwiązywane latami, ponieważ na tym etapie kod nie zawiera błędów, on jest błędem. Ale tutaj musisz zmierzyć się z bańkami filtrującymi : w zależności od tego, gdzie w sieci spojrzysz, znajdziesz albo ludzi głęboko zadowolonych z Darktable (wydajność, stabilność, projekt), albo ludzi głęboko z niego niezadowolonych. Moja empiryczna obserwacja jest taka, że zadowoleni obozowicze przeciętnie posiadają potężne komputery i mają dyplomy STEM.4 Niezadowoleni ludzie mają tendencję do odchodzenia i ograniczania czasu, który tracą z oprogramowaniem, co oznacza, że jeśli nie szukasz ich aktywnie, będziesz tylko karmić swój błąd ocalałego . I choć nie widzę sensu w próbach nawracania użytkowników na Darktable (ani na jakikolwiek edytor zdjęć open-source), bo każdemu według potrzeb, odsiewanie i zniechęcanie użytkowników na podstawie ich biegłości w obsłudze komputera jest wielką porażką dla każdej aplikacji do edycji zdjęć.
Jako facet z kanałem na Youtube wyjaśniającym, jak używać Darktable, i prowadzący indywidualne sesje szkoleniowe, mam tendencję do przyciągania bardziej różnorodnych opinii niż tylko systemy śledzenia zgłoszeń na Githubie (gdzie krytyka projektu i tak jest dość szybko uciszana), i na własne oczy jestem świadkiem, podczas rozmów wideo, tych dziwnych, losowych i niereprodukowalnych błędów. Każdy uprzywilejowany facet ma tendencję do zaprzeczania, bagatelizowania lub lekceważenia świadectw dotyczących problemów, z którymi sam się nie mierzy, a nawet do obwiniania za problemy osoby, która je zgłasza. Mam więc często wrażenie dwóch równoległych wszechświatów, które się nie komunikują, ale patrzą na siebie z góry, jeśli chodzi o opinie na temat Darktable. Oczywiście programiści Darktable wybrali patrzenie tam, gdzie świeci słońce.
I choć Darktable wygląda na aktywny projekt z mnóstwem nowych funkcji dodawanych regularnie przez tuzin facetów, tym trudniej jest wyjaśnić, że tym, co faktycznie dzieje się za kulisami, jest niszczenie bazy kodu, ponieważ jakość kodu bardzo się pogarsza z upływem czasu, aż w końcu debugowanie nie będzie w ogóle możliwe. Objętość zmian nie mówi nic o jakości, niezawodności czy łatwości utrzymania. Ale 2 wieki kapitalizmu uwarunkowały nas do poszukiwania błyszczących nowych funkcji, bez względu na cenę, a pod tym względem Darktable spełnia oczekiwania.
Kod rodzi się zepsuty. Każde oprogramowanie ma błędy. Co gorsza, używamy wielu bibliotek zewnętrznych, aby uniknąć „wynajdowania koła na nowo", ale te biblioteki zmienią w przyszłości swoje API , co oznacza, że kod, który działa dziś, przestanie działać jutro i będzie musiał zostać przerobiony w przyszłości, gdy zmienią się zależności. Kod jest jak ogród: każdy nowy sezon przynosi swoją porcję obowiązków. Nazywa się to utrzymaniem. Gdy się to uzna, mądrość polega na planowaniu sposobów, by uczynić utrzymanie najpierw możliwym, a potem łatwym.
Dobry kod to kod łatwy w utrzymaniu. To znaczy, dobry kod jest napisany w sposób miły dla ludzi, którzy muszą go czytać, rozumieć i naprawiać. Nie piszemy kodu dla komputerów. Nie piszemy kodu po to, by funkcje „po prostu działały" teraz i w najbliższych miesiącach. Kod nie jest czymś, co chowamy pod ładną maską, mając nadzieję, że już nigdy nie będziemy musieli na to spojrzeć. Kod jest żywym organizmem, którego utrzymanie przy życiu kosztuje energię i czas.
Utrzymanie ma swój koszt, który często jest niedoceniany. Nie ma znaczenia, czy twój produkt jest najlepszy na rynku, jeśli koszty utrzymania są zaporowe, (poinformowani) klienci będą go unikać. Utrzymanie jest nudne, nieciekawe, nieseksowne. Utrzymanie jest przeciwieństwem wprowadzania błyszczących nowości: to zapewnianie, że zakurzone stare rzeczy nadal cicho działają. W notatkach o wydaniu twojego oprogramowania trafia na koniec. Użytkowników nie ekscytują utrzymywane funkcje, ale wściekną się z powodu nieutrzymywanego kodu i mają tendencję do używania niewłaściwej miary do oceny, jak dobrze projekt jest utrzymywany (czyli: krzątanina i pozory pracy). Nie wygrasz więc nic na utrzymywaniu kodu, ale stracisz na jego nieutrzymywaniu, i będzie cię to kosztować, czy to robisz, czy nie.
Kod jest nie do utrzymania, gdy każda poprawka błędu prowadzi do nowego błędu gdzie indziej, w stylu whack a mole, a natura poprawek błędów to w rzeczywistości kontekstowe łatanie i obejścia, które tylko dodają oprogramowaniu złożoności. Gdy osiągniesz ten punkt, twoją jedyną opcją jest przepisanie inkryminowanego kodu od zera. Co oznacza, że przeszła praca właśnie stworzyła więcej pracy teraz. A gdy ta konkretna przeszła praca już nadpisywała wcześniejszą pracę, wchodzimy w idiokrację.
Więcej kodu nie jest sukcesem ani osiągnięciem. Osiągnięcia są w rozwiązywaniu problemów użytkowników. Tu znowu kapitalistyczny sposób myślenia uderza w nas mocno: chcielibyśmy mierzyć pracę objętością dodanego kodu. Więcej kodu to po prostu więcej zobowiązań, więcej długu technicznego, więcej kosztów utrzymania. To dysonans poznawczy, skoro oprogramowanie polega właśnie na pisaniu kodu. Ale pomyśl o tym tak: budowanie samochodu nie polega na dodawaniu coraz więcej stali na 4 kołach, bo w pewnym momencie samochód będzie musiał się poruszać. Potrzebujesz odpowiedniej ilości stali, ukształtowanej we właściwy sposób we właściwych miejscach: musisz być wydajny i oszczędny. Oprogramowanie polega na rozwiązywaniu problemów użytkowników za pomocą komputerów, a nie na gromadzeniu kodu.
W projektach, gdzie współtwórcy nie są opłacani, nudne utrzymanie nie jest tym, na co ludzie chcą poświęcać swoje soboty, i jest to realny problem, jeśli chodzi o zarządzanie projektem. Tym ważniejsze jest, by ułatwić utrzymanie, gdy ludzie pracują za darmo. Na szczęście Darktable ma zerowe zarządzanie projektem, tylko rój przypadkowych współtwórców drapiących się tam, gdzie ich swędzi, w przypadkowych momentach, bez ujednoliconego celu, strategii, harmonogramu czy podziału pracy. Dlatego chciałbym, żeby wszyscy przestali używać określenia „zespół Darktable". Nie ma żadnego zespołu Darktable, bo nie ma podziału pracy, przywództwa, harmonogramu, planu działania, planowania, celu, priorytetów, wizji, strategii, metody, projektu, komunikacji przed robieniem rzeczy, dokumentów specyfikacji dla problemów do rozwiązania. To licealny klub informatyczny, złożony z odłączonych od siebie jednostek.
Są 3 rzeczy, które programista musi zrobić, aby zapewnić, że utrzymanie jest tak łatwe, jak to tylko możliwe:
- pisać jak najmniej kodu: śledzenie błędu wśród 300 linii będzie znacznie szybsze niż wśród 3000 linii,
- pisać jak najprostszy kod: „prosty" w sensie „logika funkcjonalna ma niewiele kroków, niewiele założeń, niewiele przypadków skrajnych". Prostszy oznacza łatwiejszy do czytania, rozumienia i naprawiania, ale także taki, że będzie mniej przypadków do pokrycia podczas testowania. W praktyce oznacza to unikanie przypadków kontekstowych, opcji użytkownika, wariantów,
if/elsew kodzie. - pisać samozamknięty kod: podzielić funkcjonalność oprogramowania na moduły (podprogramy), które komunikują się przez rdzeń i są odizolowane od siebie nawzajem. W miarę jak objętość kodu rośnie, gwarantuje to, że zmiany zachodzące wewnątrz modułów nie będą miały nieprzewidzianych skutków na zewnątrz.
Wreszcie, musisz ocenić, czy nowe funkcje, które dodajesz, są warte dodatkowego kosztu utrzymania. W przypadku obsługi skrótów zaspokajamy „potrzeby" (a raczej luksus) 2% bazy użytkowników za pomocą implementacji, która jest (co najmniej) dwukrotnie bardziej skomplikowana niż ta, którą zastąpiła. Rozważ to w swoim kapitalistycznym umyśle…5
Złożoność kodu można mierzyć za pomocą teorii grafów, poprzez złożoność cyklomatyczną, złożoność poznawczą lub złożoność N-path. Wiele artykułów naukowych koreluje objętość kodu i/lub złożoność kodu z liczbą ukrytych błędów, co jest dość intuicyjne: linia kodu, której nie napiszesz, jest jedyną, w której nigdy nie będziesz mieć błędów. Prostota jest celem. I, jak przekonałem się na własnej skórze, złożoność GUI (front-endu) jest często bezpośrednim skutkiem złożoności back-endu. Jest wielu facetów wyjących do księżyca, by przywołać mistyczną postać projektanta UI/UX, mając nadzieję na magiczne rozwiązanie okropnego GUI Darktable (skomplikowanego i niespójnego). GUI nie istnieje równolegle do back-endu, ono tylko podłącza dane wejściowe oczekiwane przez back-end do graficznych kontrolek. Uproszczenia front-endu nie da się zrobić bez uproszczenia back-endu, to po prostu głupi dogmat wymyślony przez ludzi mających jedynie umiejętności miękkie. Ale upraszczanie back-endów jest o wiele bardziej skomplikowane niż samo rysowanie makiet.
Jak się okazuje, to, co stało się z Wielkim turduckenem MIDI, zawiodło na wszystkich 3 frontach: objętości kodu, złożoności kodu, samozamkniętości kodu. A programiści Darktable nigdy nie nauczą się na swoich błędach, czego dowodzi Darktable 5.0. W miarę jak błędy skrótów klawiszowych piętrzyły się z czasem w Ansel (na dodatek do funkcji okropnych z założenia), próbowałem naprawiać je w sposób, który unikał przepisywania całości, aż stało się dość jasne, że nie zdołam znacznie dłużej uniknąć przepisania.
Nazywa się to długiem technicznym . Cały kod Wielkiego turduckena MIDI miał działać, gdy tylko został napisany, a nie być łatwy w utrzymaniu na dłuższą metę. To w zasadzie dowód koncepcji, który nigdy nie powinien trafić do produkcji. A samym dowodem jego niemożności utrzymania jest to, jak bardzo objętość i złożoność kodu urosły od poprawki do poprawki, między Darktable 3.8 a 5.0, czyniąc go jeszcze trudniejszym w utrzymaniu w miarę naprawiania błędów. To definicja przyklejania się do pajęczyny: im bardziej się ruszasz, tym bardziej się zaplątujesz.
Moim błędem jest być może to, że zacząłem podnosić moją krytykę (braku) zarządzania Darktable w 2022 roku, po tym, jak zdobyłem dowód, że zdezorganizowana zgraja współtwórców nigdy nie uzna swoich błędów ani się na nich nie nauczy. Choć samonarzucone i niezrównoważone tempo pracy bardziej sprzyjało tworzeniu wypalenia niż refleksji. Od tamtej pory Pascal Obry, obecny samozwańczy opiekun Darktable, próbuje przekonać wszystkich, że jestem nieznośnym członkiem zespołu, niezdolnym do pracy z innymi osobami, które się ze mną nie zgadzają, który zaczął wszystkich obrażać. Oczywiście nie udzielono żadnej konkretnej i technicznej odpowiedzi na kwestie, które podniosłem w Darktable: crashing into the wall in slow-motion, tylko niejasno uspokajające ogólnikowe stwierdzenia w tonie „Darktable to aktywny projekt, zdrowy, bo ma wielu współtwórców". Jakby więcej zdezorganizowanych małp w końcu dorównało inżynierowi, gdyby dodać ich wystarczająco dużo.
Myślę, że przez 4 lata byłem niczym innym jak miły – w istocie zbyt miły — dopóki nie zdałem sobie sprawy, jak bardzo ci faceci zaszkodzili projektowi. Nie uczą się i nigdy nie nauczą się na swoich błędach, bo nawet ich nie uznają, a ewolucja Darktable 5.0 tylko potwierdza ten trend. Ale piętrzenie się coraz większej liczby dziwnych, losowych i niereprodukowalnych błędów w systemach śledzenia błędów jest dość wyraźną wskazówką, że coś jest głęboko nie tak. Zwłaszcza że badanie tych błędów prowadziło mnie do archeologii w okropnych stosach gówna-kodu, który nie miał nawet 2 lat, i mimo że moja wiedza i doświadczenie z bazą kodu Darktable rosły przez lata, moja zdolność do naprawiania pierwotnej przyczyny błędów malała, a mierzyłem się z coraz bardziej zbijającymi z tropu labiryntami pośrednictw kodu .6
Trudno to wszystko wytłumaczyć ludziom, którzy postrzegają komputery jako magiczne pudełka zaprojektowane przez technologicznych czarodziejów. Nie ma tam żadnej magii. To głównie matematyka i zastosowania. Wielu programistów przyzna, że są słabi z matematyki, co oznacza, że są też słabi w programowaniu. Bo matematyka to nie tylko wykonywanie operacji arytmetycznych, to cała dyscyplina umysłu pozwalająca abstrahować złożone problemy, aby rozbić je na proste problemy, co doprowadzi do prostego kodu i prostego GUI. Dobrzy programiści spędzają dużo czasu, myśląc o tym, jak napisać mało kodu. Bo kod jest zobowiązaniem, kod jest długiem technicznym, kod jest kosztowny w utrzymaniu. Spłacasz więc dług z góry, bez odsetek, myśląc dużo o swoim kodzie, zanim go napiszesz, zamiast najpierw kodować, a potem spędzać lata na gaszeniu pożarów.
Wszystko to rodzi też pytanie, kto jest właścicielem kodu open-source i projektów open-source. Odkąd założyciel projektu Darktable, Hanatos, opuścił statek, podobnie jak cała pierwsza generacja programistów, z różnych powodów, ostatni pozostały człowiek z pierwszej generacji mianował się nowym opiekunem. Jest bardzo zdolnym i wykwalifikowanym programistą: jego kod jest czysty, uporządkowany, i jak dotąd nie znalazłem żadnego błędu w linii, w której git blame wskazywał „Pascal Obry". Ale jego polityka dotycząca zarządzania kodem jest okropna: wierzy, że każdy wkład jest dobrym wkładem, że „rozpędu" wkładów nie należy zniechęcać, i jest po prostu niezdolny do powiedzenia „nie" wkładom, co oznacza, że niemal wszystkie pull requesty zostają scalone. To Francja w 1940 roku: wszystko wchodzi, jest witane z szerokim uśmiechem, a Führer dostaje dwa razy więcej Żydów, niż zażądał. Tymczasem członków ruchu oporu nazywa się terrorystami.
Ale istnieje ogromna różnica między jakością kodu, który Pascal pisze, a jakością kodu, który przyjmuje i scala. To niepokojący paradoks znajdujący swoje korzenie między lękiem przed przegapieniem czegoś a radykalnym technopozytywizmem , który błądzi po stronie dogmatu i przekonań, z całkowitym lekceważeniem projektu i perspektywy użytkownika. I być może przesadnym zaufaniem do zdolności „Wspólnoty" do naprawiania błędów później.
Jest wiele przypadków, w których nierobienie niczego jest lepsze niż zrobienie tego źle, zwłaszcza gdy zastępujesz istniejące funkcje. Ponieważ Darktable jest nieniszczącym edytorem kodu, inwestujesz w niego, gdy zaczynasz bazę danych edycji obrazów. Chyba że planujesz eksportować wszystkie swoje obrazy do plików o wysokiej rozdzielczości i dużej głębi bitowej, gdy tylko skończysz je edytować, by nigdy więcej ich nie zmieniać. To tworzy uzasadnione oczekiwanie długoterminowej stabilności i spójności, tak by twoje stare edycje wciąż można było otworzyć, dopracować i ponownie wyeksportować, być może do nowych formatów, być może do wyższych rozdzielczości. Zmiana kursu w projekcie aplikacji jest swego rodzaju naruszeniem umowy, i chociaż licencja GNU/GPL unieważnia wszelką odpowiedzialność prawną, nie unieważnia szkód wyrządzonych użytkownikom. Nie zwraca też lat mojego życia, które straciłem na naprawianie ich gówna.
Zatem, nawet pomijając kwestie utrzymania skoncentrowane na programiście, jest też do przeprowadzenia dyskusja na temat tego, kto ma decydować, jak stare i sprawdzone funkcje zostają zastąpione, zwłaszcza te podstawowe i uniwersalne funkcje aplikacji desktopowych, jak obsługa plików (import, eksport, przeglądanie) czy interakcja myszą i klawiaturą, które były tak wszechobecne od tak dawna, że lata 2020. są 30 lat za późno, by udawać, że wynajdują je na nowo.
Mnóstwo pracy i roboczogodzin zainwestowano w pogorszenie skrótów klawiszowych, w imię wadliwej polityki i szkodliwych dogmatów, na dodatek do pobożnych życzeń i próżniactwa społecznego , gdzie wszyscy mają nadzieję, że Wspólnota® (czyli ktoś inny) zajmie się naprawianiem ich własnych błędów. Użytkownicy musieli też stracić swoją konfigurację klawiatury i byli zmuszeni wszystko zresetować i wszystkiego nauczyć się od nowa. Ale zrobienie tego we właściwy sposób kosztowałoby w rzeczywistości mniej pracy i mniej roboczogodzin. To samonapędzająca się pętla szaleństwa, tworząca toksyczne środowisko pracy, gdzie niestabilność sprzyja jeszcze większej niestabilności, gdzie złożoność sprzyja jeszcze większej złożoności, znowu bez jakiegokolwiek planu działania dla funkcji, który dałby wszystkim zaangażowanym ogólny kierunek i widoczność.
Krótka historia złego projektu
Dopiero po zrekonstruowaniu funkcji skrótów od zera zrozumiałem, co poszło nie tak w skrótach/akceleratorach Darktable.
Na początku jest ta paraliżująca rozpusta funkcji, która sprawia, że kuszące staje się odchudzenie GUI poprzez zwykłe ukrywanie funkcji, tylko po to, by były obsługiwane z klawiatury. Problem polega wtedy na tym, że takie funkcje nie zawsze są niszowe i opcjonalne (jak skrót omijający interakcje z maską przy przeciąganiu i upuszczaniu głównego podglądu obrazu w ciemni), ale są zdecydowanie nie do odkrycia przez użytkowników. Ansel rozwiązał ten problem za pomocą globalnego menu.
Niektóre funkcje były ukryte poprzez podstawową obsługę vimkeys, jeśli zaczniesz wpisywać :: :q zamknie aplikację, :set a po nim nazwa suwaka lub listy rozwijanej zmieni wartość. Nie jest to oczywiście nigdzie udokumentowane w podręczniku Darktable, i jako użytkownik Darktable od ponad dekady nigdy o tym nie słyszałem, zanim nie usunąłem tego kodu, ponieważ ten mały żarcik nasłuchuje wszystkich twoich naciśnięć klawiszy, by ustalić, czy powinien zareagować na twoje pisanie, czy nie.
Ale jest też fakt, że moduły używają domowej roboty widżetów Gtk (nazwanych „Bauhaus", w src/bauhaus/bauhaus.c), które nie implementują wszystkiego, czego oczekiwałbyś od widżetu GUI przechwytującego zdarzenia użytkownika, zwłaszcza nie funkcji dostępności.
Jedną z najbardziej podstawowych funkcji dostępności jest możliwość przechodzenia między widżetami, które mogą otrzymać fokus. W żargonie GUI (i Gtk) widżet, który może otrzymać fokus, to taki, który może przechwytywać zdarzenia naciśnięcia klawisza, gdy jest sfokusowany. Widżety są zazwyczaj fokusowane po kliknięciu, ale Gtk zarządza też wewnętrznie łańcuchem fokusu , po którym nawigujesz klawiszem Tab i klawiszami strzałek. Pierwszy problem to klawisz Tab, który w Darktable był przypisany do trybu „podglądu" (włączanie/wyłączanie wszystkich paneli w widoku). I w rzeczywistości, używając natywnych akceleratorów Gtk, nie byłoby to w ogóle możliwe, ponieważ Tab jest przypisany przez Gtk i zakazany w skrótach zdefiniowanych przez użytkownika, ale ponieważ Darktable zaimplementowało własną obsługę skrótów, jeszcze przed Wielkim turduckenem MIDI, został on nadpisany. Zatem przechodzenie po łańcuchu fokusu oparte na tabulacji było wyłączone po prostu dlatego, że klawisz Tab był przypisany do czegoś innego. Ale drugim problemem było to, że domowej roboty widżety Bauhaus przechwytywały też wszystkie naciśnięcia klawiszy strzałek. Tak więc nawigacja między kontrolkami w sposób sekwencyjny (następny/poprzedni) była również całkowicie niemożliwa, z założenia. Tak samo jak widżety Bauhaus przechwytywały wszystkie zdarzenia przewijania myszą, uniemożliwiając przewijanie paneli bocznych.
Ponieważ sekwencyjna/przyrostowa nawigacja między widżetami, które mogą otrzymać fokus, była z założenia niemożliwa, wszystkie interakcje klawiaturowe musiały być z konieczności absolutne: dla każdego suwaka, dla każdej listy rozwijanej miałbyś skrót bezpośrednio przypisany do zwiększania/zmniejszania/resetowania wartości.
Ale więcej problemów pojawiło się, gdy moduły stały się wielokrotnie instancjonowalne, ponieważ kontrolki były identyfikowane przez ścieżkę akceleratora typu view/module/slider/increase lub view/module/slider/decrease, ale wszystkie instancje modułu dziedziczyły tę samą ścieżkę. To wywołało potrzebę zarządzania tym wszystkim w czasie działania, z preferencjami użytkownika decydującymi, czy docelowym modułem będzie pierwszy, ostatni czy ostatnio używany moduł.
Uogólnienie tego wszystkiego na MIDI i gamepady tylko pogorszyło sprawę, ponieważ na dodatek do posiadania jednego skrótu na możliwą akcję na widżet, pojawiła się potrzeba zarządzania emulacją typowej interakcji desktopowej z innych urządzeń wejściowych. Ale zamiast zarządzać warstwą emulacji wysokopoziomowo, na styku między MIDI a zwykłymi skrótami klawiatury/myszy, okropny programista całkowicie przeinżynierował warstwę abstrakcji akcji, wbudowaną w moduły, natywne widżety Gtk (jako nakładka) i domowej roboty widżety Bauhaus (głęboko wbudowaną). Problem polega na tym, że ta warstwa abstrakcji nie była tak naprawdę warstwą, lecz bardziej przerzutowym guzem rozprzestrzeniającym się wszędzie. Usunięcie jej i wszystkich jej zależności doprowadziło do usunięcia 7674 linii rozłożonych na 163 plikach, mimo że miała być zaimplementowana w src/gui/accelerators.c (4412 linii kodu, komentarzy i pustych linii).
Przeprojektowanie skrótów klawiszowych/akceleratorów od zera
Zerowym krokiem przeprojektowania są te 2 proste wymagania:
- Każda akcja powinna być do odkrycia w GUI, skróty klawiszowe nie są przeznaczone do odchudzania GUI; odchudzanie GUI polega na rozbiciu przepływu pracy na jednostkowe kroki i prezentowaniu tylko tych kontrolek, które mają znaczenie dla bieżącego kroku.
- Oprogramowanie powinno być w pełni obsługiwalne samą myszą i samą klawiaturą. Mieszana interakcja powinna być całkowicie opcjonalna.
Pierwszym ograniczeniem przeprojektowania jest zatem uczynienie skrótów absolutnych całkowicie opcjonalnymi, to znaczy zaprojektowanie klawiaturowego przepływu pracy dla dostępu sekwencyjnego/względnego (przechodzenie między następną/poprzednią kontrolką).
Względna nawigacja klawiaturowa
Pierwszym elementem rozwiązania jest tu globalne menu, które przechowuje wiele przycisków wcześniej ukrytych w zwijanych modułach (a czasem w zwijanych sekcjach zwijanych modułów, bo współtwórcy Darktable zakochali się w nich od 2021 roku). Usunięcie tych modułów pozwoliło zwolnić prawy pasek boczny w stole podświetlanym, przeznaczając więcej przestrzeni ekranu na miniatury. Wpisy menu mają mnemoniki klawiszowe, to znaczy po naciśnięciu Alt jedna litera w ich etykiecie zostanie podkreślona i, jeśli zostanie naciśnięta przy wciśniętym Alt, rozwinie odpowiednie menu. Gdy menu jest rozwinięte, po wszystkich menu można nawigować klawiszami strzałek, a odpowiadające im akcje można wywołać klawiszem Enter.
To jest nie tylko całkowicie standardowe, jeśli chodzi o paradygmat GUI, ale też zapobiega konieczności ustawiania i zapamiętywania jakiegokolwiek skrótu. Wisienką na torcie jest to, że menu to natywne obiekty Gtk, które dodają bardzo mało narzutu kodu i są już podłączone do wszystkich typowych metod dostępności, od ręki.
Ponieważ skrót Tab również został oddzielony od funkcji pełnego podglądu, jest on wtedy dostępny do przechodzenia w dół łańcucha fokusu, w obrębie natywnych widżetów Gtk, i rozszerzyłem domowej roboty widżety Bauhaus, by obsługiwały fokusowanie jak każdy natywny widżet Gtk.
W widoku ciemni moduły przetwarzania obrazu są zorganizowane w karty, które można przełączać w przód i w tył typowymi Ctrl+Tab i Ctrl+Shift+Tab. W obrębie karty poszczególne moduły można przeglądać (rozwijać i fokusować) w górę i w dół za pomocą Page Up/Down. Gdy moduł jest sfokusowany, przechodzenie przez jego wewnętrzne kontrolki można wykonać za pomocą Ctrl+Up/Down, co obsługuje karty, tak że gdy dotrzesz do ostatniej kontrolki widocznej karty i naciśniesz Ctrl+Down, następna karta zostanie automatycznie wyświetlona, a jej pierwsza kontrolka zostanie sfokusowana. Zarówno domowej roboty widżety Bauhaus, jak i natywne widżety Gtk obsługują natywne fokusowanie Gtk Up/Down (do poprzedniej/następnej kontrolki), ale działa to tylko wtedy, gdy jedna z kontrolek modułu jest sfokusowana i dla widocznych widżetów. Dlatego Ctrl+Up/Down zostało zaimplementowane dla lepszej niezawodności.
Wszystko to daje kontrolkom fokus, co oznacza, że pozwala im rejestrować dalsze naciśnięcia klawiszy. Sfokusowane kontrolki są wyświetlane pogrubioną czcionką w GUI. Sfokusowane moduły są również wyróżnione.
Interakcja ze sfokusowanymi kontrolkami
Podzielony paradygmat „fokusuj", a potem „wchodź w interakcję" (którego nie wymyśliłem…) jest bardzo potężny, ponieważ pozwala ograniczyć naciśnięcia klawiszy do właściwego kontekstu, co oznacza, że te same naciśnięcia klawiszy (zwłaszcza klawisze strzałek Up/Down/Right/Left) mogą być przypisane więcej niż raz w GUI i być obsługiwane różnie w zależności od tego, który kontekst ma fokus. Jest to bardziej elastyczne i w rzeczywistości prostsze7 niż darktable’owa obsesja podłączania wszystkiego do globalnych, absolutnych skrótów, które następnie kolidowałyby na często używanych klawiszach i prowadziły do konieczności dodawania coraz większej liczby modyfikatorów klawiszy jako obejście.
Jak dotąd nawigacja przez kontrolki tylko dawała im fokus. A co z faktyczną interakcją?
W widoku stołu podświetlanego, gdy siatka miniatur jest sfokusowana, nawigacja przez miniatury odbywa się typowymi klawiszami strzałek, Page Up/Down itd. (zobacz dokumentację po wszystkie szczegóły), a zaznaczenia obrazów można dokonywać na różne sposoby (wsadowo, seriami, pojedynczo) również z klawiatury.
W widoku ciemni zmianę wartości na suwakach i listach rozwijanych można wykonać za pomocą klawiszy strzałek (ewentualnie używając Shift dla dużego kroku lub Ctrl dla drobnego kroku), wywołanie próbnika kolorów (na suwakach, które go obsługują) odbywa się za pomocą Insert itd. (znowu, przeczytaj dokumentację po szczegóły).
Zatem, znowu, jak dotąd żadnego skrótu zdefiniowanego przez użytkownika, żadnej tajemniczej kombinacji klawiszy do zapamiętania, to głównie klawisze strzałek, a mimo to do wszystkiego można uzyskać dostęp.
Absolutne fokusowanie kontrolek
To wszystko wspaniałe, ale zostawia cię na swego rodzaju szlaku Ikei, gdy potrzebujesz uzyskać bezpośredni dostęp do jakiegoś obszaru aplikacji, ale musisz nawigować przez wszystkie sekcje od drzwi wejściowych.
Aby temu zaradzić, bardzo starą funkcją Darktable była karta „ulubione moduły", czyli specjalna karta, która duplikowała GUI najczęściej używanych modułów, na podstawie wyboru użytkownika. To w istocie rozwiązywanie nadmiaru kolejnym nadmiarem, a mimo to użytkownicy bardzo się do tego przywiązali. Choć jeśli skupimy się na celu, a nie na środku, wymaganiem jest szybki dostęp do dowolnych modułów, co jest całkowicie zrozumiałe.
Zostało to więc ponownie zaimplementowane jako sposób na zdefiniowanie absolutnego skrótu natychmiast fokusującego moduł przetwarzania obrazu lub którąkolwiek z jego wewnętrznych kontrolek. Sfokusowanie ukrytego modułu lub kontrolki automatycznie sprawi, że pojawi się on w GUI. Stamtąd dalsza interakcja odbywa się dokładnie jak wcześniej, za pomocą jednolitych kombinacji klawiszy. To znacznie zmniejsza liczbę skrótów do skonfigurowania, czyni całość bardziej ogólną, a okno ustawień skrótów znacznie prostszym.
Absolutne skróty mogą też celować we wpisy menu (czyli akcje globalne), w którym to przypadku będą przywoływane w menu, obok etykiety akcji, co znowu jest natywną funkcją Gtk pochodzącą z zerowym narzutem.
Zastępowanie kontrolerów MIDI
Jeśli odłożymy na bok cały szum wokół posiadania dedykowanych kontrolerów i poczucia bycia pilotem samolotu, jedyną rzeczą, którą kontrolery MIDI mają, a której klawiatura i mysz nigdy nie będą miały, jest zdolność do przypisania potencjometrów (obracanych pokręteł) bezpośrednio do suwaków GUI. Ale kosztem tego jest posiadanie dodatkowego urządzenia zajmującego miejsce (i kurz) na twoim biurku, nie wspominając o przyszłych śmieciach elektronicznych. Wszyscy fotografowie, których znam, którzy kupili MIDI lub Loupedecki, schowali je „tymczasowo", by odzyskać trochę miejsca na biurku… i nigdy nie wyciągnęli ich z powrotem z magazynu.
Kontrolki przetwarzania obrazu można podłączyć do skrótów jednoklawiszowych, ponieważ Ansel używa własnej nakładki skrótów na natywne funkcje akceleratorów Gtk. Zmodyfikowałem domowej roboty widżety Bauhaus tak, że po naciśnięciu jednego z powyższych absolutnych skrótów fokusujących i przytrzymaniu go, przewijanie kółkiem myszy zostanie bezpośrednio przypisane do widżetu, nawet jeśli mysz nie znajduje się nad właściwym suwakiem.
Zatem łącząc jednoliterowe skróty fokusujące kontrolkę z przewijaniem myszą (lub touchpadem), otrzymujesz całą wspaniałość obracanych pokręteł MIDI bez dodatkowego urządzenia, dodatkowej biblioteki do obsługi i cudów przeinżynierowanych warstw emulacji.
Ale wszystko to nadal dzieje się za pomocą jednego i jedynego absolutnego skrótu, więc nie musisz definiować i zapamiętywać kilku skrótów na kontrolkę, tylko po to, by zabrakło ci dostępnych kombinacji klawiszy.
Akcje bez skrótów, wyszukiwarka i wyzwalacze w stylu vimkeys
Moja obsługa skrótów to cienka nakładka na natywne API akceleratorów Gtk. Jako taka, akcja jest zdefiniowana przez ścieżkę tekstową, jak Ansel/Darkroom/Modules/Exposure/Black level, która jest unikalnym identyfikatorem, czytelnym zarówno dla komputera, jak i dla człowieka. GUI deklaruje funkcję przypisaną do każdej z tych ścieżek, zawierającą kod do uruchomienia w celu zastosowania odpowiedniej akcji. Następnie obsługa skrótów mapuje kombinację klawiszy na tę ścieżkę.
Zatem, ilekroć użytkownik naciśnie jakieś klawisze, obsługa skrótów sprawdza, czy mamy znaną ścieżkę dla tej kombinacji, a jeśli ją znajdzie, wywołuje przypisaną do niej funkcję. To odporny na błędy projekt, który nie wie nic o wnętrzu modułów Ansel, domowej roboty widżetów itd. Można go więc rozszerzyć na wiele części oprogramowania bez narzutu.
Ale jest on w rzeczywistości znacznie potężniejszy niż tylko to. Ponieważ wypisując wszystkie znane ścieżki, możemy następnie zwracać ścieżki pasujące do tekstowego zapytania wyszukiwania (szukając kontrolki, modułu lub wpisu globalnego menu po nazwie), czyli znaleźć wszystkie akcje z listy, ale możemy je też wtedy wywołać, mimo że nie są przypisane do żadnego skrótu.

Ponieważ moduły przetwarzania obrazu również można w ten sposób znaleźć i wyświetlić, zastępuje to również wyszukiwarkę modułów, odzyskując trochę pionowej przestrzeni dla długich modułów i ich opcji maskowania/mieszania (i usuwając około 200 linii kodu). Stamtąd rozszerzyłem ją na wszystkie przyborniki i uczyniłem globalną, co oznacza, że wyszukiwarka akcji działa we wszystkich widokach, ale wypisze tylko akcje istotne dla bieżącego widoku.
W ciemni obsługuje również wiele instancji modułów, pozwalając celować bezpośrednio w konkretną instancję (więcej na ten temat w dokumentacji).
Domyślnie globalne wyszukiwanie akcji jest przypisane do skrótu Ctrl+P i można uzyskać do niego dostęp z globalnego menu Pomoc lub za pomocą przycisku Szukaj akcji na środku paska nagłówka. To również poniekąd zastępuje vimkeys, które miały bardzo częściową obsługę akcji GUI (i wymagałyby całkowitego zduplikowania akceleratorów, by rozszerzyć je do użytecznego stanu), tak że zamiast wpisywać : a po nim polecenie, możesz nacisnąć Ctrl+P i albo wpisać ścieżkę akcji, albo rozpocząć zapytanie i wybrać z listy dopasowań (używając klawiszy strzałek, a następnie Enter).
Dopasowania są sortowane według malejącej trafności (od góry do dołu), a trafność jest obliczana na podstawie pozycji dopasowania. Założenie jest tu takie, że skoro ścieżki akcji są od lewej do prawej od ogólnych do szczegółowych (view/module/control), dopasowania tekstowe występujące na końcu ścieżki mają rzekomo pasować do kontrolek, a nie do modułów czy widoków, które uważamy za bardziej szczegółowe, a zatem bardziej trafne. Może to pozwolić uniknąć konieczności przewijania w dół obok całej zawartości modułów, która mogłaby pasować do zapytania tekstowego szukającego kontrolki.
Okno edycji skrótów
Ponieważ na kontrolkę przypada teraz tylko jeden skrót konfigurowalny przez użytkownika, GUI do wypisywania i edytowania skrótów to proste drzewo:

Wystarczy dwukrotnie kliknąć w kolumnie Klawisze, aby rozpocząć rejestrowanie nowej kombinacji klawiszy. Ponieważ jest to takie proste, to okno zastępuje zarazem ściągawkę. Skróty można wyszukiwać po nazwie akcji lub po używanych klawiszach, a wyszukiwanie klawiszy ma autouzupełnianie dla modyfikatorów klawiszy (szczegóły w dokumentacji). Wyskakujące okno skrótów można wyświetlić z globalnego menu Edycja → Skróty klawiszowe…
Dokumentacja wewnątrz programu
Rzecz w tym: utrzymywanie aktualnej dokumentacji domyślnych skrótów to udręka, bo jest zbyt drobiazgowe. To rodzaj dokumentu, który zdąży się zdezaktualizować, zanim skończysz go pisać. Skoro domyślne skróty i tak muszą być zaimplementowane w aplikacji, najlepszym miejscem na ich udokumentowanie jest właśnie ona sama, dzięki czemu aktualizacja odbywa się automatycznie.
Darktable miał 2 nadmiarowe interfejsy skrótów: jeden do konfigurowania skrótów, a drugi w rodzaju wyskakującej „ściągawki" (która przez długi czas była dostępna wyłącznie przez… skrót. Tyle w kwestii wykrywalności). Powodem było to, że wyskakujące okno ustawień było zbyt zagracone, by służyć za jakąkolwiek szybką ściągę. Później skróty dodano do dymków niektórych elementów sterujących… dymków pojawiających się tylko przy najechaniu na te elementy myszą. Jak bezsensowne jest to, że powinieneś używać myszy, aby odkrywać, jak używać klawiatury, przypadek po przypadku?
Ansel ma skróty (kombinacje klawiszy) zapisane w wyskakującym oknie ustawień, a także przywoływane w globalnym wyszukiwaniu akcji. Ale te skróty nie ograniczają się do tych konfigurowalnych przez użytkownika — rozszerzyłem obsługę skrótów o „skróty wirtualne", czyli skróty w zasadzie niepowiązane z żadną akcją, ale zadeklarowane tak samo jak reszta i pojawiające się wśród reszty jako „zablokowane" skróty.

Skróty opisane jako kontekstowa interakcja przy fokusie dokumentują ogólne akcje kierowane na element sterujący z fokusem, niezależnie od tego, czy element uzyskał fokus w sposób względny, czy bezwzględny.
Szczegóły implementacji
Kod źródłowy całego systemu obsługi skrótów, wraz z częściami GUI (globalne wyszukiwanie akcji i wyskakujące okno edycji skrótów), wykorzystuje 1144 wiersze kodu, z czego połowa to GUI, przy złożoności cyklomatycznej wynoszącej 216 . To jedna piąta objętości kodu przy jednej szóstej złożoności (w porównaniu z Darktable 5.0), mimo że zapewnia dodatkowe funkcje (wyszukiwanie klawiszy z autouzupełnianiem, globalne wyszukiwanie, jawne wskazywanie instancji modułów itd.). Zrezygnowano z obsługi MIDI, bo — szczerze mówiąc — nie widzę, jaki problem ona rozwiązuje, którego nie rozwiązuje już obecny, prostszy projekt.
Znalezienie akcji przypisanej do naciśnięcia klawisza zajmuje około kilkunastu nanosekund, podczas gdy Wielki Turducken MIDI zajmował od 10 do 50 milisekund przy każdym naciśnięciu.8
Graf zależności tej funkcji można zobaczyć w dokumentacji dla programistów; jest on znacznie czystszy niż poprzednia miska spaghetti. Reszta kodu GUI Ansela współpracuje z obsługą skrótów, deklarując nowe ścieżki akceleratorów, rejestrując przypisane do nich funkcje zwrotne, a być może i domyślne skróty — wszystko to za pomocą jednej metody z API. Obsługa skrótów jest nieświadoma wnętrzności Ansela i na nie odporna; w szczególności nie wie nic o modułach ani o domowej roboty widżetach Bauhaus, więc projekt jest całkowicie samowystarczalny. Preferencje są przechowywane osobno dla każdego języka w ~/.config/ansel/keyboardrc-LANG, przy użyciu natywnej mapy akceleratorów Gtk . API jest w pełni udokumentowane w dokumentacji dla programistów Ansela na potrzeby przyszłego utrzymania i rozszerzania, więc nie będzie potrzebna żadna inżynieria wsteczna.


Tak właśnie pracuję, bo nie programuję dla zabawy. Programowanie nie sprawia mi żadnej frajdy. Rozwiązuję problemy, starając się nie tworzyć nowych.
Podsumowanie
To sztandarowy przykład wszystkiego, co poszło źle w Darktable pod względem bezlitosnego przeinżynierowania, oraz tego, jak należało to naprawić. Zaproponowane tu rozwiązanie jest lepsze, ponieważ:
- po całym GUI można nawigować z klawiatury bez konieczności zapamiętywania choćby jednego skrótu,
- elementy sterujące, moduły i inne akcje mają tylko jeden bezpośredni, bezwzględny skrót konfigurowalny przez użytkownika, który bezpośrednio wyzwala akcję lub — jeśli taki istnieje — ustawia fokus na widżecie sterującym, co sprawia, że GUI ustawień jest znacznie mniej przytłaczające, i eliminuje potrzebę dodatkowej wyskakującej ściągawki,
- akcje można globalnie wyszukiwać i wyzwalać, niezależnie od tego, czy są powiązane z kombinacją klawiszy,
- mieszane interakcje typu klawisz+przewijanie można wyzwalać bez dodatkowych kosztów, emulując obrotowe pokrętła i suwaki MIDI bez potrzeby dodatkowego sprzętu,
- kod jest obiektywnie 5 do 6 razy prostszy (w zależności od tego, którą metrykę weźmiesz pod uwagę),
- całość jest w pełni udokumentowana i obficie skomentowana w kodzie,
- każdy przyszły bezmózgi idiota potrafiący czytać w C będzie w stanie utrzymać tę rzecz, która i tak nie powinna wymagać wiele utrzymania, bo nie robi nic sprytnego i żyje poza rdzeniem oprogramowania.
Translated from English by : Claude. In case of conflict, inconsistency or error, the English version shall prevail.
A turducken is a chicken stuffing a duck stuffing a turkey. That’s a decadent amount of meat that will likely go to waste, unless you have 20 persons to feed. Anyway, it will take forever to cook, and the turkey will likely be dry by the time the chicken is well done. ↩︎
Developers call that “whack-a-mole bug fixing” . ↩︎
Although the stress and anxiety inflicted upon workers by ever-changing software stacks is largely underrated, since innovation is deemed to increase productivity by definition, regardless of user feedback. ↩︎
STEM: Science Technology Engineering Mathematics ↩︎
I don’t see why the capitalistic mindset is ok when it comes to getting excited about new products, but gets boring when it reaches return on investment and hidden/sunk costs… ↩︎
I’m not talking here about the Darktable way of “fixing bugs” that consists into rushing on the visible manifestation of the bug, and adding a fourth level of nested
ifto take care of the pathological corner case. That’s working around the cause of the bug by creating more technical debt, not actually fixing the root cause of the bug. And since that root cause will generally stem many visible manifestations, patching all the manifestations is actually more complicated on the long run, and leads to brittle code. ↩︎Flexibility is usually the opposite of simplicity, so you have to enjoy when you can win on both fronts. ↩︎
Remember that the shortcut handler has to listen to all keystrokes before deciding if it’s supposed to do something with them or discard them, so this part of the software runs all the time for all users, whether or not they actually use shortcuts. ↩︎