Niedawno rozmawiałem z kolegą na temat stylu kodu. Twierdził, że korzystanie z interfejsów API i ogólnych wzorców, których używasz, powinno być możliwie jak najbardziej zbliżone do otaczającego kodu, jeśli nie z bazą kodu jako całością, podobnie jak wygląd kodu (pozycjonowanie nawiasów, wielkie litery itp.) . Na przykład, gdybym dodawał metodę do klasy DAO w języku C #, spróbowałbym użyć LINQ tam, gdzie to właściwe, aby mój kod był czysty i łatwy w utrzymaniu, nawet jeśli żadna z innych metod w tej klasie go nie używała. Jednak mój kolega argumentowałby, że nie powinienem go używać w tym przypadku, ponieważ byłoby to sprzeczne z istniejącym stylem tej klasy i dlatego trudniejsze do zrozumienia.
Na początku jego pozycja była dość ekstremalna, ale po przemyśleniu jej przez chwilę zaczynam rozumieć jego rację. W hipotetycznym przykładzie LINQ być może ta klasa go nie zawiera, ponieważ moi koledzy nie znają LINQ? Jeśli tak, to czy mój kod nie byłby łatwiejszy w utrzymaniu dla innych programistów, gdybym go nie używał? Z drugiej strony, jeśli naprawdę wierzę, że zastosowanie takiej techniki zapewni czystszy kod, to czy nie powinienem go używać, nawet jeśli drastycznie różni się on od otaczającego kodu?
Myślę, że sedno argumentu mojego kolegi polega na tym, że jeśli wszyscy zaczniemy wdrażać podobną funkcjonalność w bazie kodu na różne sposoby i każdy z nas będzie uważał, że nasza droga jest „najlepsza”, to ostatecznie cały kod staje się coraz trudniejszy rozumieć. Jednak w tej chwili nadal uważam, że jeśli będziemy zbyt ślepo podążać za istniejącym kodem, wówczas jakość z czasem będzie powoli gnić.
W jakim stopniu wzorce są częścią stylu kodu i gdzie powinniśmy wytyczyć granicę między zachowaniem spójności a wprowadzaniem ulepszeń?
źródło
IEnumerable
s zamiast DAO.Odpowiedzi:
Aby udzielić bardziej ogólnej odpowiedzi:
W takim przypadku istnieją dwie „najlepsze praktyki” programowania, które są sobie przeciwne: spójność kodu jest ważna, ale tak samo jak wybór najlepszej możliwej metody wykonania zadania. Nie ma jednej poprawnej odpowiedzi na ten dylemat; zależy to od kilku czynników:
Jak korzystny jest „właściwy” sposób?
Jak duży problem spowodowałby niespójność?
W oparciu o równowagę tych problemów musisz dokonać właściwego wyboru trasy. Osobiście uważam, że spójność jest niewielka ze względu na spójność i wolałbym stosować najnowsze, najlepsze metody, chyba że będzie to wiązało się ze znacznymi kosztami.
Oczywiście istnieje trzecia opcja: przepisanie istniejącego kodu, aby korzystał z najlepszych metod i był spójny. Są chwile, kiedy jest to konieczne, ale wiąże się to z wysokimi kosztami.
źródło
Zachowanie spójności ma niewielką wartość z mojej perspektywy; ciągłe wprowadzanie ulepszeń jest koniecznością.
Pozycja twojego kolegi naprawdę hamuje innowacje. Argument spójności wprowadza cię w sytuację, w której możesz użyć, na przykład LINQ, tylko jeśli migrujesz cały kod, aby użyć LINQ. No cóż, nie mamy na to czasu, prawda?
Wolałbym mieć niespójność, gdy jakiś kod nadal działa
foreach
na ArrayLists, a inne części używają LINQIEnumerable<T>
, zamiast trzymać się najstarszego sposobu robienia rzeczy do końca czasu.Obowiązkiem współpracowników jest pozostawanie aktualnym i uczenie się nowych sposobów działania.
źródło
Spójność interfejsu API jest bardzo ważna, zarówno dla publicznych, jak i wewnętrznych interfejsów API.
Spójność formatowania kodu jest ważna i idealnie powinna być egzekwowana przez narzędzie do automatycznego formatowania z tymi samymi regułami formatowania dla wszystkich. Ułatwia życie ze współdzieloną bazą kodu kontrolowaną wersją.
Konwencje nazewnictwa powinny być spójne, również w przypadku zmiennych lokalnych itp.
Narzędzia do analizy statycznej powinny być stosowane w celu egzekwowania pewnych innych konwencji i dobrych praktyk (ale nie ślepo przestrzegaj domyślnych ustawień takiego narzędzia, wartości domyślne mogą czasem graniczyć z obłędem), chociaż jeśli coś tego wymaga, nie bój się wyłączyć niektórych tymczasowo sprawdź (zwykle z dyrektywą w komentarzu), czy możesz to uzasadnić.
To, co dzieje się w funkcjach / metodach , oprócz tego, co wymieniono powyżej, nie musi być w żaden sposób spójne, o ile sam jest dobrym kodem . Dobry, zrozumiały, dobrze skomentowany kod jest bardzo ważny, ale potem, jeśli kompilator i narzędzia analizy statycznej uważają, że jest to spójny kod, to wystarczająco spójny.
Jeśli chodzi o nowe funkcje językowe, takie jak LINQ (cóż, to nie jest dokładnie nowe), jedyną rzeczą, którą należy wziąć pod uwagę, jest to, czy nowa wystarczająca wersja języka / bibliotek będzie używana wszędzie tam, gdzie będzie używany kod? W razie wątpliwości trzymaj się funkcji, o których wiadomo, że są kompatybilne. To oczywiście nie przeszkadza w rozpowszechnianiu aktualizacji wersji w całym systemie, dzięki czemu możesz zacząć korzystać z nowych fajnych rzeczy.
I każdy programista pracujący z kodem powinien być na bieżąco, więc każdy programista .NET powinien znać LINQ, a jeśli nie, powinien być zmuszony do nauki, dla własnego dobra (nigdy nie wiadomo, kiedy będziesz szukał nowego praca w tym biznesie, z tego czy innego powodu).
źródło
Odpowiedź na to pytanie jest prosta.
Spójność ma ogromne znaczenie.
ale zawiera zastrzeżenie ...
Ty i twój współpracownik prawdopodobnie macie obsesję na punkcie niewłaściwej konsystencji
Realizacje są jednorazowe. Można je całkowicie przebudować z różnym stopniem łatwości, w zależności od jakości i kompleksowości zestawu testowego. Martwiąc się o rzeczy takie jak „Czy to powinna być właściwość?”, „Czy cienki kod nie powinien używać LINQ zamiast konstrukcji niższego poziomu?” ma wątpliwą wartość. Trudno jest powiązać jakiekolwiek pomiary z wartością spójności na poziomie wdrożenia. O wiele lepszym pytaniem na tym poziomie jest „Czy ten kod działa zgodnie z reklamą?”. Spójność implementacji TL; DR polega na włączeniu hobgoblinów przez „małe umysły”.
Dlaczego spójność nie jest tutaj tak ważna? Wdrożenia zwykle mają niewielką liczbę współpracowników. Większość metod jest zapisywana i nigdy więcej nie dotykana. Z pozostałego kodu liczba metod, które mają dwóch autorów, prawie na pewno większość. Ten wzór trwa w nieskończoność . W tym kontekście spójność po prostu nie jest tak ważna. Jeśli okres przechowywania kodu jest dość mały ( kilka lat ), korzyści wynikające z agresywnej spójności są prawdopodobnie nieistotne.
Nie oznacza to, że powinieneś zwariować w swoich implementacjach. Mówi raczej, że ładny, czysty i prosty projekt będzie rzędami wielkości bardziej wartościowymi dla twojego hipotetycznego przyszłego opiekuna niż głupia metoda konsystencji płyty kotła metodą. To prowadzi nas do prawdziwego punktu ...
Interfejsy API nie są jednorazowe.
To wszystko poziom kodu API, usługi sieciowe, SDK itp. Muszą one, muszą, MUSI być spójne. Wzrost wydajności z tej różnorodności konsystencji jest ogromny z wielu powodów:
Testy integracyjne:
Jeśli utrzymasz spójność interfejsu API, możesz tworzyć pakiety testów integracyjnych. Dzięki temu programiści mogą swobodnie wymieniać szczegóły implementacji i uzyskiwać natychmiastową weryfikację. Chcesz zamienić swoje badziewie na LINQ? Czy działają testy integracyjne? Zapewnia również sprawdzanie poprawności podczas przygotowań do przejścia do produkcji. Ponieważ komputery są szybkie, pojedynczy laptop może wykonać pracę tysiąca testerów wykonujących przyziemne zadania. Jest to równoznaczne ze znacznym zwiększeniem liczby pracowników w organizacji.
Wydajność
Gdy interfejsy API są spójne, możesz zgadywać, jak korzystać z interfejsu API, po prostu postępując zgodnie z tym, czego się nauczyłeś na temat używania innych części interfejsu API. Wynika to z faktu, że interfejs API zapewnia naturalny, spójny „wygląd i działanie”. Oznacza to, że Twój klient spędza mniej czasu na przeglądaniu dokumentacji. Wbudowanie jest łatwiejsze i tańsze. Osoby, które opracowały interfejs API, zadają mniej pytań. Spójność sprawia, że wszyscy są zwycięzcami
Dlaczego spójność jest ważna w tym scenariuszu? Ponieważ interfejsy API mają dokładnie odwrotny problem z implementacjami. Liczba osób korzystających z nich jest zwykle znacznie większa niż liczba osób przyczyniających się do ich implementacji. Niewielkie zyski z niewielkiej spójności są zwielokrotniane, a koszty utrzymania tej spójności są amortyzowane.
Wniosek
Konsystencja jest droga. Na pierwszy rzut oka obniża produktywność. Ogranicza programistów i utrudnia ich życie. Ogranicza to sposób, w jaki mogą rozwiązać problem, niekiedy zmuszając go do rozwiązania go w nieoptymalny sposób. Często dzieje się tak z powodów, których nie rozumieją, są źle rozumiani lub nie są wtajemniczeni (umowy, większe zasady organizacyjne lub międzyorganizacyjne).
Raymond Hettinger napisał kilka doskonałych punktów w swoim przemówieniu Pycon 2015 na temat używania przewodnika po stylu PEP8 dla zespołów programistów pythonowych. Pokazał, że obsesja na punkcie spójności stylistycznej fragmentu kodu spowodowała, że recenzenci kodu stracili poważne wady logiczne i projektowe. Jego hipotezę można streścić, ponieważ znalezienie niespójności stylistycznych jest łatwe; ustalenie prawdziwej jakości fragmentu kodu jest trudne
Punkt tutaj jest krytyczny. Określ, gdzie spójność jest ważna i chroń ją agresywnie. Tam, gdzie to nie jest ważne, nie marnuj czasu. Jeśli nie możesz zapewnić obiektywnego sposobu pomiaru wartości spójności (w powyższych przypadkach „efektywne zatrudnienie”, koszt jako funkcja wydajności) i nie możesz wykazać, że zwroty są znaczące, prawdopodobnie robisz krzywdę Twoja organizacja.
źródło
Język C # wciąż się rozwija. Gdyby ludzie nie nauczyli się zmian z C # 1, straciliby:
To tylko niewielki wybór typowych funkcji znalezionych w artykule w Wikipedii. Chodzi mi o to, że jeśli programiści się nie nauczą, baza kodów pozostanie w próżni. Można mieć nadzieję, że Twoi programiści ciągle się ulepszają, a baza kodu ewoluuje, obsługiwana przez kompletny zestaw testów. Czy pamiętasz, jak źle było z .NET 1 w przypadku ręcznego wdrażania właściwości.
Linq ułatwia życie. Użyj go tam, gdzie możesz. Możesz motywować członków swojego zespołu.
Ulepszenia są stopniowe. Dla mnie nie ma sensu utrzymywanie kodu w starym stylu, który jest mniej czytelny i potencjalnie mniej konserwowalny. Członkowie twojego zespołu powinni przynajmniej być w stanie ustalić, co się dzieje, nawet jeśli nie mogą tego napisać.
źródło
Powinieneś być spójny, ale niekoniecznie ze starym kodem. Oznacza to, że Twój zespół powinien uzgodnić właściwy sposób zrobienia czegoś i używać go w ten sposób, gdy zostanie napisany nowy kod lub zostaną wprowadzone istotne zmiany.
W ten sposób czerpiesz większość korzyści wynikających ze spójności (w szczególności nie będzie miało znaczenia, kto pisze kod), ale wciąż możesz poprawić, jeśli zespół dostrzeże wyraźną korzyść, robiąc rzeczy w inny sposób.
W idealnym świecie przepisalibyśmy cały stary kod, aby był zgodny z nowym właściwym sposobem. Chociaż nie jest to ekonomicznie opłacalne, powinno mieć sens techniczny (w przeciwnym razie nowy sposób nie jest lepszym sposobem), a twoim długoterminowym planem powinno być jego ulepszenie. Jeśli to nie jest tego warte, nie przejmuj się nowym sposobem. Innymi słowy, nowy sposób na uznanie go za właściwy musi mieć wyraźną przewagę.
źródło
Myślę, że ważne jest przestrzeganie stylu kodu w projekcie np. konwencje nazewnictwa, wcięcia itp.
Nie zgadzam się, że powinieneś być ograniczony w używaniu nowych konstrukcji językowych lub wzorców projektowych tylko dlatego, że twoi koledzy ich nie rozumieją lub nie byli wcześniej wykorzystywani w projekcie.
Oczywiście te rzeczy powinny mieć dobre powody, aby z nich korzystać np. wydajność lub zwięzłość, w stosownych przypadkach.
źródło
Byłbym bardzo ostrożny na ślepo podążając za obecnymi wzorami projektowymi. Oczywiście, gdy nie ma znaczących wad, zawsze należy próbować stosować podobne wzorce w całej bazie kodu.
Jednak zbyt łatwo jest wejść w sytuacje, w których większość programistów uważa, że „najlepszą praktyką” jest podążanie za złymi wzorcami prowadzącymi do sytuacji, w których dobrzy programiści piszą zły, niemożliwy do utrzymania kod.
Z drugiej strony spójność jest ważna. Kiedy mamy do czynienia z olbrzymimi podstawami kodu, niezwykle przydatne jest staranie się przestrzegać podobnych wzorców, aby nawet jeśli programiści nie przeczytali każdego cala podstawy kodu, wiedzą, czego się spodziewać.
Dlatego uważam, że najlepiej jest ustalić i zaktualizować wytyczne dotyczące tego, jakie wzorce powinni stosować programiści, jeśli to możliwe. W ten sposób każdy nowy kod jest zgodny z innym nowym kodem.
źródło
Odbywamy regularne, dość nieformalne spotkania techniczne, które każdy z nas może prowadzić. Jeśli znajdziemy nową technikę, prezentujemy ją na spotkaniu. Na ogół masz poczucie, jak dobrze pomysł jest akceptowany i rozumiany przez twoich kolegów. Pomaga ci to zdecydować, czy mądrze jest włączyć go do twojego kodu, pomaga innym rozszyfrować go, jeśli to zrobisz, a także ustanawia osobę „idź do”, jeśli inni potrzebują pomocy w tym stylu. Gdyby nikt nie wymyślił koła na nowo, nadal ciągnęlibyśmy rzeczy po kłodach.
źródło