Jakie popularne „najlepsze praktyki” nie zawsze są najlepsze i dlaczego? [Zamknięte]


100

„Najlepsze praktyki” są wszędzie w naszej branży. Wyszukiwania Google na „Kodowanie najlepszych praktyk” pojawia się prawie 1,5 miliona wyników. Pomysł wydaje się przynosić komfort wielu; postępuj zgodnie z instrukcjami, a wszystko się ułoży.

Kiedy czytam o najlepszych praktykach - na przykład ostatnio czytałem kilka z Clean Code - denerwuję się. Czy to oznacza, że zawsze powinienem stosować tę praktykę? Czy są jakieś warunki? Czy są sytuacje, w których może to nie być dobrą praktyką? Skąd mam wiedzieć, dopóki nie dowiem się więcej o problemie?

Kilka praktyk wymienionych w Clean Code nie zgadzało się ze mną, ale szczerze mówiąc, nie jestem pewien, czy to dlatego, że są potencjalnie złe, czy to tylko moja osobista uprzedzenie. Wiem, że wielu wybitnych ludzi w branży technologicznej wydaje się myśleć, że nie ma najlepszych praktyk , więc przynajmniej moje dokuczliwe wątpliwości umiejscawiają mnie w dobrym towarzystwie.

Liczba najlepszych praktyk, o których czytałem, jest po prostu zbyt duża, by je tutaj wymienić lub zadać indywidualne pytania, dlatego chciałbym sformułować to jako ogólne pytanie:

Które praktyki kodowania, które są powszechnie określane jako „najlepsze praktyki”, mogą być nieoptymalne, a nawet szkodliwe w pewnych okolicznościach? Jakie są te okoliczności i dlaczego sprawiają, że praktyka jest kiepska?

Wolałbym usłyszeć o konkretnych przykładach i doświadczeniach.


8
Z jakimi praktykami się nie zgadzasz ?, po prostu ciekawy.
Sergio Acosta

Każdy może napisać książkę i nie muszę się z nią zgadzać - to takie proste.
Job

Jedną z rzeczy, które lubię w książce „Code Complete” Steve'a McConnella, jest to, że popiera wszystkie swoje wskazówki twardymi dowodami i badaniami. Tylko
mówię

5
@Walter: Jest otwarty od miesięcy, jest zdecydowanie konstruktywny, dlaczego go zamknąć?
Orbling

2
Biorąc pod uwagę, jak wymieniono tu moje imię, przypuszczam, że powinienem się wtrącić: uważam, że odpowiedzi tutaj są cenne, ale pytanie można przełożyć na coś zdecydowanie mniej podobnego do ankiety bez unieważnienia żadnej z odpowiedzi. Przykładowy tytuł: „Które popularne„ najlepsze praktyki ”mogą czasem być szkodliwe i kiedy / dlaczego?”
Aaronaught

Odpowiedzi:


125

Myślę, że trafiłeś w sedno tym stwierdzeniem

Nienawidzę brać rzeczy za dobrą monetę i nie myśleć o nich krytycznie

Ignoruję prawie wszystkie najlepsze praktyki, gdy nie ma wyjaśnienia, dlaczego istnieje

Raymond Chen najlepiej mówi w tym artykule, gdy mówi

Dobra rada ma uzasadnienie, dzięki czemu można stwierdzić, kiedy stanie się złą radą. Jeśli nie rozumiesz, dlaczego coś należy zrobić, wpadłeś w pułapkę programowania kultowego ładunku i będziesz to robić, nawet jeśli nie jest to już konieczne lub nawet staje się szkodliwe.


4
Cudowny cytat.
David Thornley,

Następny akapit cytatu Raymonda Chena prawdopodobnie opisuje notację węgierską! Większość firm, które widzę, używa go bez prawdziwego powodu, który mógłby wyjaśnić.
Craig

3
Mam jednak nadzieję, że ludzie nie traktują tego jako wymówki, by nie sprawdzać, jakie są uzasadnienia najlepszych praktyk. ;) Niestety, widziałem programistów z takim podejściem.
Vetle

3
Uzasadnienie jest dobre. Badania są lepsze.
Jon Purdy

7
Absolutnie prawda, i powiedziałem to wcześniej. Być może pierwszy standard w jakimkolwiek dokumencie „Normy” powinien brzmieć: „W celu dzielenia się wiedzą i dostarczania informacji niezbędnych do unieważnienia norm w późniejszym czasie, wszystkie normy powinny zawierać powody ich istnienia”.
Scott Whitlock

95

Równie dobrze może rzucić to w pierścień:

Premature optimization is the root of all evil.

Nie, nie jest.

Pełny cytat:

„Powinniśmy zapomnieć o małej wydajności, powiedzmy w około 97% przypadków: przedwczesna optymalizacja jest źródłem wszelkiego zła. Jednak nie powinniśmy tracić naszych możliwości w tak krytycznych 3%”.

Oznacza to, że korzystasz ze specjalnych, strategicznych ulepszeń wydajności w całym procesie projektowania. Oznacza to, że korzystasz ze struktur danych i algorytmów zgodnych z celami dotyczącymi wydajności. Oznacza to, że zdajesz sobie sprawę z rozważań projektowych mających wpływ na wydajność. Ale oznacza to również, że nie frywolna optymalizacja, gdy to zrobi, da ci niewielkie korzyści kosztem utrzymania.

Aplikacje muszą być dobrze zaprojektowane, aby nie spadały na końcu, gdy nałożysz na nie trochę obciążenia, a potem skończysz je przepisywać. Niebezpieczeństwo związane ze skróconym cytatem polega na tym, że zbyt często programiści używają go jako wymówki, aby w ogóle nie myśleć o wydajności do końca, kiedy może być za późno, aby cokolwiek z tym zrobić. Lepiej jest budować w dobrej wydajności od samego początku, pod warunkiem, że nie skupiasz się na drobiazgach.

Załóżmy, że budujesz aplikację w czasie rzeczywistym na systemie wbudowanym. Wybierasz Python jako język programowania, ponieważ „Optymalizacja przedwczesna jest źródłem wszelkiego zła”. Teraz nie mam nic przeciwko Pythonowi, ale jest to język interpretowany. Jeśli moc przetwarzania jest ograniczona, a pewna ilość pracy musi być wykonana w czasie rzeczywistym lub prawie w czasie rzeczywistym, a ty wybierasz język, który wymaga większej mocy przetwarzania niż masz, jesteś po królewsku wkręcony, ponieważ teraz muszę zacząć od nowa z dobrym językiem.


4
+1 za mocne Nie, nie jest.
Stephen

21
Ale jeśli już zauważyłeś, że jedna konkretna optymalizacja mieści się w tym krytycznym 3%, czy przedwcześnie ją optymalizujesz?
Jan

7
@Robert: Jaki jest zatem sens niezgody ze stwierdzeniem, że „przedwczesna optymalizacja jest źródłem wszelkiego zła”?
John

8
Optymalizacja projektowania na wysokim poziomie i podejmowanie decyzji technicznych, takich jak wybór języka, nigdy nie jest przedwczesne. Jednak często dopiero po ukończeniu projektu, jego nieefektywności stają się widoczne, dlatego Fred Brooks powiedział, że większość zespołów pisze wersję „wyrzuconą”, niezależnie od tego, czy zamierza. Kolejny argument za prototypowaniem.
Dominique McDonnell,

8
@Robert, cytat Knutha został przedwcześnie zoptymalizowany ...

94

Jeden zwrot na funkcję / metodę.


7
Chciałem to położyć. Uwielbiam niektóre wypowiedzi z wczesnego powrotu.
Carson Myers,

4
Absolutnie! Ludzie tworzą ciekawy program, aby uniknąć wczesnego returnwypowiedzenia. Albo głęboko zagnieżdżone struktury kontrolne, albo ciągłe kontrole. Może to naprawdę nadmuchać metodę, gdy if returnnaprawdę może uprościć ten problem.
snmcdonald

4
Jeśli potrzebujesz wielu zwrotów w funkcji (oprócz strażników), twoja funkcja jest prawdopodobnie zbyt długa.
EricSchaefer

18
Nie ma sensu mieć słowa kluczowego return, chyba że miało ono pojawiać się w wielu miejscach. Wróć wcześnie, często wracaj. Służy jedynie dalszemu uproszczeniu kodu. Jeśli ludzie rozumieją, jak działają instrukcje przerywania / kontynuowania, dlaczego walczą o powrót?
Evan Plaice,

7
Myślę, że jest to bardzo przestarzała najlepsza praktyka. Nie sądzę, że jest to nowoczesna najlepsza praktyka.
Skilldrick 17.01.11

87

Nie wymyślaj na nowo koła to powszechnie stosowany dogmat. Jego idea polega na tym, że jeśli istnieje odpowiednie rozwiązanie, użyj go zamiast tworzyć własne; oprócz oszczędności, istniejące rozwiązanie jest prawdopodobnie lepiej wdrożone (wolne od błędów, wydajne, przetestowane) niż to, co początkowo wymyślisz. Na razie w porządku.

Problem polega na tym, że rzadko istnieje 100% odpowiednie rozwiązanie. Może istnieć 80% odpowiednie rozwiązanie i prawdopodobnie jest w porządku. Ale w jaki sposób około 60% jest odpowiednie? 40%? Gdzie rysujesz linię? Jeśli nie narysujesz linii, możesz w końcu włączyć do projektu rozdętą bibliotekę, ponieważ używasz 10% jej funkcji - tylko dlatego, że chcesz uniknąć „ponownego wynalezienia koła”.

Jeśli wymyślisz koło na nowo, otrzymasz dokładnie to, czego chcesz. Dowiesz się również, jak robić koła. Uczenie się poprzez działanie nie powinno być niedoceniane. Ostatecznie niestandardowe koło może być lepsze niż standardowe koło standardowe.


3
Zdarzyło mi się to na odwrót. Zbudowałem własny komponent siatki ajax, ponieważ w tym czasie nie było takiego, który zrobiłby to, co chciałem, ale później zastąpiłem go siatkami Ext JS. Pomogło mi to od samego początku założyć, że warstwa wyświetlacza zostanie wymieniona.
Joeri Sebrechts

20
Zgoda. Gdyby nikt nie wymyślił koła na nowo, wszyscy prowadzilibyśmy nasze samochody na drewnianych oponach.
Dr Wily's Apprentice

6
Zawsze czuję się jak twój 10% przykład, gdy dodam Boost do projektu w C ++. I zawsze potrzebują mniej niż 10% jej bezpośrednio, ale oczywiście funkcje muszę importować inne moduły, które importować inne moduły, które ...
Roman Starkov

3
+1: właśnie w tym tygodniu odkryłem na nowo koło (np. Zastąpiłem rozdętą, ale popularną wtyczkę jquery, której używaliśmy, czymś, co odpowiada naszym potrzebom, ale jeszcze modułowym) i spowodowało to ogromny wzrost wydajności. Są też ludzie, których zadaniem jest dosłownie wynalezienie koła: weźmy na przykład Michelin, zajmują się badaniami i rozwojem w celu ulepszenia opon.
wildpeaks

2
@Dr. Cóż, te koła nie zostały wynalezione na nowo, zostały odnowione!

78

„Testuj wszystko”.

Słyszałem, jak często mówiono, że cały kod powinien zawierać testy jednostkowe, z czym się nie zgadzam. Jeśli masz test dla metody, wszelkie zmiany danych wyjściowych lub struktury tej metody muszą zostać wprowadzone dwukrotnie (raz w kodzie, raz w teście).

Jako takie, testy jednostkowe powinny moim zdaniem być proporcjonalne do stabilności strukturalnej kodu. Jeśli piszę system warstwowy od podstaw, moja warstwa dostępu do danych przetestuje wazoo; moja warstwa logiki biznesowej będzie dość dobrze przetestowana, moja warstwa prezentacji będzie miała kilka testów, a moje widoki będą miały niewiele lub nie będzie żadnych testów.


7
Podejrzewam, że „Unit Test Everything” stało się frazesem, podobnie jak cytat „przedwczesnej optymalizacji”. Zasadniczo zgadzam się z twoimi proporcjami i widziałem wiele przykładów deweloperów przechodzących przez monumentalny wysiłek, aby wyśmiewać obiekt warstwy aplikacji, wysiłek, który lepiej byłoby poświęcić na testowanie akceptacyjne.
Robert Harvey

36
Jeśli zmiana w strukturze metody powoduje zmianę w testach, być może testowanie jest nieprawidłowe. Testy jednostkowe nie powinny weryfikować implementacji, tylko wynik.
Adam Lear

7
@Anna Lear: Myślę, że mówił o robieniu zmian projektowych / strukturalnych (refaktoryzacja). Ponieważ projekt nie jest wystarczająco dojrzały, gdy znajdziesz lepszy sposób, możesz zmodyfikować wiele testów. Zgadzam się, że kiedy jesteś bardziej wykwalifikowanym testerem, łatwiej możesz zauważyć, gdzie test byłby złym pomysłem (z tego powodu i innych powodów), ale jeśli projekt nie jest naprawdę dojrzały, najprawdopodobniej nadal będziesz mieć kilka testów w droga.
n1ckp

13
Myślę, że właśnie dlatego pomysł „najpierw przetestuj” nie działa. Aby wykonać testy, musisz mieć odpowiedni projekt. Ale odpowiednie zaprojektowanie wymaga wypróbowania rzeczy i zobaczenia, jak działają, abyś mógł je ulepszyć. Tak więc nie możesz naprawdę wykonać testów, zanim nie będziesz mieć projektu, a jego poprawne wykonanie wymaga kodowania i sprawdzenia, jak to działa. Chyba że masz naprawdę uber-architekta, tak naprawdę nie widzę, jak ten pomysł zadziała.
n1ckp

13
@ n1ck TDD nie jest tak naprawdę ćwiczeniem testowym, ale jest ćwiczeniem projektowym. Chodzi o to, że rozwijasz swój projekt poprzez testy (ponieważ to szybko ujawnia rozsądne API dla twoich rzeczy), a nie dopasowujesz testy do istniejącego projektu (który może być zły / niewystarczający). Więc nie, nie musisz mieć prawa do projektowania, aby najpierw wykonać testy.
Adam Lear

57

Zawsze programuj do interfejsów.

Czasami będzie tylko jedna implementacja. Jeśli opóźnimy proces wyodrębniania interfejsu do czasu, gdy zauważymy jego potrzebę, często stwierdzimy, że nie jest to konieczne.


4
Po uzgodnieniu programujesz interfejs, gdy potrzebujesz interfejsu (tj. Stabilnego interfejsu API do pracy).
Robert Harvey

45
W moim czytaniu ta zasada nie dotyczy interfejsów jako konstrukcji języka. Oznacza to, że nie powinieneś przyjmować żadnych założeń dotyczących wewnętrznego działania klasy podczas wywoływania jej metod i powinieneś polegać tylko na kontraktach API.
Zsolt Török

2
Ok, oto ciekawe pytanie - jestem przede wszystkim programistą .NET, więc dla mnie moje interfejsy wyglądają jak IBusinessManager lub IServiceContract. Dla mnie jest to bardzo łatwe w nawigacji (i generalnie przechowuję moje interfejsy w innej przestrzeni nazw [lub nawet innym projekcie]). Kiedy korzystałem z Javy, to faktycznie było to mylące (generalnie implementacje interfejsu, które widziałem, mają sufiks .impl - a interfejsy nie mają rozgraniczenia). Czy może to być problem ze standardami kodu? Oczywiście interfejsy w Javie sprawiają, że kod wygląda na zagracony - na pierwszy rzut oka wyglądają dokładnie tak samo jak normalne klasy.
Watson

5
@Watson: jednym kosztem jest to, że za każdym razem, gdy wciskam F3 („skok do deklaracji”) w wywołaniu metody w Eclipse, przeskakuję do interfejsu, a nie do jednej implementacji. Następnie muszę nacisnąć klawisz Control-T, strzałkę w dół, wrócić do implementacji. Blokuje również niektóre automatyczne refaktoryzacje - na przykład nie można wprowadzić metody w definicji interfejsu.
Tom Anderson

4
@Tom: Cóż, proszę pana, chętnie bym cię zaangażował w tę wojnę, Eclipse vs. Intellij - jednak mam znakomity kodeks moralny, który uniemożliwia mi fizyczną konfrontację z kimś, kto ma oczywistą przeszkodę. BUM. Nie twierdzę, że Eclipse jest zły, mówię, że gdyby moce Osi wykorzystały go do budowy lub zaprojektowania swoich machin wojennych, II Wojna Światowa byłaby teraz znana jako „dwudniowa kerfufa”. Poważnie, okazało się, że brakuje mu trochę polskiego, co dostaję w gotowych IDE (Intellij / VS + ReSharper). Przekonałem się, że walczę z nią więcej niż jeden raz - co jest o jeden za dużo.
Watson

46

Nie używaj żadnych programów typu open source (lub innych firm niż Microsoft dla programistów .NET)

Jeśli Microsoft go nie opracował - nie używamy go tutaj. Chcesz użyć ORM - EF, chcesz użyć IOC - Unity, chcesz się zalogować - blok aplikacji do rejestrowania w przedsiębiorstwie. Istnieje wiele lepszych bibliotek - a jednak zawsze utknąłem przy zamówieniach z menu dolara świata programistów. Przysięgam, że za każdym razem, gdy słyszę najlepsze praktyki firmy Microsoft, myślę „Wytyczne żywieniowe McDonalda”. Pewnie, będziesz żył, jeśli będziesz ich przestrzegać, ale będziesz także niedożywiony i z nadwagą.

  • Pamiętaj, że to może nie być twoja najlepsza praktyka, ale jest to powszechna praktyka stosowana niemal wszędzie, gdzie pracowałem.

13
Brzmi okropnie ... = (Prawdopodobnie jestem po drugiej stronie, jednak
unikam

To nie powinno tak być. Bibliotekę należy wybrać ze względu na jej wartość, nie tylko biorąc pod uwagę, kto ją stworzył. Na przykład uwielbiam EF, ale miałem złe doświadczenia z Enterprise Library i znalazłem lepsze narzędzia do sprawdzania poprawności i rejestrowania, takie jak FluentValidation, log4net i Elmah.
Matteo Mosca

4
Nie zostaniesz zwolniony za zakup IBM ^ wMicrosoft
Christopher Mahan

17
Istnieje również wersja lustrzanego obrazu, tzn. Nigdy nie używaj niczego Microsoft ani nigdy nie używaj niczego, za co musisz zapłacić.
Richard Gadsden

5
Mam szczęście pracować w organizacji, w której nie jest to szeroko rozpowszechniony dogmat, ale w miejscach, w których przyjęliśmy rozwiązania komercyjne, na pewno jest dużo bólu. Problem pojawia się, gdy jakaś część komercyjnego rozwiązania nie do końca działa. Gdy jest to oprogramowanie typu open source, możesz spojrzeć na źródło (dokumentacja ostateczna) i dowiedzieć się, co się dzieje. W zamkniętym źródle musisz zapłacić za przywilej dostępu do wiedzy pomocy technicznej, która jeszcze mniej wie o twoim produkcie. I to jedyna dostępna „poprawka”.
SingleNegationElimination

40

Orientacja obiektowa

Istnieje założenie, ponieważ kod jest „obiektowy”, jest magicznie dobry. Ludzie dzielą funkcjonalność na klasy i metody, aby być zorientowanym obiektowo.


7
Nie wyobrażam sobie zbudowania systemu oprogramowania o znacznej wielkości bez korzystania z organizacji zapewnianej przez Object Orientation.
Robert Harvey

18
Robert. Uniks nie jest zorientowany obiektowo i z pewnością kwalifikuje się jako system oprogramowania o znacznych rozmiarach. Wydaje się również być dość popularny (pomyśl Mac OSX, iPhone, telefony z Androidem itp.)
Christopher Mahan

7
Miałem na myśli to, że uważam, że powinniśmy zastosować najbardziej odpowiednią metodologię. Widziałem ludzi, którzy używają metod i klas, w których jest to uciążliwe i nie ma większego sensu, tylko dlatego, że „jest zorientowane obiektowo”. To kult ładunku.
LennyProgrammers

8
Nie ma srebrnej kuli. Programowanie funkcjonalne (Haskell) jest całkiem udane bez zorientowania obiektowego. Na koniec dnia masz wiele narzędzi i Twoim zadaniem jest wybrać najlepszy asortyment do danego zadania.
Matthieu M.,

9
Zabawne jest to, że oprócz używania klas, polimorfizmu i podobnych elementów, większość kodu obiektowego to tak naprawdę kod proceduralny.
Oliver Weiler

35

Cały kod należy skomentować.

Nie powinno tak być. Kiedyś masz oczywisty kod, na przykład seterów nie należy komentować, dopóki nie zrobią czegoś specjalnego. Ponadto, dlaczego powinienem to komentować:

/** hey you, if didn't get, it's logger. */
private static Logger logger = LoggerFactory.getLogger(MyClass.class);

13
Cały kod powinien być zrozumiały . Komentarze są w tym ważnym narzędziem, ale dalekim od jedynego.
Trevel

Oczywiście, kod powinien być zrozumiały. Ale nie ma jednego powodu, aby napisać komentarz, który nie doda niczego do, na przykład, nazwy metody. Jeśli piszesz, /** sets rank. */ void setRank(int rank) { this.rank = rank; }uważam ten komentarz za głupi. Dlaczego jest napisane?
Vladimir Ivanov

2
Wygenerowana dokumentacja. Do tego /** */służy format zamiast /* */komentarza do formatu. Lub dla .NET byłoby///
Berin Loritsch,

10
Korzystanie }//end if, }//end for, }//end whilesą najlepszym przykładem marnotrawienia komentując jakie kiedykolwiek spotkałem. Widziałem to wiele razy, gdy nawias otwierający znajduje się nie więcej niż 2 linie powyżej. IMHO, jeśli potrzebujesz tych komentarzy, Twój kod wymaga ponownego faktorowania ... lub musisz kucnąć 20 USD i kupić edytor IDE / Text, który wyróżnia pasujące nawiasy klamrowe.
scunliffe

7
Kod mówi „jak”. Komentarze muszą zawierać „dlaczego”.

32

Metodologie, szczególnie scrum. Nie mogę zachować prostej twarzy, gdy słyszę, że dorośli używają frazy „Scrum Master”. Jestem tak zmęczony słyszeniem protestów programistów, że jakiś aspekt Metodologii X nie działa w ich firmie, ale Guru So-and-So informuje go, że powodem, dla którego nie działa, jest fakt, że nie są oni prawdziwymi praktykami Metodologii X. „Scrum mocniej, musisz, mój uczeń Padawan!”

W zwinnych metodologiach są bryłki mądrości --- wiele z nich --- ale często są one osadzone w takiej ilości nawozu, że nie mogę walczyć z odruchem wymiotnym. Weź to ze strony scrum Wikipedii :

Wiele ról jest zdefiniowanych w Scrumie. Wszystkie role dzielą się na dwie odrębne grupy - świnie i kury - w zależności od charakteru ich zaangażowania w proces rozwoju.

Naprawdę? Świnie i kurczaki, mówisz? Fascynujący! Nie mogę się doczekać, aby przekazać ten mój szefowi ...


Ciekawy. Zgadzam się do pewnego stopnia. Ale z tą ostatnią częścią: nazywaj ich jak chcesz, to mnemoniki, to wszystko.
Steven Evers

12
+1 ... masz rację, trudno brać to na poważnie. <wielki buczący głos> * JESTEM ZWALCOWĄ * </voice>
GrandmasterB

2
I przypowieści. Przypomina mi kazania kościelne lub rodzaje anegdot, z których słyną guru samopomocy (i komicy): „Weź mojego przyjaciela Steve'a. Steve nieustannie kłócił się z żoną Sheryl. Ci dwaj chodzili godzinami, aby moment, w którym ich małżeństwo było naprawdę zagrożone. Pewnego dnia… „Tego rodzaju przędza dydaktyczna nie przeszkadza mi w innych dziedzinach, ale nienawidzę, gdy rozmnażają się w naukach technicznych.
evadeflow,

2
Co z Scrum Ninja?
Berin Loritsch,

1
Nie zgadzam się z porównaniem „Świnia i kurczak” ... leci wprost w stronę Agile Manifesto. Mianowicie „Współpraca z klientami w zakresie negocjacji umów”. Klienci są tak samo zaufani (jeśli nie więcej) w sukcesie projektu, jak zespół projektowy. Nazywanie niektórych ról świniami i innymi rolami kurczaków ustanawia mentalność „my kontra je”, że IMHO jest największą przeszkodą dla udanych projektów.
Michael Brown

25

Object Relational Mapping ... http://en.wikipedia.org/wiki/Object-relational_mapping

Nie chcę nigdy abstrahować od moich danych, ani nie chcę stracić tej precyzyjnej kontroli i optymalizacji. Moje doświadczenie z tymi systemami było bardzo słabe ... Zapytania generowane przez te warstwy abstrakcji są jeszcze gorsze niż to, co widziałem podczas offshoringu.


19
Przedwczesna optymalizacja jest źródłem wszelkiego zła. Wolny kod jest w rzeczywistości niezwykle rzadko problemem w porównaniu do kodu niemożliwego do utrzymania. Użyj ORM, a następnie przecinaj abstrakcję tylko tam, gdzie jej potrzebujesz.
Fishtoaster

28
ORM to narzędzie 80-20. Są przeznaczone do obsługi 80% CRUD, który staje się tak męczący, aby pisać cały ten niekończący się kod hydrauliczny po pewnym czasie. Pozostałe 20% można wykonać na bardziej „konwencjonalne” sposoby, takie jak stosowanie procedur przechowywanych i pisanie zwykłych zapytań SQL.
Robert Harvey

18
@ Fishtoaster: Czy nie masz na myśli: „Powinniśmy zapomnieć o małej wydajności, powiedzmy w około 97% przypadków: przedwczesna optymalizacja jest źródłem wszelkiego zła. Jednak nie powinniśmy tracić naszych możliwości w tak krytycznych 3%.”?
Robert Harvey

5
@Robert Harcey: Jest powód, dla którego nie użyłem bezpośredniego cytatu. Myślę, że większość programistów zbytnio koncentruje się na wydajności - to problem, który niewielu z nich naprawdę musi rozwiązać. Trzeba przyznać, że istnieją pewne dziedziny, w których jest to ważniejsze niż inne, ale łatwość konserwacji i rozszerzalność stanowią problem wszędzie. Kolejny zmodyfikowany cytat: „Spraw, by działał, spraw, by był łatwy w utrzymaniu, uczyń go czytelnym, spraw, by był rozszerzalny, spraw, by był testowalny, a następnie , jeśli masz czas i okaże się, że potrzebujesz go, spraw, by był szybki”.
Fishtoaster

12
@Craig: Jak nie rozpoznałeś ironii w swoim oświadczeniu? Potrzeba roku, aby nauczyć się, jak uzyskać dobrą wydajność z ORM, jest doskonałym argumentem przeciwko ORM, podobnie jak potrzeba „kontrolowania” SQL i wstrzykiwania przechowywanych procedur. Jeśli masz na to wiedzę, możesz całkowicie ominąć ORM.
Nicholas Knight

22

Pisanie nazw funkcji tak, jakby były angielskimi zdaniami:

Draw_Foo()
Write_Foo()
Create_Foo()

itp. Może to wyglądać świetnie, ale nauka interfejsu API jest uciążliwa. O ile łatwiej jest wyszukać indeks „Wszystko, co zaczyna się od Foo”?

Foo_Draw()
Foo_Write()
Foo_Create()

itp.


2
Prawdopodobnie tak proste, jak wpisanie Foo na liście funkcji TM.
Josh K

68
Wygląda na to, że tak naprawdę byś chciał Foo.Draw(), Foo.Write()i Foo.Create()żebyś mógł zrobić Foo.methods.sortlubFoo.methods.grep([what I seek]).sort
Inaimathi

7
Rozpoczęcie od „Get” to kolejny przykład.
JeffO

1
Pochodzę ze świata celu-c i bardzo tęsknię za pełnymi nazwami metod i zapisem notacji, kiedy robię java (moje drugie życie). Odkąd zaczęło działać uzupełnianie kodu, nie znalazłem też dodatkowego problemu z pisaniem.

2
@Scott Whitlock: Nie jest to nieaktualne dla niektórych programistów .NET, iirc, VS 2008 tego nie zrobiło. 2010 tak jest i jest fantastyczny.
Steven Evers,

22

MVC - często stwierdzam, że przy wielu problemach z projektowaniem stron internetowych w podejściu MVC chodzi bardziej o to, aby uczynić ramę (szyny itp.) Szczęśliwymi niż o prostotę lub strukturę. MVC jest ulubieńcem „astronautów architektury”, którzy wydają się cenić nadmierne rusztowania nad prostotą. ymmv.

oparty na klasach OO - moim zdaniem sprzyja złożonym strukturom stanu zmiennego. jedynymi przekonującymi przypadkami, które znalazłem na przestrzeni lat w oparciu o klasy OO, są banalne przykłady „kształt-> prostokąt-> kwadrat”, które tworzą rozdział 1 dowolnej książki OO


4
Zajmuję się tworzeniem stron internetowych w ASP.NET i ASP.NET MVC i chociaż MVC wydaje się scaffoldy, zdecydowanie wolę go od ASP.NET z wielu powodów: prostoty, łatwości konserwacji i wyjątkowo dokładnej kontroli nad znacznikami. Wszystko ma swoje miejsce i choć wszystko wydaje się nieco powtarzalne, utrzymanie go jest przyjemnością. Jest całkowicie konfigurowalny, więc jeśli nie podoba ci się zachowanie po wyjęciu z pudełka, możesz go zmienić.
Robert Harvey

1
Jeśli chodzi o OO, istnieją dobre i złe sposoby na zrobienie tego. Dziedzictwo jest przereklamowane i używane bardziej oszczędnie w prawdziwym świecie, niż większość książek chciałaby; obecnie istnieje trend w kierunku bardziej funkcjonalnego, niezmiennego stylu rozwoju, nawet w świecie OO.
Robert Harvey

1
+1 za wzmiankę o MVC. Chociaż koncepcja MVC (oddzielanie logiki warstwy danych, logiki prezentacji i logiki tła jest dobrym pomysłem), fizyczne rozdzielenie ich na złożoną hierarchię folderów z pomieszaniem plików zawierających fragmenty kodu jest głupie. Winię za to całe zjawisko brak obsługi przestrzeni nazw w PHP, a nowi programiści gloryfikujący dziesięciolecia techniki jako „najnowszą rzecz”. To proste, stwórz przestrzeń nazw dla akcesorów bazy danych, GUI i logiki w tle (i podprzestrzeni w razie potrzeby).
Evan Plaice,

3
Jeśli chodzi o OO, tak naprawdę nie zobaczysz korzyści, dopóki projekt nie osiągnie rozmiarów, w których zarządzanie złożonością staje się ważne. W miarę możliwości przestrzegaj zasady pojedynczej odpowiedzialności, a jeśli twój kod jest publicznie dostępny (np. Dla .dll), ukryj wewnętrzną implementację klas / metod / właściwości tam, gdzie to możliwe, aby zwiększyć bezpieczeństwo kodu i uprościć interfejs API.
Evan Plaice,

1
Osobiście uważam, że kształt-> prostokąt-> kwadrat jest jednym z najbardziej eleganckich argumentów przeciwko oop. na przykład Square(10).Draw()wystarczy Rectangle(10, 10).Draw(). więc myślę, że to oznacza, że ​​kwadrat jest podklasą prostokąta. Ale mySquare.setWidthHeight(5,10)to nonsens (IE, nie spełnia zasady podstawienia Liskowa), kwadrat nie może mieć różnej wysokości i szerokości, chociaż prostokąt może, więc implikuje, że prostokąt jest podklasą kwadratu. Jest to znane w innych kontekstach jako „problem z
kołem, elipsą

22

YAGNI

( Nie będziesz go potrzebował )

To podejście kosztowało mnie wiele godzin, kiedy musiałem zaimplementować funkcje w istniejącej bazie kodu, gdzie staranne planowanie obejmowałoby te funkcje wcześniej.

Moje pomysły były często odrzucane z powodu YAGNI i przez większość czasu ktoś musiał później zapłacić za tę decyzję.

(Oczywiście można argumentować, że dobrze zaprojektowana baza kodu pozwoli również na dodanie funkcji w późniejszym czasie, ale rzeczywistość jest inna)


15
Zgadzam się z YAGNI, ale widzę, o co ci chodzi. Celem YAGNI jest zajmowanie się ludźmi, którzy chcą wszystko zaplanować od początku do najmniejszego szczegółu. Dziewięć razy na dziesięć jest wykorzystywana jako wymówka dla kodu inżyniera lub całkowitego pominięcia planowania.
Jason Baker

12
P.Floyd, @Jason Baker: +1 Absolutnie racja. Stare powiedzenie obowiązuje tutaj: „miesiące w laboratorium mogą zaoszczędzić godziny w bibliotece”
Steven Evers,

Specyfikacja często pozostawia (i najczęściej powinna) większość implementacji, a część interfejsu jest otwarta. wszystko, co nie jest bezpośrednio w specyfikacji, ale jest wymagane w celu implementacji specyfikacji, niezależnie od tego, czy decyzja implementacyjna, interfejs widoczny dla użytkownika, czy cokolwiek innego, jest również pośrednim wymogiem specyfikacji. Jeśli funkcja nie znajduje się w specyfikacji i nie jest sugerowana przez specyfikację, to jej nie potrzebujesz. Jak to może być mylące?
SingleNegationElimination

1
@TokenMacGuy kluczowym aspektem jest dorozumiana część specyfikacji . Tam opinie są bardzo różne.
Sean Patrick Floyd

20

Dla SQL

  1. Nie używaj wyzwalaczy
  2. Zawsze chowaj tabele za widokami

W porządku:

  1. Są funkcją, która ma swoje miejsce. Masz wiele ścieżek aktualizacji do tabeli lub potrzebujesz 100% kontroli?

  2. Dlaczego? Zrobiłbym to, gdybym refaktoryzował się, aby utrzymać kontrakt, ale nie wtedy, gdy czytam, że ludzie zmieniają widok, aby pasował do wszelkich zmian na stole

Edytować:

Numer 3: Unikanie * z ISTNIENIEM. Spróbuj 1/0. To działa. Lista kolumn nie jest oceniana zgodnie ze standardem SQL. Str. 191


3
# 2 to najlepsza praktyka?
Hogan


1
@Hogan: Widok, który po prostu odzwierciedla tabelę podstawową, nie zapewnia żadnych zabezpieczeń przed bezpośrednim użyciem tabeli podstawowej. Jeśli dołączysz do tabeli bezpieczeństwa użytkownika lub zamaskujesz niektóre kolumny, to wystarczy. Ale wybierz każdą kolumnę z tabeli lub widoku: bez różnicy. Osobiście i tak używam przechowywanych proc.
gbn

3
@Hogan: Wiem coś o SQL Server :-) stackoverflow.com/users/27535/gbn Mam na myśli, że GRANT SELECT na stole nie różni się od GRANT SELECT ON VIEW, jeśli widok jest SELECT * FROM TABLE
gbn

1
@gbn: Zgadzam się. Nie ma tam różnicy. Myślę, że możemy mówić to samo. Wydaje mi się, że mój oryginalny komentarz („# 2 to najlepsza praktyka?”) Opierał się bardziej na moim osobistym doświadczeniu, że widoki (jak wyzwalacze) są częściej pomijane niż poprawnie używane. Tak więc taka najlepsza praktyka prowadziłaby jedynie do nadużycia, a nie poprawy. Jeśli jest to uważane za najlepszą praktykę, masz 100% racji, jest złe.
Hogan

20

Wzory projektowe głównie. Są nadmiernie wykorzystywane i niedostatecznie wykorzystywane.


13
+1 Nadal nie widzę, w jaki sposób Wzory projektowe są pięknymi lub eleganckimi rozwiązaniami. Są obejściem braków językowych, niczym więcej.
Oliver Weiler

2
Po prostu postrzegaj to jako próbę wyeliminowania zapachu języka za pomocą samego języka.
Filip Dupanović 18.01.11

15

Zasada jednolitej odpowiedzialności

(„każda klasa powinna mieć tylko jedną odpowiedzialność; innymi słowy, każda klasa powinna mieć jeden i tylko jeden powód do zmiany”)

Nie zgadzam się. Myślę, że metoda powinna mieć tylko jeden powód do zmiany, a wszystkie metody w klasie powinny mieć logiczny związek ze sobą , ale sama klasa może faktycznie robić kilka (powiązanych) rzeczy.

Z mojego doświadczenia wynika, że ​​ta zasada zbyt często stosuje się zbyt gorliwie, co kończy się wieloma drobnymi klasami opartymi na jednej metodzie. Zrobiły to oba zwinne sklepy, w których pracowałem.

Wyobraź sobie, że twórcy interfejsu API .Net mieli taką mentalność: zamiast List.Sort (), List.Reverse (), List.Find () itp. Mielibyśmy klasy ListSorter, ListReverser i ListSearcher!

Zamiast sprzeczać się już z SRP (co samo w sobie nie jest okropne) , podzielę się kilkoma moimi odwiecznymi anegdotycznymi doświadczeniami:


W jednym miejscu, w którym pracowałem, napisałem bardzo prosty solver o maksymalnym przepływie, który składał się z pięciu klas: węzła, wykresu, kreatora grafów, solvera grafów i klasy do używania kreatora grafów / solverów do rozwiązywania problem w świecie rzeczywistym. Żadna z nich nie była szczególnie złożona ani długa (solver był zdecydowanie najdłuższy przy ~ 150 liniach). Zdecydowano jednak, że klasy mają zbyt wiele „obowiązków”, więc moi współpracownicy przystąpili do refaktoryzacji kodu. Kiedy skończyli, moje 5 klas zostało poszerzonych do 25 klas, których łączna liczba linii kodu była ponad trzykrotnie większa niż pierwotnie. Przepływ kodu nie był już oczywisty, podobnie jak cel nowych testów jednostkowych; Trudno mi było zrozumieć, co zrobił mój własny kod.


W tym samym miejscu prawie każda klasa miała tylko jedną metodę (jej jedyna „odpowiedzialność”). Postępowanie w ramach programu było prawie niemożliwe, a większość testów jednostkowych polegała na testowaniu tej klasy kodu z innej klasy , których oba cele były dla mnie równie tajemnicą. Były dosłownie setki klas, w których powinno być (IMO) tylko kilkadziesiąt. Każda klasa zrobiła tylko jedną „rzecz” , ale nawet przy konwencjach nazewnictwa, takich jak „AdminUserCreationAttemptorFactory” , trudno było określić związek między klasami.


W innym miejscu (które miało również mentalność klas, które powinny mieć tylko jedną metodę ), próbowaliśmy zoptymalizować metodę, która zajęła 95% czasu podczas pewnej operacji. Po (raczej głupiej) optymalizacji, zwróciłem uwagę na to, dlaczego nazywano to bajillion razy. Został wywołany w pętli w klasie ... której metoda została wywołana w pętli w innej klasie .. która również została wywołana w pętli ..

W sumie pięć poziomów pętli rozłożonych na 13 klas (poważnie). To, co właściwie robiła jedna klasa, było niemożliwe do ustalenia na podstawie samego jej spojrzenia - trzeba było naszkicować mentalny wykres tego, jakie metody wywołał i jakie metody te metody wywołały i tak dalej. Gdyby wszystko zostało połączone w jedną metodę, miałby tylko około 70 linii długości, a nasza metoda problemowa byłaby osadzona w pięciu natychmiast oczywistych poziomach pętli.

Moja prośba o przekształcenie tych 13 klas w jedną klasę została odrzucona.


6
Wygląda na to, że ktoś dostał „gorączkę wzorcową” lub w tym przypadku „gorączkę podstawową” przy tym zadaniu. Klasa listy nie narusza SRP. Wszystkie jego funkcje służą jednemu celowi - manipulowaniu kolekcją obiektów. Posiadanie tylko jednej funkcji w klasie wydaje mi się przesadą. Zasada SRP polega na tym, że jednostka kodu (metoda, klasa lub biblioteka) powinna ponosić jedną odpowiedzialność, którą można jednoznacznie stwierdzić.
Michael Brown

3
Zacząłem dostrzegać tego rodzaju szaleństwo od ludzi, którzy nie mogą napisać czystego, funkcjonalnego kodu. Zbyt dużo edukacji, że każdy problem na świecie można rozwiązać z książki wzorów. Za mało myśli o pragmatyzmie. Tak jak ty widziałem oparty na klasach kod OO, który jest tak okropny, że podążanie za nim jest całkowicie niemożliwe. I jest ogromny i wzdęty.
szybko_now

3
Drugi komentarz tutaj. Wiele „zasad” jest nadmiernie stosowanych. Jest wiele rzeczy, które są dobrymi pomysłami, w których czasami robi się dokładnie odwrotnie. DOBRE programiści wiedzą, kiedy łamią zasady. Ponieważ reguły nie są „regułami”, są one stwierdzeniami „dobrej praktyki przez większość czasu, chyba że jest to naprawdę głupi pomysł”.
szybko_now

„Wyobraź sobie, że twórcy interfejsu API .Net mieliby taką mentalność: zamiast List.Sort (), List.Reverse (), List.Find () itp. Mielibyśmy klasy ListSorter, ListReverser i ListSearcher ! ”. Właśnie to robi się w C ++ i jest cudowne . Algorytmy są oddzielone od struktur danych, więc jeśli napiszę własny kontener, wszystkie algorytmy, które działają ze standardową biblioteką, po prostu działają z moim nowym kontenerem. Na ziemi .Net musi być okropnie, pisząc nową funkcję sortowania dla każdego nowego kontenera, który chcesz posortować.
Mankarse

14

Teraz, gdy wspomniałeś o Czystym Kodzie, choć zawiera on kilka dobrych pomysłów, myślę, że jego obsesja polegająca na przekształceniu wszystkich metod w metody podrzędne, a także w metody podrzędne, jest zbyt daleko posunięta. Zamiast kilku dziesięcioliniowych metod powinieneś preferować dwadzieścia (podobno dobrze nazwanych) jedno-liniowych. Oczywiście ktoś myśli, że jest czysty, ale dla mnie wydaje się znacznie gorszy niż oryginalna wersja.

Ponadto, zastępując proste elementarne rzeczy, takie jak

0 == memberArray.length

w klasie z wywołaniem własnej metody klasy, takiej jak

isEmpty()

jest wątpliwym „ulepszeniem” IMHO. Dodatek: Różnica polega na tym, że pierwsze sprawdzenie wykonuje dokładnie to, co mówi: sprawdza, czy długość tablicy wynosi 0. Ok, isEmpty()może również sprawdzić długość tablicy. Ale można to również zaimplementować w następujący sposób:

return null != memberArray ? 0 == memberArray.length : true;

Oznacza to, że zawiera ukrytą kontrolę zerową! Może to być dobre zachowanie w przypadku metody publicznej - jeśli tablica jest pusta, to z pewnością coś jest puste - ale kiedy mówimy o wewnętrznych elementach klasy, nie jest tak dobrze. Podczas gdy hermetyzacja na zewnątrz jest koniecznością, elementy wewnętrzne klasy muszą dokładnie wiedzieć, co się dzieje w klasie. Nie można hermetyzować klasy od siebie samej . Jawne jest lepsze niż niejawne.


Nie oznacza to, że przełamywanie długich metod lub logiczne porównania nie są dobre; Oczywiście, że tak, ale w jakim stopniu to zrobić - tam, gdzie jest to najsłodsze miejsce - jest oczywiście kwestią gustu. Złamanie długiej metody skutkuje powstaniem większej liczby metod, co nie przychodzi za darmo. Musisz skakać po kodzie źródłowym, aby zobaczyć, co się naprawdę dzieje, kiedy możesz to zobaczyć na pierwszy rzut oka, jeśli wszystkie te rzeczy są w jednej metodzie.

Chciałbym nawet posunąć się nawet do stwierdzenia, że ​​w niektórych przypadkach metoda 1-liniowa jest zbyt krótka, aby zasłużyć na bycie metodą.


6
Rzadko postrzegam to jako problem. Głównie dlatego, że zwykle widzę za dużo w jednej metodzie, a nie za mało. Jednak według niektórych badań bardzo niska złożoność metod ma również nieco wyższy wskaźnik błędów niż średnio niska złożoność. enerjy.com/blog/?p=198
MIA

Tak, to zdecydowanie problem tylko w Clean Code. Jak powiedzieliście, w rzeczywistości metody są zbyt długie. Ale ciekawie jest zobaczyć tę krzywą! Rzeczywiście, rzeczy powinny być jak najprostsze, ale nie prostsze.
Joonas Pulakka

1
Uważam, że twój drugi przykład jest znacznie bardziej czytelny, a ta forma (lub coś podobnego, jak właściwość Length w samej klasie) jest koniecznością, jeśli podajesz go do wiadomości publicznej.
Robert Harvey

@Robert Harvey: Drugi przykład jest dobrą metodą publiczną, ale wywołanie jej z poziomu samej klasy jest wątpliwe, ponieważ nie wiesz dokładnie, co robi, zanim spojrzysz na to, jak jest zaimplementowana. Może na przykład sprawdzić wartość null. Zobacz mój dodatek powyżej.
Joonas Pulakka

@Joonas: Wystarczająco uczciwy.
Robert Harvey

13

„Bądź liberalny dzięki komentarzom”

Komentarze są zdecydowanie dobre, ale zbyt wiele jest tak samo złych, jeśli nie gorszych niż niewystarczające. Dlaczego? Cóż, ludzie zwykle ignorują komentarze, jeśli widzą zbyt wiele niepotrzebnych. Nie twierdzę, że możesz mieć doskonale samodokumentujący się kod, ale lepiej jest kod, który wymaga komentarza do wyjaśnienia.


1
kod samo-dokumentujący jest zdecydowanie fajny. Chociaż lubię mieć obok komentarze takie jak proste obliczenia (aby wyrazić, jaki jest typ zwracanej lub zwracanej wartości). Jeśli jednak twoje komentarze wymagają więcej słów niż sam kod, prawdopodobnie czas przepisać kod.
sova

6
Muszę zgodzić się ze sposobem, w jaki sova to ujęła. Czysty kod jest lepszy od komentarzy.
riwalk

4
Nadal potrzebujesz „dlaczego” tam jest!

Wolę komentarze wyjaśniające dlaczego. Oznacza to, że muszę mniej MYŚLEĆ w inżynierii odwrotnej zamiarów kodu, kiedy przyjrzę się temu.
szybko_nie

12

GoTo uważany za szkodliwy

Jeśli implementujesz maszynę stanową, instrukcja GOTO może mieć większy sens (czytelność i efektywny kod) niż podejście „programowania strukturalnego”. Naprawdę martwiło to niektórych współpracowników, gdy pierwszy fragment kodu, który napisałem w nowej pracy, zawierał nie tylko jedną, ale kilka instrukcji goto. Na szczęście byli wystarczająco inteligentni, aby zdać sobie sprawę, że w tym konkretnym przypadku było to najlepsze rozwiązanie.

Każda „najlepsza praktyka”, która nie dopuszcza rozsądnych i udokumentowanych wyjątków od jej zasad, jest po prostu przerażająca.


16
Zajmuję się programowaniem przez dziewięć lat bez jednego polecenia goto (w tym kilku automatów stanów, jak wspomniałeś). Rozwiń swój umysł na nowe pomysły.
riwalk

3
@Mathieu M. - zgodził się - mieszanie GOTO ze strukturalnymi instrukcjami kontrolnymi nie jest rozsądne. (To było czyste C i nie było problemu.
MZB,

1
@ Stargazer2 - z prostym FSM zależy od tego, czy umieszczenie stanu w zmiennej i użycie go jako indeksu do wywołania procedury (czy to nie to samo, co obliczone GOTO?) Daje wyraźniejszy / szybszy kod niż przy użyciu licznika programu jako stan FSM. Nie zalecam tego jako najlepszego rozwiązania w większości przypadków, tylko najlepszego rozwiązania w niektórych okolicznościach. Rozwiń swój umysł na alternatywne podejścia.
MZB,

5
@MZB, czy nie zgadzasz się, że wywołanie funkcji jest również tylko obliczonym GOTO? To samo dotyczy konstrukcji typu / while / if / else / switch. Projektanci języków bez powodu usuwają bezpośrednie zmiany w liczniku programu. Nie używaj goto.
riwalk

3
Bezpośrednie wdrożenie statemachine jest prawdopodobnie antypatternem. Istnieje wiele sposobów posiadania maszyny stanów bez wyrażenia stanów i przejść dosłownie. na przykładimport re
SingleNegationElimination

12

Poświęcamy się, aby kod był testowalny

Przeskakuję przez wiele obręczy, aby mój kod był testowalny, ale nie udaję, że nie zrobiłbym tego, gdyby miał wybór. Często jednak słyszę, jak ludzie popierają pomysł, że są to „najlepsze praktyki”. Praktyki te obejmują (napisane w języku .Net, ale dotyczą również innych języków) :

  • Tworzenie interfejsu dla każdej klasy. To podwaja liczbę klas (plików) do czynienia, i kod duplikatów. Tak, programowanie interfejsu jest dobre, ale do tego właśnie służą specyfikatory publiczne / prywatne.
  • Każda klasa, która nie została utworzona przy uruchomieniu, potrzebuje fabryki. Oczywiście new MyClass()jest to o wiele prostsze niż pisanie fabryki, ale teraz metody, która ją tworzy, nie można przetestować osobno. Gdyby nie ten fakt, zrobiłbym tylko 1/20 liczby klas fabrycznych, które teraz robię.
  • Upublicznij każdą klasę, co przeczy celowi posiadania specyfikatorów dostępu do klas w ogóle. Jednak do klas niepublicznych nie można uzyskać dostępu (a tym samym przetestować) z innych projektów, więc jedyną inną opcją jest przeniesienie całego kodu testowego do tego samego projektu (a zatem zwolnienie go z produktem końcowym).
  • Wstrzykiwanie zależności. Najwyraźniej muszę podawać co drugiej klasie, której używam pola i parametru konstruktora, to znacznie więcej pracy niż tylko tworzenie ich, kiedy ich potrzebuję; ale wtedy nie mogę już przetestować tej klasy w izolacji.
  • Zasada Jednej Odpowiedzialności, która spowodowała tak wiele bólów głowy, doprowadziłem ją do własnej odpowiedzi .

Co więc możemy zrobić, aby to naprawić? Potrzebowalibyśmy radykalnej zmiany w architekturze językowej:

  • Potrzebowalibyśmy umiejętności kpienia z zajęć
  • Potrzebowalibyśmy możliwości testowania prywatnych metod klas wewnętrznych z innego projektu (może się to wydawać luką w zabezpieczeniach, ale nie widzę problemu, jeśli testowany jest zmuszony nazwać swoje klasy testerów) .
  • Wstrzykiwanie zależności (lub lokalizacja usługi), a także coś równoważnego z naszym istniejącym wzorcem fabrycznym, musiałoby być podstawową częścią języka.

Krótko mówiąc, potrzebujemy języka zaprojektowanego od podstaw z myślą o testowaniu .


Zgaduję, że nigdy nie słyszałeś o TypeMock ? Pozwala kpić z klas, szeregowców, statyki (fabryka), cokolwiek.
Allon Guralnek 20.01.11

@Allon: Mam, ale jest daleki od darmowego , co sprawia, że ​​nie jest to opcja dla większości ludzi.
BlueRaja - Danny Pflughoeft

Jeśli musisz napisać wiele klas fabrycznych, robisz coś złego. Biblioteki Smart DI (np. Autofac dla C #) mogą wykorzystywać Func <T>, Lazy <T>, Delegaci itp. W fabrykach, bez samodzielnego pisania jakichkolwiek szablonów.
gix

10

Rozdzielanie aplikacji na poziomy; Warstwa danych, warstwa biznesowa, warstwa interfejsu użytkownika

Głównym powodem, dla którego mi się to nie podoba, jest to, że większość miejsc, które stosują tę metodę, używają bardzo kruchych ram, aby to zrobić. Warstwa interfejsu IE jest ręcznie kodowana do obsługi obiektów warstwy biznesowej, obiekty warstwy biznesowej są ręcznie kodowane do obsługi reguł biznesowych i bazy danych, baza danych jest SQL i jest już dość krucha i zarządzana przez grupę „DBA”, która nie lubi zmian.

Dlaczego to takie złe? Najczęstszym żądaniem rozszerzenia jest prawdopodobnie „Potrzebuję pola na ekranie X, które ma Y”. Huk! Masz tylko nową funkcję, która wpływa na każdą warstwę, a jeśli oddzielisz warstwy za pomocą różnych programistów, stało się to dużym problemem z udziałem wielu osób i grup, dla bardzo prostej zmiany.

Ponadto nie wiem, ile razy brałem udział w kłótniach, które dotyczą czegoś takiego. „Pole nazwy jest ograniczone do maksymalnej długości 30, czy jest to warstwa interfejsu użytkownika, warstwa biznesowa lub warstwa danych?” I jest sto argumentów i nie ma właściwej odpowiedzi. Odpowiedź jest taka sama, wpływa na wszystkie warstwy, nie chcesz, aby interfejs użytkownika był głupi i musisz przejść przez wszystkie warstwy i zawieść w bazie danych, tak aby użytkownik odkrył, że jego wpis jest za długi. Jeśli to zmienisz, wpłynie to na wszystkie warstwy itp.

„Warstwy” również mają tendencję do wycieku; Jeśli jakakolwiek warstwa jest fizycznie oddzielona granicami procesu / maszyny (interfejs internetowy IE i logika zaplecza biznesowego), reguły są duplikowane, aby wszystko działało całkiem dobrze. Tzn. Logika biznesowa kończy się w interfejsie użytkownika, nawet jeśli jest to „reguła biznesowa”, ponieważ użytkownik potrzebuje interfejsu użytkownika, aby móc reagować.

Jeśli zastosowana struktura lub zastosowana architektura jest odporna na niewielkie zmiany i wycieki, tj. W oparciu o metadane i jest dynamicznie dostosowywana we wszystkich warstwach, może być mniej bolesna. Ale większość frameworków jest królewskim bólem, wymagającym zmian interfejsu użytkownika, zmian warstwy biznesowej i zmian bazy danych dla każdej drobnej zmiany i powodującym więcej pracy i mniej pomocy niż ta technika powinna przynieść.

Prawdopodobnie zostanę o to zatrzaśnięty, ale oto on :)


+1, brzmi jak moje ostatnie miejsce zatrudnienia w najdrobniejszych szczegółach! Zasadniczo szanuję aplikacje wielopoziomowe, jednak zbyt wiele osób traktuje je jak srebrną kulę, gdy nie ma to sensu. Większość oprogramowania biznesowego ma zadziwiająco małą logikę biznesową, a to, co ma, jest stosunkowo proste. Może to sprawić, że logika biznesowa warstw stanie się koszmarem kodu typu „płyta główna”. Wiele razy linie mogą się zacierać między dostępem do danych a logiką biznesową, ponieważ zapytanie JEST logiką biznesową.
wałek klonowy

... ponadto większość sklepów absolutnie nie rozpoznaje logiki interfejsu użytkownika lub logiki prezentacji. Ponieważ nie rozumieją, jak mało jest logiki biznesowej w typowej aplikacji CRUD, czują, że muszą robić coś złego, gdy większość ich logiki znajduje się w warstwie prezentacji jako logika prezentacji. Zostaje fałszywie zidentyfikowany jako logika biznesowa, a następnie ludzie wypychają go na serwer w celu wykonania kolejnego połączenia z serwerem. Cienki klient może i powinien mieć logikę prezentacji, np. (Ukryj textField2, jeśli opcja dropDown3 jest zaznaczona).
wałek klonowy


7

Historie użytkowników / Przypadki użycia / Personas

 

Rozumiem ich potrzebę, gdy programujesz dla branży, której nie znasz, ale myślę, że kiedy zostaną wdrożone w pełni, stają się zbyt korporacyjne i tracą czas.


7

Limity 80 znaków / linii są głupie

Rozumiem, że należy wprowadzić pewne kompromisy, aby dopasować tempo najwolniejszego programu uruchamiającego po stronie GUI (ograniczenia rozdzielczości ekranu itp.), Ale dlaczego ta reguła dotyczy formatowania kodu?

Zobacz ... Był mały wynalazek zwany poziomym paskiem przewijania, który został stworzony w celu zarządzania wirtualnym miejscem na ekranie poza skrajną prawą granicą pikseli. Dlaczego programiści, którym udało się stworzyć świetne narzędzia zwiększające produktywność, takie jak podświetlanie składni i automatyczne uzupełnianie, nie używają go?

Jasne, istnieją edytory CLI religijnie używane przez dinozaury * nix, które przestrzegają starych, zmęczonych ograniczeń terminali VT220, ale dlaczego reszta z nas ma ten sam standard?

Mówię, przykręć limit 80 znaków. Jeśli dinozaury są wystarczająco epickie, aby hakować emacs / vim przez cały dzień, dlaczego nie mogą być w stanie stworzyć rozszerzenia, które automatycznie otacza linie lub daje możliwości przewijania w poziomie ich IDE CLI?

Monitory pikselowe 1920 x 1080 staną się w końcu normą, a programiści na całym świecie nadal będą podlegać tym samym ograniczeniom, nie mając żadnego wpływu na to, dlaczego tak robią, z wyjątkiem tego, że powiedzieli im to starsi, gdy dopiero zaczynali programować.

Limity 80 znaków nie są najlepszą praktyką, ale niszową praktyką dla bardzo mniejszości programistów i powinny być traktowane jako takie.

Edytować:

Jest zrozumiałe, że wielu programistów nie lubi poziomego paska przewijania, ponieważ wymaga gestu myszy, więc ... Dlaczego nie zwiększyć limitu szerokości kolumny do wyższej liczby (niż 80) dla tych z nas, którzy używają nowoczesnych wyświetlaczy.

Kiedy monitory komputerowe 800x600 stały się normą dla większości użytkowników, twórcy stron internetowych zwiększyli szerokość swoich witryn, aby pomieścić większość ... Dlaczego programiści nie mogą zrobić tego samego.


1
@Orbling Nice logiki GWB z ___ jest złym kątem. Więc nienawidzisz hScroll, czy masz jakiś uzasadniony powód, dla którego szerokość kolumny powinna być ograniczona do 80 znaków? Dlaczego nie 160 lub 256? Myślę, że wszyscy możemy założyć, że większość programistów wycofała swoje terminale VT220 i zastąpiła je puTTY, aby i tak mogli programowo zwiększyć szerokość.
Evan Plaice

4
Wolę trzymać się limitu 80 znaków. Jak tylko dasz mi więcej przestrzeni poziomej, postaram się otworzyć dodatkowe dokumenty obok siebie. Nie chciałbym przewijać na cztery sposoby. Poza tym często zauważyłem, że zmuszony jestem pisać bardziej czytelny kod przy pomocy znaku 80 znaków.
Filip Dupanović 18.01.11

2
jak byś to wydrukował?

5
Przepraszam - muszę się z tym nie zgodzić. Naprawdę nienawidzę długich długich linii - wymaga więcej ruchów gałek ocznych, wymaga gestów myszy, aby przewijać, trudniej jest dostrzec subtelnie małe, zwisające rzeczy na końcu linii. W około 99% przypadków istnieją czyste sposoby sprawiania, by rzeczy przebiegały po kilku (krótszych) liniach, co jest wyraźniejsze i łatwiejsze do odczytania. 80 znaków może być dowolnych i „ponieważ tak było w czasach kart dziurkowanych”, ale nadal jest to rozsądne ramy do pracy w środku - przez większość czasu - z powyższych powodów.
szybko_nie

3
Wcięcie o 2 spacje. I użyj edytora z automatycznym śledzeniem wcięć. Robiłem to w ten sposób od lat, nic wielkiego. (Pomaga tutaj Emacs z odpowiednimi trybami).
szybko_niedz.

5

Mierz, mierz, mierz

Tak dobrze, odmierzaj, ale do izolowania błędów wydajności, mierzenia efektów, a także sukcesywnej eliminacji. Oto metoda, której używam.

Próbowałem wyśledzić źródło „mądrości” miary. Powiedział to ktoś z wystarczająco wysokim mydłem, a teraz podróżuje.


5

Mój nauczyciel wymaga, aby wszystkie moje identyfikatory (bez stałych) zaczynać małymi literami, np myVariable.

Wiem, że wydaje się to drobnostką, ale wiele języków programowania wymaga zmiennych, które zaczynają się od wielkich liter. Cenię sobie spójność, więc moim zwyczajem jest zaczynać wszystko od wielkich liter.


9
Miałem nauczyciela, który wymagał camelCase, ponieważ nalegał, aby ludzie używali go w prawdziwym świecie ... W tym samym czasie programowałem w dwóch różnych grupach w mojej pracy - obie grupy nalegały na niedostateczne wyniki. Liczy się to, czego używa twoja grupa. Mógł określić się jako główny programista i wszystko byłoby dobrze w mojej książce - przestrzegamy jego konwencji - ale zawsze wyrażał swoją opinię jako „sposób, w jaki rzeczy są wykonywane w prawdziwym świecie”, jak gdyby nie było innych ważnych droga.
xnine

@xnine Nie mam jeszcze wystarczającej liczby przedstawicieli na tej stronie, aby ocenić twój komentarz, więc po prostu odpowiem tym komentarzem zatwierdzającym.
Maxpm

5
Wielbłąd (pierwsza litera) jest dość powszechną konwencją, podobnie jak litera Pascala (pierwsza litera każdego słowa pisana wielką literą). W większości języków camelCase jest używany w zmiennych prywatnych / wewnętrznych, a PascalCase w klasach, metodach, właściwościach, przestrzeniach nazw, zmiennych publicznych. Przyzwyczajenie się do bycia przygotowanym do projektów, które mogą wykorzystywać inny schemat nazewnictwa, nie jest złą praktyką.
Evan Plaice,

2
Po prostu FYI. Niektóre języki wywodzą znaczenie na podstawie tego, czy pierwsza litera zmiennej jest wielka, czy nie. W jednym z takich języków, jeśli pierwsza litera jest duża, zmienna jest traktowana jako stała - każda próba jej zmiany spowoduje błąd.
Berin Loritsch,

1
W Go metody publiczne i członkowie klas zaczynają się od dużej litery; prywatne z małą literą.
Jonathan Leffler,

5

Użyj singletonów

Kiedy powinieneś mieć tylko jedną instancję czegoś. Nie mogę się nie zgodzić . Nigdy nie używaj singletonu i po prostu przydziel go raz i w razie potrzeby omiń wskaźnik / obiekt / referencję. Nie ma absolutnie żadnego powodu, aby tego nie robić.


2
To cała masa negatywów, które wprawiły mnie w zakłopotanie co do twojej rzeczywistej postawy wobec singletonów.
Paul Butcher

1
@Paul Butcher: Nienawidzę singletonów i nigdy nie należy ich używać

1
@rwong: Osobiście nie sądzę, aby jakikolwiek powód był uzasadniony. Po prostu napisz to jako normalną klasę. Naprawdę nie ma powodu, aby używać singletona innego niż lenistwo i promować złe nawyki lub projektowanie.

6
Kto powiedział, że używanie Singeltons jest najlepszą praktyką?
Phil Mander,

2
Singletony mają swoje miejsce, szczególnie w przypadkach, w których struktura operacyjna jest przydzielana i wypełniana przy starcie, a następnie w zasadzie staje się czytana tylko w czasie wykonywania programu. W takim przypadku po prostu staje się pamięcią podręczną po drugiej stronie wskaźnika.
Tim Post

5

Używanie unsigned int jako iteratora

Kiedy dowiedzą się, że używanie podpisanego int jest znacznie bezpieczniejsze i mniej podatne na błędy. Dlaczego tak ważne jest, aby indeks tablicy mógł być tylko liczbą dodatnią, aby każdy z przyjemnością przeoczył fakt, że 4-5 to 4294967295?


Okej, teraz jestem ciekawa - dlaczego to mówisz? Czuję się trochę głupio - czy możesz podać przykłady kodu, aby wykonać kopię zapasową swoich oświadczeń?
Paul Nathan

4
@Paul Nathan: jeśli chodzi o buggyness, oto jeden przykład: for (unsigned int i = 0; i <10; i ++) {int crash_here = my_array [max (i-1,0)];}
AareP

@AareP: Dla pewności - przypuszczam, że odwołujesz się do faktu, że kiedy int 0intonowany przez niepodpisane jest zmniejszany 1, faktycznie kończy się na maksymalnej wartości dodatniej, którą może przechowywać int bez znaku?
Adam Paynter,

1
@Adam Paynter: tak. Może się to wydawać normalne dla programistów c ++, ale spójrzmy prawdzie w oczy, „unsigned int” to jedna zła „implementacja” liczb dodatnich.
AareP

Nie jest to dobry pomysł na małych komputerach wbudowanych - często bez znaku int generuje mniejszy, szybszy kod. Zależy od kompilatora i procesora.
szybko_nie

4

Metody nie powinny być dłuższe niż pojedynczy ekran

Całkowicie zgadzam się z zasadą jednej odpowiedzialności, ale dlaczego ludzie postrzegają ją jako „funkcję / metodę, która może ponosić tylko jedną odpowiedzialność na najwyższym poziomie logicznej szczegółowości”?

Pomysł jest prosty. Funkcja / metoda powinna wykonać jedno zadanie. Jeśli części tej funkcji / metody można użyć gdzie indziej, należy ją pokroić na własną funkcję / metodę. Jeśli można go użyć w innym miejscu projektu, przenieś go do własnej klasy lub klasy użyteczności i spraw, aby był dostępny wewnętrznie.

Posiadanie klasy zawierającej 27 metod pomocniczych, które są wywoływane tylko raz w kodzie, jest głupie, marnuje miejsce, niepotrzebny wzrost złożoności i ogromny czas. Brzmi bardziej jak dobrą zasadę dla osób, które chcą wyglądać na zajętego refaktoryzacją kodu, ale nie produkują dużo.

Oto moja zasada ...

Napisz funkcje / metody, aby coś osiągnąć

Jeśli masz zamiar skopiować / wkleić jakiś kod, zadaj sobie pytanie, czy lepiej byłoby utworzyć funkcję / metodę dla tego kodu. Jeśli funkcja / metoda jest wywoływana tylko raz w innej funkcji / metodzie, czy naprawdę jest sens, aby mieć ją na pierwszym miejscu (czy będzie ona wywoływana częściej w przyszłości). Czy warto dodawać więcej skoków do / z funkcji / metod podczas debugowania (tj. Czy dodany skok ułatwia lub utrudnia debugowanie)?

Całkowicie się zgadzam, że funkcje / metody większe niż 200 linii wymagają analizy, ale niektóre funkcje wykonują tylko jedno zadanie w tylu liniach i nie zawierają żadnych użytecznych części, które można by wyodrębnić / wykorzystać w pozostałej części projektu.

Patrzę na to z perspektywy deweloperów API ... Gdyby nowy użytkownik spojrzał na diagram klasowy twojego kodu, ile części tego diagramu miałoby sens w większej całości projektu i ile istniałoby wyłącznie jako pomocnicy do innych części wewnętrznych projektu.

Gdybym miał wybierać między dwoma programistami: pierwszy ma tendencję do pisania funkcji / metod, które próbują robić zbyt wiele; drugi łamie każdą część każdej funkcji / metody do najdrobniejszego poziomu szczegółowości; Wybrałbym pierwsze rozdania. Pierwszy osiągnąłby więcej (tj. Napisałby więcej aplikacji), jego kod byłby łatwiejszy do debugowania (ze względu na mniejszą liczbę skoków do funkcji / metod podczas debugowania) i traciłby mniej czasu na pracowitą pracę, doskonaląc jak kod wygląda vs doskonalenie jego działania.

Ogranicz niepotrzebne abstrakcje i nie zanieczyszczaj autouzupełniania.


To. Kiedyś przekształciłem jakąś długą funkcję w kilka, tylko po to, aby zdać sobie sprawę, że prawie wszystkie z nich wymagały prawie wszystkich parametrów oryginalnego kodu. Obsługa parametrów była tak uciążliwa, że ​​łatwiej było wrócić do starego kodu.
l0b0

3
Myślę, że jednym z przeciwnych argumentów jest to, że refaktoryzacja części dużej metody na osobne wywołania może ułatwić odczytanie większej metody. Nawet jeśli metoda jest wywoływana tylko raz.
Jeremy Heiler

1
@Jeremy How? W jaki sposób wyodrębnienie części kodu i umieszczenie jej we własnej metodzie sprawia, że ​​jest ona bardziej czytelna niż umieszczanie komentarza w jednym wierszu na początku fragmentu kodu opisującego, co robi? Zakładając, że blok kodu jest używany tylko raz w tej sekcji kodu. Czy naprawdę jest to takie trudne dla większości programistów, którzy rozkładają działające części kodu podczas czytania i / lub umieszczają kilka jednowierszowych komentarzy przypominających im, co robi, jeśli nie mogą?
Evan Plaice,

4
@Evan: Umieszczenie fragmentów kodu w funkcjach skutecznie nadaje im nazwę , miejmy nadzieję, że dobrze wyjaśnia, co robi ten fragment kodu. Teraz, niezależnie od tego, gdzie wywoływany jest ten fragment kodu, możesz zobaczyć nazwę wyjaśniającą, co robi kod , zamiast analizować i rozumieć sam algorytm. Jeśli zrobisz to dobrze, może to znacznie ułatwić czytanie i zrozumienie kodu.
sbi

1
+1, a gdybym mógł, dałbym więcej. Nie ma nic złego w kawałku kodu C, który zawiera 1000 wierszy w jednej funkcji (np. Parser z ogromnym przełącznikiem ()). ZAPEWNIONY cel jest jasny i prosty. Rozbicie wszystkich małych kawałków i wywołanie ich tylko utrudnia zrozumienie. Oczywiście są też granice ... rozsądny osąd jest wszystkim.
szybko_nie
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.