Jak w znaczący sposób mierzyć łatwość konserwacji?


23

Kontekst: Jestem programistą korporacyjnym w sklepie MS.

Czy ktoś może polecić dobry sposób obiektywnego pomiaru możliwości utrzymania części kodu lub aplikacji?

Dlaczego łatwość konserwacji : Mam dość wskaźników „jakości” w mojej grupie, które dotyczą jedynie liczby błędów i pokrycia kodu. Oba wskaźniki są łatwe do grania, szczególnie gdy nie mierzysz łatwości konserwacji. Krótkowzroczność i terminy skutkują ogromnymi długami technicznymi, które tak naprawdę nigdy nie zostaną rozwiązane.

Dlaczego umiejętność obiektywnego pomiaru : pracuję w dużej grupie przedsiębiorstw. Jeśli nie możesz obiektywnie tego zmierzyć, nie możesz pociągać ludzi do odpowiedzialności za to, ani sprawić, by byli w tym lepsi. Subiektywne pomiary albo się nie zdarzają, albo nie są konsekwentne.

Patrzę na metryki kodu VS2010 , ale zastanawiam się, czy ktoś ma jakieś inne rekomendacje.


@Anon - zgadzam się, ale przynajmniej dałoby mi to miejsce do rozpoczęcia. W tej chwili nie ma nic; nie trzeba nawet grać.
nlawalker 24.01.11

1
Naprawdę nie rozumiem, jak można to zrobić bez recenzji kodów równorzędnych. Ktoś musi naprawdę zrozumieć ogólny projekt systemu (i jeden musi istnieć), aby spojrzeć na jednostkę kodu i przejść ... hm można to poprawić przez ulepszony projekt lub jest to represja kodu lub dobry Boże, twoje narzędzia są nieaktualne ... Z podobnej uwagi, możesz zachować ogólne wytyczne, takie jak: „hej, nie jest to dobry pomysł, aby kodować indeksy w widoku siatki, używać szablonów pozycji i wybierać kolumny według nazwy”. Jeśli chodzi o to, deweloperzy muszą być dobrzy i współpracować. Da Vinci nie może uczyć niesamowitości.
P.Brian.Mackey

8
Jeśli masz programistów metryki do gier zamiast pisać już dobry kod, to dodanie kolejnych metryk spowoduje, że będą oni również korzystać z tych metryk, ale nie rozwiąże problemu . Rozwiązaniem jest całkowite zlikwidowanie metryk i użycie innych środków (na przykład recenzje kodu publicznego) w celu zapewnienia jakości kodu.
Anon.

3
„Wszystko, co można policzyć, niekoniecznie się liczy; wszystko, co się liczy, niekoniecznie musi być policzone”. -Einstein
Jason Baker

@nlawalker Oprócz problemów, które już podnieśli odpowiedzi, twoje pytanie jest obciążone wątpliwym założeniem, że gdyby takie pomiary istniały, ludzie mogliby coś z tym zrobić. Niska konserwowalność wynika z różnych czynników niezależnych od samego oprogramowania: jak trudny lub dobrze zdefiniowany jest problem, który próbuje rozwiązać program, doświadczenie personelu, rotacja, czas potrzebny na wprowadzenie na rynek, zmiany zakresu ... po prostu nie można zdobyć nagrody w związku z tym oczekiwanie, że problem jest kwestią dobrej woli.
Arthur Havlicek

Odpowiedzi:


7

Zastrzeżenie dotyczące pomiaru łatwości konserwacji polega na tym, że próbujesz przewidzieć przyszłość. Pokrycie kodu, liczba błędów, LOC, cykliczność złożoności wszystko to zajmuje się teraźniejszością .

Rzeczywistość jest taka, że ​​jeśli nie masz konkretnych dowodów na to, że kodu nie da się utrzymać tak, jak jest ... to ... naprawienie błędu spowodowało N niepotrzebnych godzin z powodu niemożliwego do utrzymania kodu; wtedy posiadanie nogi do stania będzie z natury trudne. W tym przykładzie mogło to być spowodowane faktem, że zastosowano zbyt złożoną metodologię, gdy wystarczyłoby coś znacznie prostszego. Wkraczanie w obszar, w którym próbujesz zmierzyć metodologie, paradygmaty i najlepsze praktyki, staje się coraz trudniejsze, przynosząc niewielki lub żaden długoterminowy zysk.

Zejście tą ścieżką jest niestety drogą do nikąd. Skoncentruj się na odkrywaniu głównych problemów, które mają istotne zalety i nie są związane z osobistymi odczuciami na temat problemu, takimi jak brak konwencji nazewnictwa w całej bazie kodu i znajdź sposób pomiaru sukcesu i porażek wokół tego głównego problemu. Pozwoli to na rozpoczęcie zestawiania zestawu bloków konstrukcyjnych, z których następnie możesz zacząć formułować rozwiązania.


7

Miarą, której używam lub lubię myśleć, że używam jest:

Dla każdego niezależnego, pojedynczego, jednowierszowego wymagania funkcjonalnego typu „weź lub zostaw”, wykonaj migawkę podstawy kodu przed jego wdrożeniem. Następnie zaimplementuj go, w tym znajdując i usuwając wszelkie błędy wprowadzone w tym procesie. Następnie uruchom diffmiędzy bazą kodu przed i po. diffPokaże listę wszystkich insercji, delecji i modyfikacji wprowadzonych zmian. (Jak wstawienie 10 kolejnych wierszy kodu to jedna zmiana.) Ile było zmian? Im mniejsza jest ta liczba, tym kod jest łatwiejszy w utrzymaniu.

Nazywam to redundancją kodu źródłowego, ponieważ jest to jak redundancja kodu korygującego błędy. Informacje były zawarte w 1 części, ale zostały zakodowane jako N części, które wszystkie muszą być wykonane razem, aby były spójne.

Myślę, że taki jest pomysł DRY, ale jest to trochę bardziej ogólne. Powodem, dla którego ta liczba jest niska, jest fakt, że jeśli potrzeba N zmian, aby zaimplementować typowe wymaganie, a jako zawodny programista dostaniesz tylko N-1 lub N-2 z nich poprawnie zrobionych, na początku umieściłeś 1 lub 2 błędy. Oprócz wysiłków związanych z programowaniem O (N), błędy te muszą zostać wykryte, zlokalizowane i naprawione. Dlatego małe N jest dobre.

Konserwowalność niekoniecznie oznacza czytelność dla programisty, który nie nauczył się, jak działa kod. Optymalizacja N może wymagać robienia pewnych rzeczy, które tworzą krzywą uczenia się dla programistów. Oto przykład. Jedną z rzeczy, która pomaga, jest to, że programista próbuje przewidzieć przyszłe zmiany i pozostawia wskazówki w komentarzu do programu.

Myślę, że gdy N jest wystarczająco zredukowane (optymalne jest 1), kod źródłowy czyta się bardziej jak język specyficzny dla domeny (DSL). Program nie tyle „rozwiązuje” problem, co „stwierdza” problem, ponieważ idealnie każde wymaganie jest przekształcane jako pojedynczy fragment kodu.

Niestety nie widzę ludzi, którzy dużo się uczą, jak to robić. Wydaje się raczej, że myślą, że rzeczowniki mentalne powinny stać się klasami, a czasowniki metodami, a jedyne, co muszą zrobić, to obrócić korbą. Z mojego doświadczenia wynika, że ​​kod to N równy 30 lub więcej.


Czy nie stanowi to wielkiego założenia, że ​​wszystkie wymagania funkcjonalne są mniej więcej tego samego rozmiaru? I czy ta metryka nie zniechęca do podziału obowiązków? Muszę wprowadzić funkcję poziomą; najbardziej „utrzymywalny” kod jest zatem prawie całkowitym przepisaniem programu, który jest całkowicie zawarty w jednej metodzie monolitycznej.
Aaronaught

@Aaronaught: Nie wiem, jak wspaniale jest, ale w naszej grupie opracowujemy listy wymagań / funkcji, niektóre współzależne, inne nie. Każdy z nich ma stosunkowo krótki opis. Jeśli wymaga to poważnego przepisania, na pewno to widziałem / zrobiłem, ale mówi mi, że prawdopodobnie byłby lepszy sposób na uporządkowanie kodu. To jest mój kanoniczny przykład. Nie twierdzę, że jest łatwy do nauczenia, ale kiedy się go nauczysz, oszczędza duży wymierny wysiłek, wprowadzając zmiany szybko i bezbłędnie.
Mike Dunlavey

5

Utrzymanie nie jest tak naprawdę wymierne. Jest to subiektywne spojrzenie na osobę oparte na jej doświadczeniach i preferencjach.

Aby uzyskać kawałek kodu, wymyśl idealną formę.

Następnie dla każdego odchylenia prawdziwego kodu od tego idealnego zmniejsz wartość 100 o pewną liczbę. Od tego, co dokładnie zależy od konsekwencji wyboru niedoskonałego podejścia.

Przykład:

Fragment kodu odczytuje i importuje pewien format danych i może wyświetlać komunikat o błędzie, jeśli coś jest nie tak.

Idealne rozwiązanie (100) zawierałoby komunikaty o błędach przechowywane w jednym wspólnym miejscu. Jeśli w twoim rozwiązaniu są one zakodowane na stałe jako stałe łańcuchowe bezpośrednio w kodzie, zdejmujesz, powiedzmy 15, off. Tak więc twój wskaźnik utrzymania wynosi 85.


4

Jednym z rezultatów kodu, który jest trudny w utrzymaniu, jest to, że naprawienie błędów zajmie ci więcej czasu (średnio). Na pierwszy rzut oka wydaje się, że jednym pomiarem jest czas potrzebny na naprawienie błędu od momentu przypisania (tj. Poprawka jest uruchomiona) do momentu „gotowości do przetestowania”.

Teraz zadziała to naprawdę tylko po naprawieniu rozsądnej liczby błędów, aby uzyskać „średni” (cokolwiek to znaczy) czas. Nie możesz użyć tej liczby do żadnego konkretnego błędu, ponieważ to, jak trudno jest wyśledzić, nie zależy tylko od „łatwości konserwacji” kodu.

Oczywiście, gdy naprawiasz więcej błędów, kod staje się „łatwiejszy” do utrzymania, ponieważ poprawiasz go (a przynajmniej powinieneś być) i zaczynasz się lepiej zaznajomić z kodem. Przeciwdziałanie temu polega na tym, że błędy będą bardziej niejasne, a zatem trudniejsze do wyśledzenia.

Ma to również problem z tym, że jeśli ludzie będą spieszyć się z poprawkami błędów, aby uzyskać niższy wynik, albo powodując nowe błędy, albo nieprawidłowo naprawiając istniejący, co prowadzi do jeszcze większej pracy i być może nawet gorszego kodu.


2

Uważam, że Visual Studio Code Metrics jest całkiem przyzwoite, ponieważ zapewnia szybką miarę „łatwości konserwacji”. Przechwytywanych jest 5 podstawowych wskaźników:

  • Złożoność cykliczna
  • Głębokość dziedziczenia
  • Couling klasy
  • Linie kodu (na metodę, na klasę, na projekt, cokolwiek, w zależności od poziomu roll-up)

Indeks konserwacji jest dla mnie przydatny. Jest to indeks złożony oparty na:

  1. Rozmiar całkowity (linie kodu)
  2. Liczba klas lub plików
  3. Liczba metod
  4. Cyklomatyczna złożoność powyżej 20 (lub 10 - konfigurowalne, 10 to moja preferencja)
  5. Powielanie

Czasami przyjrzę się moim metodom z niskim indeksem konserwacji (niski = zły dla tego). Niemal bezbłędnie, metody w moim projekcie o najniższym wskaźniku utrzymania są najbardziej potrzebne do przepisania i najtrudniejsze do odczytania (lub utrzymania).

Więcej informacji na temat obliczeń znajduje się w białej księdze .


1

Dwa, które będą miały znaczenie, to cykliczność i sprzężenie klas. Nie możesz wyeliminować złożoności, wszystko, co możesz zrobić, to podzielić ją na części możliwe do zarządzania. Te 2 miary powinny dać ci wyobrażenie o tym, gdzie można znaleźć trudny w utrzymaniu kod, a przynajmniej gdzie najtrudniej szukać.

Cyklomatyczna złożoność jest miarą liczby ścieżek w kodzie. Każda ścieżka powinna zostać przetestowana (ale prawdopodobnie nie jest). Coś o złożoności powyżej około 20 należy podzielić na mniejsze moduły. Moduł o cyklicznej złożoności wynoszącej 20 (można by to powielić za pomocą 20 kolejnych if then elsebloków) będzie miał górną granicę 2 ^ 20 ścieżek do przetestowania.

Sprzężenie klas jest miarą tego, jak ściśle powiązane są klasy. Przykład złego kodu, z którym pracowałem u mojego poprzedniego pracodawcy, zawiera komponent „warstwy danych” zawierający około 30 elementów w konstruktorze. Osoba w większości „odpowiedzialna” za ten komponent dodawała parametry biznesowe i parametry interfejsu użytkownika do wywołań konstruktora / otwartych, dopóki nie była to naprawdę wielka kula błota. Jeśli pamięć służy mi poprawnie, było około 15 różnych nowych / otwartych wywołań (niektóre już nieużywane), wszystkie z nieco innymi zestawami parametrów. Zainicjowaliśmy recenzje kodu wyłącznie w celu powstrzymania go przed robieniem więcej takich rzeczy - i aby nie wyglądać, jakbyśmy go wyróżniali, sprawdziliśmy kod każdego zespołu, więc zmarnowaliśmy około pół dnia na 4-6 ludzie każdego dnia, ponieważ my nie


2
Szczerze mówiąc, recenzowanie kodu dla wszystkich nie jest złą rzeczą. Może się wydawać, że marnujesz czas, ale chyba że wszyscy wykorzystają go jako pretekst do zwolnienia się, powinieneś uzyskać od nich cenne spostrzeżenia.
Anon.

1

Podsumowując, łatwość konserwacji można naprawdę zmierzyć tylko wtedy, gdy jest to wymagane, a nie wcześniej . Oznacza to, że można tylko stwierdzić, czy fragment kodu jest możliwy do utrzymania, kiedy trzeba go zachować.

Względnie oczywiste jest zmierzenie, jak łatwo było dostosować kawałek kodu do zmieniających się wymagań. Jest prawie niemożliwe zmierzyć z wyprzedzeniem, jak zareaguje na zmiany wymagań. Oznaczałoby to, że musisz przewidzieć zmiany wymagań. A jeśli możesz to zrobić, powinieneś dostać cenę nobla;)

Jedyne, co możesz zrobić, to uzgodnić ze swoim zespołem, na podstawie konkretnych zasad (takich jak zasady SOLID), które według wszystkich ogólnie zwiększają łatwość utrzymania.
Jeśli zasady są dobrze wybrane (myślę, że dobrym pomysłem byłoby skorzystanie z SOLID, na początek), możesz dość wyraźnie wykazać, że są łamane i pociągnąć autorów do odpowiedzialności.
Będziesz miał bardzo trudny czas, starając się promować absolutną miarę łatwości utrzymania, a jednocześnie stopniowo przekonywać swój zespół do przestrzegania ustalonego zestawu ustalonych zasad, które wydają się realistyczne.


1

ogromne kwoty długu technicznego, które tak naprawdę nigdy nie zostaną rozwiązane

Co z długiem technicznym, który jest „wyprzedzany przez wydarzenia”?

Piszę kiepski kod i pędzę go do produkcji.

Zauważysz - poprawnie - że nie da się tego utrzymać.

Kod ten jest jednak ostatnią rundą funkcji dla linii produktów, która zostanie wycofana z eksploatacji, ponieważ zmienił się kontekst prawny i linia produktów nie ma przyszłości.

„Dług techniczny” zostaje wyeliminowany przez zmianę legislacyjną, która powoduje, że wszystko staje się przestarzałe.

Wskaźnik „łatwości konserwacji” zmienił się z „zły” na „nieistotny” ze względów zewnętrznych.

Jak można to zmierzyć?


„Za sto lat wszyscy będziemy martwi i nic z tego nie będzie miało znaczenia. Wygląda z innej perspektywy, prawda?” Jeśli jest coś nieistotnego, to ta odpowiedź nie jest odpowiedzią na pytanie.
Martin Maat

0

Kolejną najlepszą rzeczą do recenzji kodów równorzędnych jest stworzenie sprawnej architektury przed kodowaniem jednostki lub produktu. Refaktor czerwono-zielony to całkiem fajny sposób. Poproś starszego mężczyznę, aby opracował sprawny interfejs i podzielił się pracą. Każdy może wziąć swój kawałek układanki i czerwono-zielony drogę do zwycięstwa. Po tym, przegląd kodu równorzędnego i refaktor byłyby w porządku. To działało całkiem nieźle na poprzednim ważnym produkcie, nad którym pracowałem.


0

Ankieta

Co powiesz na zrobienie anonimowego kwestionariusza dla programistów, który będzie wypełniany raz na miesiąc? Pytania będą wyglądać następująco:

  • Ile czasu spędziłeś w ostatnim miesiącu na projekcie X (w przybliżeniu) [0% ... 100%]
  • Jak oceniasz stan podstawy kodu pod względem łatwości konserwacji (naprawdę słaba, słaba, neutralna, dobra, dobra, naprawdę dobra).
  • Jak bardzo oceniasz bazę kodu w porównaniu ze złożonością projektu [zbyt skomplikowane, w sam raz, zbyt uproszczone].
  • Jak często czułeś się przeszkadzany w rozwiązywaniu zadań z powodu nadmiernej złożoności bazy kodu? [wcale, raz na jakiś czas, często ciągle].

(Możesz dodać dodatkowe pytania, które Twoim zdaniem byłyby przydatne w pomiarze łatwości konserwacji w komentarzach, a ja je dodam).


0

Mogę wymyślić dwa sposoby spojrzenia na łatwość konserwacji (jestem pewien, że istnieje więcej nadziei, że inni mogą wymyślić dobre definicje.

Modyfikacja bez zrozumienia.

Czy narzędzie do naprawy błędów może wejść do kodu i rozwiązać problem bez konieczności rozumienia działania całego systemu.

Można to osiągnąć, zapewniając kompleksowe testy jednostkowe (testy regresji). Powinieneś być w stanie sprawdzić, czy jakakolwiek zmiana w systemie nie zmienia sposobu, w jaki zachowuje się system, przy jakimkolwiek konkretnym dobrym wejściu.

W tej sytuacji narzędzie do naprawy błędów powinno być w stanie naprawić (prosty) błąd przy minimalnej znajomości systemu. Jeśli poprawka działa, żaden z testów regresji nie powinien zakończyć się niepowodzeniem. Jeśli jakiekolwiek testy regresji zakończą się niepowodzeniem, musisz przejść do etapu 2.

maintainabilty1 = K1 . (Code Coverage)/(Coupling of Code) * (Complexity of API)

Modyfikacja ze zrozumieniem.

Jeśli usunięcie błędu stanie się nietrywialne i musisz zrozumieć system. Jaka jest dokumentacja systemu. My nie mówimy dokumentację API zewnętrznym (są stosunkowo bezużyteczne). Musimy zrozumieć, w jaki sposób system działa w przypadku sprytnych sztuczek (czytających hacków) wykorzystywanych we wdrożeniach itp.

Ale dokumentacja to za mało, kod musi być przejrzysty i zrozumiały. Aby zmierzyć zrozumiałość kodu, możemy użyć małej sztuczki. Po tym, jak programista zakończy kodowanie, daj mu miesiąc na pracę nad czymś innym. Następnie poproś ich, aby wrócili i udokumentowali system w takim stopniu, że molo może teraz zrozumieć system. Jeśli kod jest stosunkowo łatwy do zrozumienia, powinien być szybki. Jeśli jest źle napisany, więcej czasu zajmie opracowanie tego, co zbudowali i napisanie dokumentacji.

Być może moglibyśmy wymyślić coś takiego:

maintainability2 = K2 . (Size of doc)/(Time to write doc)

0

Często stwierdzam, że rozwiązanie „najkrótszego odpowiednika” wydaje się być najłatwiejsze w utrzymaniu.

Tutaj najkrótsza oznacza najmniej operacji (nie linii). Odpowiednik oznacza, że ​​krótsze rozwiązanie nie powinno mieć gorszej złożoności czasu lub przestrzeni niż poprzednie rozwiązanie.

Oznacza to, że wszystkie logicznie podobne powtarzające się wzorce należy wyodrębnić do odpowiedniej abstrakcji: Podobne bloki kodu? Wyodrębnij go do działania. Zmienne, które wydają się występować razem? Wyodrębnij je do struktury / klasy. Klasy, których członkowie różnią się tylko rodzajem? Potrzebujesz ogólny. Wygląda na to, że w wielu miejscach przeliczyłeś to samo? Oblicz na początku i zapisz wartość w zmiennej. Spowoduje to skrócenie kodu. Zasadniczo taka jest zasada OSUSZANIA.

Możemy również zgodzić się, że nieużywane abstrakcje powinny zostać usunięte: klasy, funkcje, które nie są już potrzebne, są martwym kodem, więc należy je usunąć. Kontrola wersji zapamięta, czy kiedykolwiek będziemy musieli ją przywrócić.

Często dyskutowane są abstrakcje, do których odwołuje się tylko jeden raz: funkcje bez oddzwaniania, które są wywoływane tylko raz, bez powodu, aby być wywoływanym więcej niż raz. Generyczny, który jest tworzony przy użyciu tylko jednego typu i nie ma powodu, aby kiedykolwiek był tworzony przy użyciu innego typu. Interfejsy, które są zaimplementowane tylko raz i nie ma żadnego rzeczywistego powodu, że byłby kiedykolwiek implementowany przez jakąkolwiek inną klasę i tak dalej. Moim zdaniem te rzeczy są niepotrzebne i powinny zostać usunięte, to w zasadzie zasada YAGNI.

Powinno być więc narzędzie wykrywające powtórzenia kodu, ale myślę, że problem ten jest podobny do znalezienia optymalnej kompresji, która jest problemem złożoności Kołmogorowa, który jest nierozstrzygalny. Ale z drugiej strony niewykorzystane i słabo wykorzystane abstrakcje są łatwe do wykrycia na podstawie liczby referencji: sprawdzenie tego można zautomatyzować.


0

Wszystko to jest subiektywne i wszelkie pomiary oparte na samym kodzie są ostatecznie nieistotne. Ostatecznie wszystko sprowadza się do twojej zdolności do sprostania wymaganiom. Czy nadal możesz dostarczyć żądane funkcje, a jeśli tak, to jak często powrócą do Ciebie, ponieważ coś jeszcze nie jest w porządku i jak poważne są te problemy?

Właśnie (ponownie) zdefiniowałem łatwość konserwacji, ale nadal jest subiektywna. Z drugiej strony może to nie mieć większego znaczenia. Musimy po prostu zadowolić naszego klienta i cieszyć się nim, do tego właśnie dążymy.

Najwyraźniej czujesz, że musisz udowodnić swojemu szefowi lub współpracownikom, że należy coś zrobić, aby poprawić stan bazy kodu. Twierdzę, że wystarczy, aby powiedzieć, że jesteś sfrustrowany faktem, że za każdą drobną rzeczą, którą musisz zmienić lub dodać, musisz naprawić lub rozwiązać 10 innych problemów, których można było uniknąć. Następnie nazwij znany obszar i zrób skrzynkę, aby odwrócić go do góry nogami. Jeśli to nie zwiększy poparcia w twoim zespole, możesz być lepiej gdzie indziej. Jeśli ludzi wokół ciebie to nie obchodzi, udowodnienie, że nie masz zamiaru zmienić zdania.

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.