Najlepsze praktyki udostępniania małych fragmentów kodu między projektami

102

Zawsze staram się śledzić DRY zasadę ściśle w pracy; za każdym razem, gdy powtarzam kod z lenistwa, gryzie go później, kiedy muszę go utrzymywać w dwóch miejscach.

Ale często piszę małe metody (może 10-15 linii kodu), które trzeba ponownie wykorzystać w dwóch projektach, które nie mogą się nawzajem odnosić. Metoda może mieć coś wspólnego z siecią / łańcuchami / MVVM itp. I jest ogólnie użyteczną metodą, która nie jest specyficzna dla projektu, w którym pierwotnie się znajduje.

Standardowym sposobem ponownego wykorzystania tego kodu byłoby utworzenie niezależnego projektu dla kodu wielokrotnego użytku i odwołanie się do tego projektu, gdy będzie to potrzebne. Problem polega na tym, że kończymy w jednym z dwóch mniej niż idealnych scenariuszy:

  1. Skończyliśmy z dziesiątkami / setkami drobnych projektów - każdy z nich zawierał małe klasy / metody, których potrzebowaliśmy ponownie. Czy warto utworzyć zupełnie nowy .DLLkod, aby tylko odrobinę kodu?
  2. W efekcie powstaje jeden projekt z rosnącą kolekcją niepowiązanych metod i klas. Takie podejście właśnie zrobiła firma, w której kiedyś pracowałem; mieli projekt o nazwie, base.commonktóry zawierał foldery dla takich rzeczy, jak wspomniałem powyżej: sieci, manipulacji ciągami, MVVM itp. To było niezwykle przydatne, ale odwoływanie się do niego niepotrzebnie przeciągało za sobą cały niepotrzebny kod, którego nie potrzebowałeś.

Więc moje pytanie brzmi:

W jaki sposób zespół programistów najlepiej wykorzystuje ponowne wykorzystanie małych fragmentów kodu między projektami?

Interesuje mnie szczególnie to, czy ktoś pracował w firmie, która ma zasady w tym obszarze, lub osobiście spotkałem się z tym dylematem.


Uwaga: moje użycie słów „Projekt”, „Rozwiązanie” i „Dokumentacja” pochodzi z tła programowania .NET w Visual Studio. Ale jestem pewien, że ten problem jest niezależny od języka i platformy.

George Powell
źródło
21
+1, chociaż wydaje mi się, że ktoś pracujący z .NET ma w sobie element humoru, który martwi się przeciąganiem nieistotnego kodu za pomocą odwołania DLL.
JDB
2
@ColeJohnson .NET sam w sobie jest ogromnym odniesieniem! Prawdopodobnie znacznie większy niż biblioteki dll, które sam stworzyłbym.
George Powell,
2
Rozumiem. Jednak kompilator JIT .NET ładuje tylko wymagane metody do pamięci RAM (gdy są wywoływane)
Cole Johnson
1
Prawdziwe. Chociaż nadal musisz rozpowszechniać całą platformę .NET dla każdego, kto chce korzystać z Twojego produktu, trudniej jest zarządzać dużymi projektami i złożonymi rozwiązaniami.
George Powell,

Odpowiedzi:

75

Jeśli naprawdę są to metody / klasy wielokrotnego użytku, możesz zapisać je w niewielkiej liczbie bibliotek „Swiss Army Knife”. Robimy to dość często w mojej firmie; nazywamy je bibliotekami szkieletowymi:

  • Framework.Data - Narzędzia do pracy z zapytaniami do baz danych.
  • Framework.ESB - Standardowe metody interakcji z naszą magistralą usług dla przedsiębiorstw
  • Framework.Logging - Zunifikowany system rejestrowania
  • Framework.Services - Narzędzia do interakcji z usługami internetowymi
  • Framework.Strings - Narzędzia do zaawansowanej manipulacji ciągiem / wyszukiwania rozmytych ciągów znaków itp.
  • ...

W sumie istnieje około kilkunastu bibliotek. Możesz naprawdę rozprowadzać kod według własnego uznania, więc nie musisz kończyć setkami ani zrzucać wszystkiego do jednego gigantycznego zestawu. Uważam, że to podejście pasuje, ponieważ tylko niektóre z naszych projektów będą potrzebne, Framework.Dataa tylko kilka będzie kiedykolwiek potrzebować Framework.Strings, więc konsumenci mogą wybrać tylko te części ram, które są odpowiednie dla ich konkretnego projektu.

Jeśli tak naprawdę są to tylko fragmenty, a nie rzeczywiste metody / klasy, które można łatwo ponownie wykorzystać, możesz spróbować rozpowszechnić je jako fragmenty kodu w IDE (np. Fragmenty kodu Visual Studio ). Zespoły, z którymi pracowałem w przeszłości, miały wspólną bibliotekę fragmentów, która ułatwiła wszystkim przestrzeganie naszych standardowych praktyk kodowania, także z kodem wewnętrznym.

pswg
źródło
4
+1 To byłoby również moje podejście. Chcesz wiedzieć, jak zdecydowałeś, gdzie umieścić kod zajmujący się sprawami z dwóch lub więcej aspektów. Na przykład IPAddressToString. I czy zezwalasz tym bibliotekom na wzajemne korzystanie. Na przykład usługi i dane prawdopodobnie skorzystają na logowaniu ...
Marjan Venema
5
@MarjanVenema W przypadku przekrojowego kodu zależy od tego, którzy konsumenci uznają tę metodę za bardziej przydatną. Na IPAddressToString, jest prawdopodobne, że konsumenci czynienia z protokołów sieciowych będzie musiał użyć, ale konsumenci który nie wiele błahy z ciągów nie troszczą się o adresy IP w ogóle. To prawdopodobnie skończyłoby się w pakiecie sieciowym Framework.Strings.
pswg
@MarjanVenema Staramy się unikać wzajemnych zależności. Nasze usługi i ramy danych są napisane w taki sposób, że nie rejestrują się same, ale ułatwiają konsumentowi napisanie odpowiedniego kodu logowania. Biblioteki frameworka mogą się nawzajem odwoływać, ale tylko przez rozszerzenie - np. Framework.Logging.GibraltarJest szczególnym dodatkiem do systemu rejestrowania.
pswg
5
+1 Możesz wziąć te biblioteki frameworka i wdrożyć je w wewnętrznym repozytorium NuGet (tak prostym jak folder sieciowy) i masz dobry sposób na zarządzanie nim.
Steven Evers
2
@ SteveEvers Aktualnie pracuję nad konfiguracją. : P
pswg
21

Nie zgadzam się z przyjętą odpowiedzią z wielu powodów.

Z mojego doświadczenia wynika, że ​​gdy widzę „różne” biblioteki, takie jak zaakceptowana odpowiedź, są one pretekstem do ponownego wynalezienia koła (lub nie wymyślonego tutaj (NIH) ) - znacznie większego grzechu niż łamanie Dont Repeat Yourself (DRY) .

Czasami naruszenie DRY może być rozsądnym kompromisem, jest lepsze niż wprowadzenie ciasnego sprzężenia. Ponowne użycie jest kwestią drugorzędną w porównaniu z dobrym projektowaniem obiektowym. Nieco (mam na myśli małą ilość, zastosuj zasadę trzech ) powielania jest łatwiejsze do zrozumienia niż podstawa kodu spaghetti.

Podejście wielu bibliotek ogólnego przeznaczenia stanowi zły przykład. Prowadzi to do drobnej ziarnistości zestawu, a zbyt wiele zestawów jest złe. Niedawno zmniejszyłem wewnętrzny z 24 bibliotek do 6 bibliotek. Poprawił czas kompilacji z kilku minut do ~ 20 sekund. Visual Studio działa również wolniej i jest mniej responsywny dzięki większej liczbie zespołów. Posiadanie zbyt wielu bibliotek prowadzi również do zamieszania co do tego, gdzie powinien znajdować się kod; wolą mniej, prostsze zasady.

Dlaczego rzeczy w .NET Framework nie są wystarczająco dobre? Framework jest dość duży; wiele razy widziałem kod, który ponownie implementuje rzeczy, które już tam istnieją. Naprawdę upewnij się, że twoje frameworki wypełniają luki w frameworku .Net i nie istnieją tylko ze względów estetycznych (na przykład „Nie lubię frameworku .Net tutaj” lub być może przedwczesnej optymalizacji )

Wprowadzenie kolejnej warstwy do architektury wiąże się ze znacznymi kosztami złożoności. Dlaczego warstwa istnieje? Widziałem fałszywe ponowne użycie, to znaczy, że kod jest zbudowany na bazie wewnętrznego frameworka. Byłoby o wiele bardziej wydajne wdrożenie go bezpośrednio na standardowych bibliotekach.

Korzystanie ze znormalizowanych technologii (takich jak .Net Framework i popularne biblioteki stron trzecich / bibliotek open source) ma zalety, które często przewyższają porównywalne korzyści technologiczne wynikające z jego samodzielnego zbudowania. Łatwiej jest znaleźć talent, który zna te technologie, a Twoi obecni programiści zainwestują więcej w naukę tego.

Moje rekomendacje:

  • Nie udostępniaj tego kodu.
  • Utwórz nową bibliotekę, jeśli ma spójny cel, nie używaj wzoru kuli z błota .
  • Jeśli to możliwe, użyj ponownie istniejących bibliotek stron trzecich.
  • Preferuj mniej zestawów z prostszymi regułami, gdzie powinien znajdować się kod.
Dave Hillier
źródło
1
Dodatkowa korzyść z korzystania z bibliotek Open Source tam, gdzie są one dostępne - jeśli wprowadzisz jakieś ulepszenia, możesz je udostępnić społeczności! Na przykład z .Net MS opublikowało EnterpriseLibrary (teraz Open Source), która daje całkiem niezły zestaw narzędzi do typowych scenariuszy, znajdź coś, co można poprawić i hej presto! Korzyści dla wszystkich!
glenatron
2
Naprawdę nie widzę niezgody z przyjętą odpowiedzią tutaj :-). „mniej zestawów, z prostszymi regułami, gdzie powinien znajdować się kod” nie jest sprzecznością z przyjętą odpowiedzią. Odpowiedź opowiada się również za użyciem tylko tylu różnych zestawów, ile wydaje się rozsądne.
sleske
Pięć lat później wytyczne Microservice również zbiegły się w tej praktyce: medium.com/standard-bank/...
Dave Hillier
11

W przypadku małych fragmentów kodu - powiedzmy pojedynczej klasy bez zależności - zwykle kopiujemy i wklejamy kod do projektów. To brzmi jak naruszenie OSUSZANIA i muszę przyznać, że czasami tak jest. Ale w dłuższej perspektywie okazało się to znacznie lepsze niż posiadanie jakiegoś ogromnego, wielogłowego projektu wspólnego z kilku powodów.

Po pierwsze, łatwiej jest mieć pod ręką kod, szczególnie podczas budowania i debugowania.

Po drugie, niezmiennie będziesz chciał dokonać drobnych poprawek wspólnego kodu dla tego projektu. Jeśli masz lokalną kopię źródła, możesz po prostu wprowadzić poprawki i nazwać to dniem. Jeśli istnieje biblioteka współdzielona, ​​możesz ją ulepszyć, a następnie upewnić się, że nie zepsujesz wszystkich innych aplikacji lub nie stworzysz koszmaru wersji.

Więc jeśli nie jest wystarczająco rozbudowany, by stworzyć własną przestrzeń nazw, zwykle popychamy go do odpowiednich części projektu i nazywamy to dniem.

Wyatt Barnett
źródło
5
Nie zgadzam się z tym podejściem. Doceniam problemy z utrzymaniem przy zarządzaniu małymi fragmentami kodu, ale argumentowałbym, że można stworzyć wspólną bibliotekę z nich wszystkich, jak sugeruje @psw. Posiadanie duplikatów kodu z drobnymi poprawkami wymaga kłopotów. Zostaną przyjęte założenia, pominięte zostaną poprawki błędów.
Andrew T Finnell,
2
-1 (do odpowiedzi). Z pewnością łatwiej jest mieć wszystkie kopie własnych wersji programów. Tak powstało oprogramowanie w latach 80-tych. Od tego czasu dowiedziałem się, że - w dłuższej perspektywie - prowadzi to do bałaganu. Trudniej jest postępować właściwie i mieć wspólną bibliotekę, ponieważ ludzie będą musieli przekazać znacznie więcej informacji na temat swojej pracy. Cóż, powinni.
Michael Durrant
3
+1 - Myślę, że warto wspomnieć o tym podejściu, nawet jeśli nie jest to takie, którego chcesz bardzo często używać. Niektóre fragmenty przypominają bardziej wzorce projektowe - użyjesz ich ponownie, ale nieco inaczej wszędzie i być może w różnych językach, a być może będziesz chciał je zmienić. Również szeroko używana biblioteka jest mało elastyczna, ponieważ zmiany w jej interfejsie API są bardzo ryzykowne. Wreszcie, takie podejście jako awaryjne poprawia jakość wspólnych bibliotek, utrzymując z nich nieco eksperymentalne elementy.
Eamon Nerbonne
6

Drugie rozwiązanie, które opisujesz, nie jest takie złe. W .NET odwołujesz się również do zestawu z GAC, nawet jeśli używasz tylko jednej jego klasy. „Przeciąganie nieistotnego kodu” nie jest problemem, jak mogłoby się wydawać. W takim przypadku konieczne jest przynajmniej uporządkowanie powiązanych metod i klas w różnych przestrzeniach nazw. Ponadto należy zastosować dobre praktyki projektowania interfejsu API, aby zapobiec bałaganowi w tym rozwiązaniu.

Jeśli chodzi o bardzo małe fragmenty kodu, myślę, że następujące podejście jest dobrym uzupełnieniem wspólnego projektu: Pozwól na ich powielanie w różnych rozwiązaniach. Postępuj z nimi jak najlepszymi praktykami: udokumentuj i przekaż je zespołowi.

Theo Lenndorff
źródło
1
Z wyjątkiem tego, że w przypadku niestandardowych bibliotek oznacza to, że będziesz musiał wysłać duży zestaw tylko z powodu jednego (lub kilku) zastosowań. Nie jest to problem w przypadku standardowych rzeczy, ponieważ i tak są one dostępne, ale zdecydowanie unikałbym wysyłania dużych, ale w większości nieużywanych zespołów, jeśli można je dobrze podzielić.
poke
6

Pracowałem tylko w środowiskach „korporacyjnych”, w których tego rodzaju problem był problemem i za każdym razem była to druga przyjęta opcja. W przeważającej części działa dobrze, ponieważ nie było żadnych ograniczeń dotyczących śladu aplikacji.

Jednak po ostatnim tygodniu spędzonym ze start-upem, który prowadzi własny serwer Nuget, jestem skłonny zaproponować to jako realną alternatywę. Oczywiście problemy, które się pojawią, będą dotyczyły zdolności odkrywania.

Jeśli projekty są odpowiednio szczegółowe, a przestrzenie nazw są sensowne, widzę, że staje się to popularnym podejściem w niektórych miejscach.

Kofi Sarfo
źródło
W jakim sensie oczekujesz, że nie będą odkrywalne? W ten sposób korzystamy z dużej i stale rosnącej liczby pakietów nuget. Największym problemem, jaki mamy, jest zarządzanie wersjami i zależnościami.
pdr
O tak. Te też. Przez problemy związane z wykrywaniem mam na myśli to, że biorąc pod uwagę wystarczającą liczbę małych pakietów z określoną funkcją, może być trudniej skatalogować (i znaleźć) każdy z nich. Na przykład, w jaki sposób twój zespół informuje, które pakiety zawierają różne funkcje? (pokazując tutaj ignorancję przy wyszukiwaniu
samorodków
Rozumiem. Tak, zdecydowanie możesz umieścić w opisie wszystko, co chcesz, a to staje się możliwe do przeszukiwania, ale myślę, że pogrupowaliśmy pakiety wystarczająco dobrze, aby nie stanowiło to problemu.
pdr
@sarfeast Byłoby miło, gdybyś mógł udostępnić link do dowolnego serwera Nuget i powiedzieć trochę o tym.
Hans-Peter Störr
6

Niedawno o tym pomyślałem i przyszła mi do głowy duża biblioteka popularnych metod, o których wspomniano do tej pory, ale z pewnym zdziwieniem. Projekt biblioteki pozwoliłby ci skonfigurować w czasie kompilacji, które elementy są uwzględnione, podobnie jak projekt BusyBox . Dzięki takiemu podejściu możesz uzyskać repozytorium biblioteki w stylu zlewozmywaka kuchennego, ale chwytaj tylko narzędzia potrzebne podczas kompilacji.

Harvey
źródło
5

GitHub ma bardzo przydatne narzędzie do zapisywania fragmentów kodu https://gist.github.com/

Przechowuje twoje fragmenty jako repozytoria git, które możesz zachować jako prywatne, lub użyć do udostępniania fragmentów innym osobom.

blacksh33p
źródło
3

W zależności od wielkości zespołu / projektu / firmy będzie to raczej trudne do zrobienia skutecznie, chyba że jakoś jest już wbudowane w twoje środowisko, a każde znalezione rozwiązanie (jeśli je wdrożysz) będzie kosztować trochę pieniędzy. (Może cię to bardziej zabezpieczyć, ale nie będziesz w stanie łatwo zmierzyć). Musisz sprawdzić, czy jest wart swojej ceny. Należy również pamiętać, że rozwiązania wielokrotnego użytku stają się abstrakcyjne i często pasują do wielu sytuacji, ale nie są optymalne.

W każdym razie, jeśli chcesz to zrobić dla kodu wygenerowanego przez więcej niż jedną osobę, najpierw potrzebujesz świadomości wszystkich i współpracy. Dotyczy to programistów i menedżerów.

Następnie upewnij się, że znasz zakres, w którym chcesz to zrobić. Zespół? Projekt? Departament? Firma? W zależności od odpowiedzi, rodzaj kodu, który umieścisz w takich rozwiązaniach, będzie się różnił, podobnie jak szczegółowość, z jaką dostosujesz biblioteki DLL. Kiedy już zdecydujesz się na to, ktoś (najlepiej z entuzjazmem dla pomysłu - ty?) Powinien usiąść i zacząć nadawać temu strukturę.

Jednak samo utworzenie takich bibliotek DLL nie wystarczy, aby załatwić sprawę. Aby były użyteczne, musisz je zareklamować (użytkownikom i współpracownikom) i utrzymywać je jak każde inne oprogramowanie, co zwykle oznacza, że ​​musisz powierzyć komuś odpowiedzialność za nie przez długi czas. Będziesz także potrzebować wiarygodnej dokumentacji, która również będzie wymagała konserwacji. Przy odrobinie szczęścia i współpracy możesz skończyć z najlepszymi praktykami, ale równie dobrze może ewoluować do własnego projektu, w zależności od wielkości i liczby zaangażowanych zespołów. Do tego nadal będziesz potrzebować wsparcia zarządzania.

Tomasz
źródło
3

często mam problemy, a moim preferowanym rozwiązaniem jest opublikowanie kodu w repozytorium obsługującym sieć github / pubic. rozwiązuje wiele problemów -

  1. łatwy dostęp i łatwe udostępnianie. cvs / svn / enterprise-repos oznacza wypisywanie projektu do wielu obszarów roboczych IDE, a czasem konieczność przełączania obszarów roboczych lub komputerów tylko w celu odniesienia się do małego fragmentu kodu.
  2. zakładając, że te fragmenty kodu nie są zastrzeżonymi / niejawnymi fragmentami kodu i są odmianami publicznie dostępnej wiedzy, opublikowanie ich w publicznym repozytorium, takim jak github, oznacza, że ​​inni będą na to patrzeć, a nawet mogą się przyczynić.
  3. publikowanie czegoś w domenie publicznej pod Twoim nazwiskiem ma dodatkową presję reputacji. podwójnie sprawdzisz i zaktualizujesz, ponieważ odzwierciedla to twoje umiejętności programistyczne.
  4. aktualizacje. rzeczą w utrzymywaniu fragmentów kodu w repozytorium jest to, że jeśli fragment kodu nie był używany od dłuższego czasu, może się zepsuć (zawierać nieaktualne apis / libs). przykład - fragment kodu java do odczytu pliku. być może wymyśliłeś najlepszy sposób, aby to zrobić w 2009 roku, ale w 2014 roku pojawia się nowy plik API, który zmienia wszystko. twój fragment? wciąż utknął w 2009 roku. w publicznym repozytorium rzeczy zostaną zaktualizowane przez ciebie (ponieważ punkt 3), twoich kolegów z drużyny lub jakiegoś członka ogólnej populacji programistów, a w tym czasie możesz nawet uzyskać sugestie, aby naprawić coś, co mogłeś źle postępować przez długi czas.

Jedną rzeczą polecam - bez względu na to, gdzie przechowujesz swoje fragmenty, zawsze korzystaj z google przed użyciem. rzeczy cały czas się zmieniają. zapisane fragmenty oszczędzają czas, ale także sprzyjają samozadowoleniu .

Quest Monger
źródło
2

Mamy osobne „narzędzia” projektu, w których przechowujemy wszystkie te małe metody wraz z testami.

Gdy projekt potrzebuje jakiegoś narzędzia, po prostu dodaje plik źródłowy wymaganą metodą z „dodaj jako link”.

Oznacza to, że nie dodano żadnych zależności w czasie wykonywania (chyba że dołączony plik tego potrzebuje).

System działał dobrze, ale podobnie jak wszystkie inne, należy przewidzieć, co to jest narzędzie. Wymaganie wysokiego zakresu testów sprawdziło się u nas dobrze, a testy stanowią również dobrą dokumentację użytkowania. Odkrycie wciąż jest dla nas nierozwiązanym problemem.

Jedną z komplikacji związanych z projektem użyteczności jest wybór poziomu widoczności przedmiotów. Ogólna zasada jest taka, że ​​metody powinny być wewnętrzne, a struktury danych - publiczne.

adrianm
źródło
2

Moja firma korzysta z lokalnych usług intranetowych. Mamy kilka usług internetowych skonfigurowanych jako wspólne wewnętrzne usługi sieciowe, a gdy inny projekt potrzebuje dostępu do jednej z usług, wysyła żądanie HTTP ze zdefiniowanym interfejsem. Ponieważ znajduje się w intranecie, mieszczącym się w tej samej farmie serwerów, żądania te są bardzo szybkie.

Oczywiście działa to tylko z aplikacjami internetowymi (i działa tylko w milisekundach, gdy jest w tej samej sieci lokalnej), ale ma kilka naprawdę fajnych zalet.

Ben Lee
źródło
0

Niedawno wymyśliłem tę usługę: Snip2Code ( http://www.snip2code.com ).

To interesujący sposób na udostępnianie tylko fragmentów kodu (nie tylko bibliotek) zespołowi. Przełamuje zwykły sens tworzenia wspólnych bibliotek, do których należy się odwoływać w innych projektach, i moim zdaniem jest to cenna wizja.

Ponadto istnieje wiele scenariuszy, w których użycie wspólnej biblioteki po prostu nie ma zastosowania: rozważmy na przykład niektóre wzorce projektowe, takie jak Singleton, strategia lub obserwator. Możesz tworzyć biblioteki do obsługi takich wzorców, ale wciąż nie ma 100% zasięgu.

Rzeczywistą potrzebą jest posiadanie narzędzia do dzielenia się powszechnymi praktykami w zespole. Próbowałem użyć Gistub, ale utknąłem w ich poszukiwaniu (naprawdę kiepskim) i w tym, że nie mogę dzielić się nimi tylko z moim zespołem, a nie z innymi ...

(Oświadczenie: Jestem jednym z założycieli Snip2Code i byłem razem z moimi współzałożycielami w tym samym nastawieniu jakiś czas temu: dlatego postanowiliśmy rozpocząć ten projekt !!)

Cristiano Ghersi
źródło