Zawstydzająco wprowadziłem „wspólną” bibliotekę, nazwaną jako taką, w środowisku zespołowym kilka dekad temu. Nie bardzo wtedy rozumiałem dynamikę tego, co mogło się zdarzyć w luźno koordynowanym otoczeniu zespołu w ciągu zaledwie kilku miesięcy.
Kiedy go przedstawiłem, pomyślałem, że to jasno wyjaśniłem, a także udokumentowałem, że dla celów, które wszyscy zgodzilibyśmy się, że są przydatne na co dzień, że ma to być biblioteka minimalistyczna i że biblioteka nie powinna zależeć od niczego poza standardowa biblioteka, aby jak najłatwiej wdrożyć ją w nowych projektach. Myślałem wtedy, że było to nasze własne małe rozszerzenie standardowej biblioteki dla rzeczy, które w naszej konkretnej dziedzinie były przydatne na co dzień.
I zaczęło się dość dobrze. Zaczęliśmy od biblioteki matematycznej ( common/math*
) procedur, z których wszyscy korzystaliśmy na co dzień, ponieważ pracowaliśmy nad grafiką komputerową, która często była ciężka dla algebry liniowej. A ponieważ często współpracowaliśmy z kodem C, uzgodniliśmy kilka przydatnych funkcji narzędziowych, takich jak find_index
które, w przeciwieństwie dostd::find
w C ++ zwróciłby indeks do elementu znajdującego się w sekwencji zamiast iteratora, który naśladowałby działanie naszych funkcji C - tego rodzaju - trochę eklektyczny, ale minimalistyczny i wystarczająco szeroko stosowany, aby pozostać znajomym i praktycznym dla wszystkich , a natychmiastowa znajomość jest niezwykle ważnym kryterium, ponieważ widzę to w próbach stworzenia czegoś, co jest „powszechne” lub „standardowe”, ponieważ jeśli naprawdę jest „powszechne”, powinno mieć tę znajomą jakość dzięki swojej szerokiej adopcja i codzienne użytkowanie.
Ale z czasem intencje projektowe biblioteki wymknęły się z moich palców, gdy ludzie zaczęli dodawać rzeczy, których używali osobiście, o których po prostu myśleli, że mogą być przydatne dla kogoś innego, tylko po to, aby nikt inny ich nie używał. Później ktoś zaczął dodawać funkcje zależne od OpenGL do popularnych procedur związanych z GL. Następnie przyjęliśmy Qt i ludzie zaczęli dodawać kod zależny od Qt, więc już teraz wspólna biblioteka była zależna od dwóch bibliotek zewnętrznych. W pewnym momencie ktoś dodał wspólne procedury cieniowania, które były zależne od naszej biblioteki modułów cieniujących specyficznych dla aplikacji, i w tym momencie nie można było nawet wdrożyć go w nowym projekcie bez wprowadzenia Qt, OGL oraz naszej biblioteki modułów cieniujących i aplikacji nietrywialny skrypt kompilacji dla twojego projektu. Więc zamieniło się w ten eklektyczny, współzależny bałagan.
Ale odkryłem również, debatując, co powinno, a czego nie powinno wchodzić do tej biblioteki, że to, co jest uważane za „powszechne”, może łatwo przekształcić się w bardzo subiektywny pomysł, jeśli nie ustawisz bardzo twardej zasady, że to, co „wspólne”, jest co każdy uważa za przydatne na co dzień. Każde poluzowanie standardów i szybko degraduje się od rzeczy, które każdy uważa za przydatne na co dzień, do czegoś, co pojedynczy programista uważa za przydatne, które może być korzystne dla kogoś innego, i w tym momencie biblioteka bardzo szybko staje się eklektycznym bałaganem .
Co więcej, po osiągnięciu tego punktu niektórzy programiści mogą zacząć dodawać rzeczy z tego prostego powodu, że nie podoba im się język programowania. Mogą nie lubić składni pętli for lub wywołania funkcji, w którym to momencie biblioteka zaczyna się zapełniać rzeczami, które po prostu walczą z podstawową składnią języka, zastępując kilka linii prostego kodu, co tak naprawdę nie jest powielanie jakiejkolwiek logiki do pojedynczego zwięzłego wiersza egzotycznego kodu znanego tylko programistom, którzy wprowadzili takie skróty. Wtedy taki programista może zacząć dodawać więcej funkcji do wspólnej biblioteki zaimplementowanej przy użyciu takich skrótów, w tym momencie znaczące fragmenty wspólnej biblioteki przeplatają się z tymi egzotycznymi skrótami, które mogą wydawać się piękne i intuicyjne dla programisty, który je wprowadził, ale są brzydkie, obce i trudne do zrozumienia dla wszystkich innych. I w tym momencie myślę, że wiesz, że wszelka nadzieja na uczynienie czegoś prawdziwie „wspólnym” jest tracona, ponieważ „wspólne” i „nieznane” są biegunowo przeciwnymi ideami.
Są tam więc wszelkiego rodzaju puszki robaków, przynajmniej w luźno skoordynowanym środowisku zespołowym, z biblioteką o ambicjach tak szerokich i tak ogólnych, jak tylko „powszechnie używane rzeczy”. I choć podstawowym problemem mogła być przede wszystkim luźna koordynacja, przynajmniej wiele bibliotek miało służyć bardziej szczególnemu celowi, jak biblioteka przeznaczona do rutynowych zadań matematycznych i nic więcej, prawdopodobnie nie pogorszyłaby się tak znacząco pod względem projektuj czystość i zależności jako „wspólną” bibliotekę. Z perspektywy czasu myślę, że o wiele lepiej byłoby pomylić się po stronie bibliotek, które mają znacznie bardziej wyraźne intencje projektowe. Przez lata odkryłem również, że wąskie cele i wąskie zastosowania to radykalnie różne pomysły.
Poza tym jestem co najmniej trochę niepraktyczny i może trochę zbytnio dbam o estetykę, ale sposób, w jaki postrzegam mój pomysł na jakość biblioteki (a może nawet „piękno”) jest oceniany bardziej na podstawie jej najsłabszego ogniwa niż jego najsilniejszy, w podobny sposób, że jeśli podałeś mi najbardziej apetyczne jedzenie na świecie, ale na tym samym talerzu umieściłeś tam coś gnijącego, co naprawdę brzydko pachnie, zwykle chcę odrzucić cały talerz. A jeśli pod tym względem jesteś podobny do mnie i robisz coś, co zachęca do wszelkiego rodzaju dodatków jako coś, co nazywa się „wspólnym”, możesz spojrzeć na analogiczną płytkę z czymś gnijącym na boku. Podobnie myślę, że dobrze jest, jeśli biblioteka jest zorganizowana, nazwana i udokumentowana w taki sposób, że z czasem zapraszać coraz więcej dodatków. I może to nawet dotyczyć twoich osobistych tworów, ponieważ z pewnością stworzyłem jakieś zgniłe rzeczy tu i tam, i „skażają” o wiele mniej, jeśli nie zostaną dodane do największej płyty. Rozdzielanie rzeczy na małe, bardzo osobliwe biblioteki ma również tendencję do lepszego oddzielania kodu, choćby tylko z tego powodu, że łączenie wszystkiego staje się znacznie mniej wygodne.
Deduplikacja kodu została wbita we mnie przez lata, ale czuję, że powinienem spróbować tym razem.
To, co mogę zasugerować w twoim przypadku, to ułatwić sobie deduplikację kodu. Nie mówię, aby kopiować i wklejać duże fragmenty źle przetestowanego, podatnego na błędy kodu lub coś w tym rodzaju, ani nie powielać ogromnych ilości nietrywialnego kodu, który z dużym prawdopodobieństwem wymaga zmian w przyszłości.
Ale szczególnie, jeśli jesteś nastawiony na stworzenie „wspólnej” biblioteki, dla której zakładam, że twoim pragnieniem jest stworzenie czegoś szeroko stosowalnego, wysoce nadającego się do wielokrotnego użytku, a być może idealnie, co uznasz za równie użyteczne dzisiaj, jak za dziesięć lat. , to czasem może być potrzebne lub potrzebne powielanie, aby osiągnąć tę nieuchwytną jakość. Ponieważ duplikacja może faktycznie służyć jako mechanizm odsprzęgający. To tak, jakbyś chciał oddzielić odtwarzacz wideo od odtwarzacza MP3, musisz przynajmniej powielić niektóre rzeczy, takie jak baterie i dyski twarde. Nie mogą dzielić się tymi rzeczami lub są ze sobą nierozerwalnie połączone i nie można ich używać niezależnie od siebie, a w tym momencie ludzie mogą już nie być zainteresowani urządzeniem, jeśli wszystko, co chcą, to odtwarzać pliki MP3. Ale jakiś czas po rozdzieleniu tych dwóch urządzeń może się okazać, że odtwarzacz MP3 może korzystać z innej konstrukcji baterii lub mniejszego dysku twardego niż odtwarzacz wideo, w którym to momencie nie można już niczego kopiować; co początkowo zaczęło się od powielania, aby umożliwić temu współzależnemu urządzeniu podział na dwa oddzielne, niezależne urządzenia, może później okazać się, że przyniosą projekty i implementacje, które nie są już w ogóle zbędne.
Warto zastanowić się nad tym z perspektywy tej korzystającej z biblioteki. Czy naprawdę chcesz użyćbiblioteka, która minimalizuje duplikację kodu? Są szanse, że nie, bo taki, który będzie naturalnie zależał od innych bibliotek. Te inne biblioteki mogą zależeć od innych bibliotek, aby uniknąć powielania ich kodu, i tak dalej, dopóki nie będzie konieczne zaimportowanie / połączenie 50 różnych bibliotek, aby uzyskać tylko podstawowe funkcje, takie jak ładowanie i odtwarzanie pliku audio, i staje się to bardzo niewygodne . Tymczasem, jeśli taka biblioteka audio świadomie zdecyduje się powielić niektóre rzeczy tu i tam, aby osiągnąć swoją niezależność, staje się o wiele łatwiejsza w użyciu w nowych projektach, a są szanse, że nie będzie musiała być aktualizowana tak często, ponieważ wygrała ” Trzeba zmienić w wyniku zmiany jednej zależnej biblioteki zewnętrznej, która może próbować spełnić znacznie bardziej ogólny cel niż to, czego potrzebuje biblioteka audio.
Czasami więc warto celowo zdecydować się na powielenie trochę (świadomie, nigdy z lenistwa - właściwie z pracowitości) w celu oddzielenia biblioteki i uniezależnienia jej, ponieważ dzięki tej niezależności osiąga szerszy zakres praktycznego zastosowania i równomierna stabilność (koniec sprzężeń aferentnych). Jeśli chcesz zaprojektować biblioteki wielokrotnego użytku, które będą trwać od jednego projektu do następnego i na przestrzeni lat, to oprócz zawężenia jego zakresu do minimum, proponuję rozważenie powielenia tutaj. I oczywiście napisz testy jednostkowe i upewnij się, że są naprawdę dokładnie przetestowane i niezawodne w tym, co robi. Dotyczy to tylko bibliotek, które naprawdę chcesz poświęcić czas na uogólnienie do punktu, który wykracza daleko poza pojedynczy projekt.