Po co tworzyć biblioteki wewnętrzne dla aplikacji wewnętrznych?


10

Mam problem ze zrozumieniem, dlaczego powinieneś tworzyć biblioteki wewnętrzne, które będą używane wyłącznie do tworzenia aplikacji wewnętrznych. Doceniam to, że jeśli chcę korzystać z oprogramowania napisanego przez osobę spoza organizacji, może on wysłać mi swoje pliki nagłówkowe oraz pliki .a lub .so i mogę po prostu połączyć je z moim projektem (zakładając, że są one skompilowane w tym samym środowisku) .

Ale dlaczego należy opracować bibliotekę wewnętrzną, aby była połączona z aplikacją wewnętrzną, gdy mam dostęp do plików nagłówka i plików implementacyjnych i mogę po prostu dołączyć je do mojego drzewa źródłowego i skompilować je wszystkie razem?

Innymi słowy: jeśli jakiś kod źródłowy zostanie napisany, jak zdecydować, czy należy go skompilować do biblioteki binarnej i połączyć z aplikacją, czy po prostu włączyć do plików źródłowych projektu i regularnie kompilować?

Kiedy mówię „dołącz” pliki do każdego projektu, nie mam na myśli kopiowania i wklejania każdego pliku do drzewa źródłowego aktualnie opracowywanego projektu. Mam na myśli opracowanie jakiegoś katalogu / biblioteki (oddzielnej dla każdego projektu) zawierającego wspólny kod źródłowy, który można włączyć do plików projektu w zwykły sposób, tj. #Include.

ps Mówię tutaj o rozwoju c / c ++ dla wielu aplikacji komputerowych.


Odpowiedzi:


25

Istnieje wiele powodów, aby tworzyć biblioteki i biblioteki współdzielone (w plikach .dll lub .so) nawet do użytku wewnętrznego:

  1. Ponowne użycie w różnych projektach jest znacznie czystsze
  2. Rozdzielenie odpowiedzialności - część kodu może być bardziej odpowiednia dla różnych programistów lub zespołów
  3. Możesz skorzystać z ulepszeń bibliotek, które wprowadzają inne zespoły, bez konieczności lokalizowania określonego kodu
  4. Szybsze czasy kompilacji, jeśli biblioteka jest stabilna, nie wymaga ponownego budowania.
  5. Miejsce na dysku - możesz mieć tylko bibliotekę i nagłówki w projekcie
  6. Jeśli korzystasz z bibliotek współdzielonych, możesz zaoszczędzić pamięć, ładując tylko jedną kopię do pamięci RAM, nawet jeśli korzysta z niej kilka programów
  7. Na ogół kończy się lepsza dokumentacja i testowanie bibliotek
  8. Czystszy projekt i kod - myślenie o tworzeniu struktur w bibliotekach powinno skutkować pokrewnymi grupami funkcji w każdej bibliotece, a ty zazwyczaj dzielisz kod ogólny na biblioteki od specyfiki aplikacji w aplikacji .
  9. Jeśli masz zastrzeżone algorytmy w bibliotekach, możesz ograniczyć dostęp do źródła, np. Nie zezwalając wykonawcom lub zewnętrznym zespołom na dostęp do źródła.
  10. Kod biblioteki może być objęty inną licencją niż Aplikacja, w której pierwotnie został napisany, niektóre firmy są nawet znane bibliotekom Open Source, z których są dumne - zdobywając duże uznanie w społeczności Open Source, a czasem przyczyniły się do znacznych ulepszeń plecy.

Niektóre firmy mają nawet praktykę księgową, w ramach której projekty tworzące biblioteki otrzymują zwrot kosztów za każde ponowne użycie.


1
Lub w odmianie punktu 9 możesz zwolnić bibliotekę na innej licencji niż główny kod aplikacji.
Michael Borgwardt,

@MichaelBorgwardt - Dobry punkt podpowiadający punkt 10 powyżej.
Steve Barnes

Ponadto posiadanie pewnego kodu jako oddzielnej biblioteki pomaga uniknąć skrótów podczas programowania, takich jak „Dodam tutaj ten dodatkowy parametr ..” i pomaga znaleźć lepsze sposoby implementacji wymaganych funkcji.
Valdas,

11

Niektóre inne możliwe przyczyny, które mogą mieć zastosowanie do większych, nietrywialnych projektów:

  • Czasy kompilacji: Ogromne monolityczne projekty C ++ z tysiącami plików, tysiącami klas, funkcji itp. Mogą zająć bardzo dużo czasu (co obniża wydajność, jeśli chcesz rekompilować za każdym razem, gdy zmieniasz kilka wierszy kodu). Biblioteki połączone statycznie i dynamicznie są kompilowane niezależnie i nie trzeba ich ponownie kompilować, jeśli ich źródło się nie zmieniło.

  • Logiczne rozdzielenie odrębnych modułów lub podsystemów : Dużymi systemami zazwyczaj łatwiej zarządzać, jeśli oddzielne obszary funkcjonalności są umieszczone w osobnych modułach, a programiści nie muszą przeszukiwać ogromnych folderów / projektów zawierających tysiące plików / klas.

  • Granice między programistami / zespołami : programiści budujący osobne nowe funkcje w tym samym czasie mogą zmniejszyć ryzyko konfliktów scalania, jeśli każdy programista może pracować w różnych modułach.

  • Kod, którego nie wolno wypuszczać do środowiska na żywo : Na przykład biblioteki testów jednostkowych lub biblioteki „pozorne”, które są używane do testowania programistów w celu zastąpienia składnika systemu na żywo (sprzęt, interfejsy API, systemy zdalne, bazy danych itp.)

  • Flagi kompilatora : Jeśli znajdziesz się w bardzo niefortunnej sytuacji integracji z interfejsem API innej firmy, który spodziewa się dziwnej flagi kompilatora, biblioteka może być „warstwą odkażającą” znajdującą się między interfejsem API innej firmy a resztą aplikacji.

  • Funkcje opcjonalne / Optymalizacja : W dużych systemach aplikacja może czekać przed załadowaniem niektórych dynamicznie połączonych modułów do pamięci w czasie wykonywania, jeśli nie mają one decydującego znaczenia dla podstawowej funkcjonalności aplikacji.


Zasadniczo wiele wewnętrznych projektów to często małe mikro-aplikacje, które nie korzystają z podziału na osobne biblioteki. Jeśli pracujesz nad małym projektem jako samotny programista, „nie musisz” martwić się o podział kodu na biblioteki (jeszcze ...). Nie zapomnij o zasadzie YAGNI .


3
@ downvoter - czy możesz wyjaśnić powód głosowania? Informacje zwrotne na temat odpowiedzi są przydatne dla poprawy jakości tej witryny dla wszystkich.
Ben Cottrell,

4

Twoje pierwotne pytanie mogło spowodować nieporozumienie w przypadku większości innych odpowiedzi. Ponieważ nie zamierzasz kopiować istniejącego kodu między projektami, ale dołączyć te same pliki źródłowe z różnych projektów jako odniesienia , każdy argument „duplikatu kodu” staje się bezcelowy, podobnie jak wiele innych przedstawionych argumentów.

Zauważ, że jest to czasem (- nie zawsze -) rozsądna technika . W rzeczywistości, gdy umieścisz wszystkie pliki źródłowe, które chcesz ponownie wykorzystać w różnych projektach, w jednym osobnym folderze dołączania, już zbudowałeś bibliotekę - bibliotekę kodów źródłowych, a nie bibliotekę binarną. Zwłaszcza w C ++, podczas tworzenia ogólnych bibliotek z szablonami, nie jest niczym niezwykłym posiadanie bibliotek tylko z nagłówkami, które wymagają jedynie prostego dołączenia i żadnych oddzielnych przygotowań do łączenia.

Sądzę więc, że Twoim prawdziwym pytaniem jest - kiedy budować biblioteki kodu źródłowego, a kiedy preferować binarne biblioteki prekompilowane? W tej starszej odpowiedzi na tej stronie omówiłem zalety i wady bibliotek tylko nagłówkowych, być może to ci pomoże. Główną zaletą bibliotek kodu źródłowego jest to, że nie wymagają one kompilacji z tymi samymi flagami wykonawczymi i / lub kompatybilnymi kompilatorem / linkerem jak aplikacja, która ich używa. Wadami są dodatkowe czasy kompilacji i wymóg zapewnienia dostępu do kodu źródłowego (co oczywiście nie stanowi problemu dla tego rodzaju „wewnętrznych” projektów, o których myślisz).


To prawda, że ​​miałem na myśli bibliotekę kodów źródłowych, która jest wspólna dla wielu projektów, w których po prostu odwołujesz się do plików, których potrzebujesz, za pomocą typowej dyrektywy #include - nie znałem tego terminu, dopóki go nie wypowiesz, a ja zmodyfikuję pytanie teraz. Twoja linkowana odpowiedź jest również bardzo pomocna.
Andrew Murtagh,

@AndrewMurtagh: fakt, że tak szybko akceptujesz odpowiedź Michaela Borgwardta, zaskoczył mnie, ponieważ to, co napisał, wydaje się być albo jego nieporozumieniem, albo moim.
Doc Brown

cóż, wyjaśnił mi początkowe zamieszanie, kiedy miałem pogrupować kod, który byłby wspólny dla wielu projektów w jednym pakiecie (czy to w bibliotekach binarnych czy bibliotekach kodu źródłowego), ale przyznając, mówiłem o posiadaniu jednego katalogu źródeł kod, który może być współdzielony między projektami, a nie kopiowanie i wklejanie każdego pliku do każdego projektu, ponieważ może ich potrzebować.
Andrew Murtagh,

2

Zgadzam się z innymi komentatorami, którzy piszą, że nie powinieneś powielać kodu. W twoim przypadku wydaje się jednak, że ty (lub osoby, z którymi pracujesz) tworzysz biblioteki dla kodu, który nie jest duplikowany w innym miejscu.

W tym przypadku przestrzegam przed przedwczesnym uogólnieniem . Często zdarza się, że wydaje się, że fragment kodu będzie można ponownie wykorzystać. Jednak bez znajomości szczegółowych informacji na temat tego, jak drugi przypadek użycia będzie wykorzystywał taki kod, bardzo łatwo jest poświęcić dodatkowy czas na funkcje „wielokrotnego użytku”, które w rzeczywistości nie będą przydatne w dodatkowych przypadkach, lub poczynić założenia, które okażą się błędne w druga sprawa.

Pisanie „biblioteki” dla jednego przypadku użycia może stać się bardzo kosztownym ćwiczeniem bez żadnej wypłaty - ugryzło mnie to kilka razy.

Przykładowe koszty:

  1. Czas / energia poświęcona na rozważenie „ogólnych” przypadków użycia
  2. Czas poświęcony na rozpowszechnianie „biblioteki” wśród „klientów” (własnego kodu)
  3. Przyszła presja, aby skorzystać z „biblioteki”, nawet jeśli nie w pełni pasuje ona do następnego przypadku użycia

Moja ogólna zasada brzmi: nie przekształcaj kodu w bibliotekę, chyba że mam co najmniej 2 oddzielne miejsca, w których kod jest potrzebny.


2
Widziałem prawie dokładnie te same powody, z których korzystali niektórzy programiści, jak to, dlaczego ich kod znajduje się w jednym pliku źródłowym o wielkości> 20 KB. W połączeniu z dziwacznymi nazwami i złymi komentarzami wkrótce otrzymasz kod, który szybciej przepisać niż zachować.
Steve Barnes

Świetna uwaga: z pewnością nie sprzeciwiam się pisaniu łatwego do utrzymania, czytelnego kodu. Oddzielne pliki, dobrze nazwane metody / klasy oraz struktura pakietów są ważnymi składnikami utrzymania. Chodzi mi o to, że koszty pisania i dystrybucji biblioteki są wysokie, ponieważ ponoszą tylko jeden przypadek użycia „biblioteki”.
Sam

1
I odwrotnie, nie twierdzę, że musisz koniecznie spakować i dystrybuować bibliotekę w każdym przypadku, tylko to, że pisanie i tworzenie struktury tak, jakby Twój kod mógł kiedyś stać się biblioteką, jest zwykle warte trochę wysiłku i często przynosi dywidendy, nawet jeśli kod nigdy nie staje się dystrybuowane jako biblioteka.
Steve Barnes,

1

dlaczego należy opracować bibliotekę wewnętrzną, aby była połączona z aplikacją wewnętrzną, gdy mam dostęp do plików nagłówka i plików implementacyjnych i mogę po prostu włączyć je do mojego drzewa źródłowego i skompilować je wszystkie razem?

Ponieważ jeśli „po prostu umieścisz je w moim drzewie źródłowym”, skopiujesz kod .

Problem polega na tym, że nie skorzystasz z żadnych ulepszeń (w tym krytycznych poprawek) wprowadzonych przez projekt, z którego skopiowałeś kod, ani nie skorzystasz z żadnych ulepszeń, które wprowadzisz.

Możesz pomyśleć, że możesz rozwiązać ten problem, po prostu regularnie kopiując najnowszą wersję kodu do drzewa źródłowego, a może nawet zautomatyzowany za pomocą submodułu w git lub czegoś podobnego. Ale wtedy ciągle będziesz mieć przerwę kompilacji z powodu niezgodnych zmian API. Z drugiej strony biblioteka ma „oficjalny” publiczny interfejs API, o którym programiści wiedzą, że nie można go zmienić bez uzgadniania z klientami.

Wreszcie mogą istnieć powody techniczne - czy utrzymanie części kodu jako biblioteki może być konieczne, aby można go było opcjonalnie załadować, a nawet załadować i rozładować na żądanie, a tym samym zmniejszyć zużycie pamięci, gdy funkcjonalność nie jest potrzebna?


1
Tak więc, jak rozumiem, głównym powodem przekształcenia fragmentu kodu w bibliotekę jest to, że będzie on używany w różnych projektach (nawet jeśli wszystkie są wewnętrznie opracowywane), aby nie można było powielać, aktualizować ani utrzymywać tego kodu osobno? A jeśli zamierzasz opracowywać tylko jeden projekt, nie ma potrzeby przekształcania czegoś w bibliotekę (chyba że zamierzasz użyć go w kolejnych projektach w późniejszym terminie).
Andrew Murtagh,

@AndrewMurtagh: Tak, tak to ująłbym. Chociaż mogą istnieć również powody techniczne; Nie znam się zbytnio na programowaniu w C / C ++ - może utrzymanie części kodu jako biblioteki jest konieczne, aby można ją było opcjonalnie załadować lub nawet załadować i wyładować na żądanie, a tym samym zmniejszyć zużycie pamięci, gdy funkcjonalność nie jest potrzebna?
Michael Borgwardt,

Wierzę, że może to być możliwe za pośrednictwem bibliotek wspólnych. Dzięki za wyjaśnienie, oznaczę twoją odpowiedź jako przyjętą.
Andrew Murtagh,

Prawie każdy VCS w ostatniej dekadzie obsługuje odniesienia zewnętrzne lub submoduły. To usunęło problem ze zduplikowanym kodem i błędem. Może zawierać więcej informacji o tym, dlaczego nie są one realnym rozwiązaniem, jeśli nadal uważasz, że są to ważne problemy.
Sirisian

Pomyśl także o konserwacji. 1) Lib może być utrzymywany niezależnie i równolegle. 2) Czy kod można łatwo wymienić? 3) Mała baza kodu jest łatwiejsza do zarządzania dla małych zespołów i łatwiejsza do zrozumienia dla wszystkich. 4) jeśli czas wprowadzenia produktu na rynek ma krytyczne znaczenie, wolisz mieć szybsze kompilacje. Kod w libs to kod, którego nie kompilujesz w kółko (IMO). 5) To niezawodny kod wielokrotnego użytku ... Udało ci się ;-)
Laiv

1

Chciałbym rozwinąć koszty, jakie Twoje rozwiązanie ma w dłuższej perspektywie.

Oczywiste jest, że dodanie biblioteki do projektu wiąże się z pewnym obciążeniem, a wszystko powyżej, jeśli jest to pierwsze: przepływy pracy muszą zostać zmienione, czasem nawet infrastruktura, a niektórym członkom zespołu może się to nie podobać (na początku). Więc zalety rozwiązania są oczywiste, jako że nakłada pomniejszonej o koszty teraz .

Jednak wraz ze wzrostem projektu wzrosną koszty „pseudo-biblioteki”. Załóżmy, że masz „pseudo-bibliotekę”, z Aktórej korzysta aplikacja i tester jednostek. Za każdym razem, gdy dodajesz cpp A, musisz dodać go do obu projektów, w przeciwnym razie nie zostaną połączone.

Co jeśli Twoja „pseudo-biblioteka” jest używana przez inną „pseudo-bibliotekę” B? Musisz dodać nowy procesor do wielu projektów. A jeśli Bprzełączysz się na inną bibliotekę? Będziesz musiał usunąć cpps ze Awszystkich projektów, w zależności tylko od B.

To wszystko byłoby za darmo, gdyby wykorzystano prawdziwą bibliotekę. Pytanie brzmi: ile procesorów jest potrzebnych do uzasadnienia przejścia do prawdziwej biblioteki?

Ale poczekaj, jest jeszcze więcej zabezpieczeń: Deweloperowi nie podoba się ta głupia praca polegająca na polowaniu na wszystkie projekty wymagające nowego CPP i doda gdzieś swój kod / klasy do już istniejących plików, co nie jest dobre w długi bieg.

Zatem użycie „pseudo-biblioteki” może być pierwszym krokiem do rozbicia monolitycznego projektu, ale nie powinieneś zbyt długo czekać, aby stała się prawdziwą biblioteką, aby móc korzystać z jej zalet.


0

Ale dlaczego należy opracować bibliotekę wewnętrzną, aby była połączona z aplikacją wewnętrzną, gdy mam dostęp do plików nagłówka i plików implementacyjnych i mogę po prostu dołączyć je do mojego drzewa źródłowego i skompilować je wszystkie razem?

Jeśli biblioteka jest używana tylko przez jedną aplikację, prawdopodobnie nie potrzebujesz jej jako oddzielnej biblioteki.

Jeśli biblioteka jest używana przez 3500 aplikacjach wtedy absolutnie zrobić trzeba go jako oddzielnej bibliotece.

Co jeśli w bibliotece jest błąd i trzeba go naprawić? Czy może nastąpią jakieś zmiany ustawowe lub wykonawcze, co oznacza, że musisz zmienić sposób działania biblioteki?

Jeśli jest w osobnej bibliotece, możesz (potencjalnie) naprawić bibliotekę, ponownie ją przetestować i wdrożyć, a każda aplikacja korzysta z tej poprawki.

Jeśli jest tylko w kodzie źródłowym, który jest „lokalny” dla każdej aplikacji, musisz zmienić, przebudować, ponownie przetestować i wdrożyć każdą aplikację osobno . To znacznie większe (tj. Droższe) ćwiczenie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.