Problemy z nazewnictwem: czy nazwa „ISomething” powinna zostać zmieniona na „Coś”? [Zamknięte]


68

Rozdział wuja Boba na temat nazw w Czystym Kodzie zaleca unikanie kodowania nazw, głównie w odniesieniu do notacji węgierskiej. On także wyraźnie wymienia usunięcie Iprefiksu z interfejsów, ale nie pokazują przykłady.

Załóżmy, że:

  • Wykorzystanie interfejsu służy głównie do testowania poprzez wstrzykiwanie zależności
  • W wielu przypadkach prowadzi to do posiadania jednego interfejsu z jednym implementatorem

Na przykład, jak należy nazwać tych dwóch? Parseri ConcreteParser? Parseri ParserImplementation?

public interface IParser {
    string Parse(string content);
    string Parse(FileInfo path);
}

public class Parser : IParser {
     // Implementations
}

A może powinienem zignorować tę sugestię w przypadkach takich jak jedno wdrożenie?


30
To wcale nie czyni religii mniejszą. Musisz szukać powodów, a nie tylko tego, że X mówi Y.
Mike Dunlavey

35
@MikeDunlavey I to jest powód pytania!
Vinko Vrsalovic

14
Jeśli istnieje istniejąca treść kodu (której nie zamierzasz przepisać), trzymaj się dowolnej stosowanej konwencji. Jeśli nowy kod, użyj tego, co większość ludzi, którzy będą nad nim pracować, jest najszczęśliwsza z / przyzwyczaić się. Tylko wtedy, gdy powyższe postanowienia nie mają zastosowania, powinno stać się pytaniem filozoficznym.
TripeHound,

9
@TripeHound Reguła większości nie zawsze jest najlepszą opcją. Jeśli istnieją powody, dla których niektóre rzeczy są lepsze od innych, jedna osoba może przekonać resztę zespołu, przedstawiając uzasadnienie na podstawie tych powodów. Po prostu ślepe podporządkowanie się większości bez dokonywania oceny rzeczy prowadzi do stagnacji. Widzę z odpowiedzi, że w tym konkretnym przypadku nie ma dobrego powodu, aby usunąć Is, ale to nie unieważnia zadawania pytań w pierwszej kolejności.
Vinko Vrsalovic

35
Książka „Wujka Boba” skupia się na JAVA, a nie na C #. Większość paradygmatów jest taka sama z C #, ale niektóre konwencje nazewnictwa różnią się (spójrz także na nazwy funkcji lowerCamelCase w Javie). Pisząc w języku C #, używaj konwencji nazewnictwa C #. Ale i tak postępuj zgodnie z głównym punktem jego rozdziału na temat nazewnictwa: czytelne nazwy, które przekazują znaczenie przedmiotu!
Bernhard Hiller

Odpowiedzi:


191

Chociaż wiele osób, w tym „Wujek Bob”, odradza stosowanie Ijako prefiksów interfejsów, jest to dobrze znana tradycja w języku C #. Ogólnie należy tego unikać. Ale jeśli piszesz w C #, naprawdę powinieneś przestrzegać konwencji tego języka i używać go. Niezastosowanie się do tego spowoduje ogromne zamieszanie z kimkolwiek znającym C #, który próbuje odczytać twój kod.


Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
wałek klonowy

9
Nie podajesz podstaw do „Ogólnie należy tego unikać”. W Javie należy unikać. W języku C # należy to objąć. Inne języki mają swoje własne konwencje.
Podstawowy

4
Zasada „ogólnie” jest prosta: klient powinien mieć prawo nawet nie wiedzieć, czy rozmawia z interfejsem czy implementacją. Oba języki źle to zrozumiały. C # pomylił konwencję nazewnictwa. Java pomyliła kod bajtowy. Jeśli przełączę implementację na interfejs o tej samej nazwie w Javie, muszę ponownie skompilować wszystkich klientów, nawet jeśli nazwa i metody się nie zmieniły. To nie jest „wybierz swoją truciznę”. Po prostu źle to robiliśmy. Naucz się z tego, jeśli tworzysz nowy język.
candied_orange

39

Interfejs jest ważną logiczną koncepcją, dlatego interfejs powinien nosić nazwę ogólną. Wolałbym więc

interface Something
class DefaultSomething : Something
class MockSomething : Something

niż

interface ISomething
class Something : ISomething
class MockSomething : ISomething

Ten ostatni ma kilka problemów:

  1. Coś jest tylko jedną implementacją ISomething, ale jest to nazwa ogólna, jakby była jakoś wyjątkowa.
  2. MockSomething wydaje się pochodzić z czegoś, ale implementuje ISomething. Może powinien nosić nazwę MockISomething, ale nigdy nie widziałem tego na wolności.
  3. Refaktoryzacja jest trudniejsza. Jeśli Coś jest teraz klasą, a później dowiesz się, że musisz wprowadzić interfejs, interfejs ten powinien mieć taką samą nazwę, ponieważ powinien być przezroczysty dla klientów, czy typ jest klasą konkretną, klasą abstrakcyjną czy interfejsem . Coś to psuje.

59
Dlaczego nie miałbyś przestrzegać ustalonego standardu zapewnianego przez C #? Jaką korzyść daje to, przewyższając koszty wprowadzenia w błąd i irytacji każdego programisty C #, który za tobą podąża?
Robert Harvey

6
@wallenborn W porządku, ale realistycznie często masz tylko jedną prawidłową implementację interfejsu, ponieważ często używa się interfejsów do kpiny w testach jednostkowych. Nie chcę, aby umieścić Defaultlub Realczy Implw tak wielu moich nazw klas
Ben Aaronson

4
Zgadzam się z tobą, ale jeśli podróżujesz tą drogą, będziesz musiał walczyć z każdym liniowcem, jaki kiedykolwiek stworzono dla C #.
RubberDuck,

3
Nie widzę problemu z posiadaniem możliwej do utworzenia klasy o takiej samej nazwie jak interfejs, jeśli zdecydowana większość instancji implementujących interfejs będzie tą klasą. Na przykład dużo kodu wymaga prostej implementacji ogólnego przeznaczenia IList<T>i tak naprawdę nie obchodzi go, jak jest przechowywany wewnętrznie; możliwość porzucenia Ii nadania nazwy klasy użytecznej wydaje się milsza niż konieczność magicznej wiedzy (jak w Javie), że kod, który chce zwykłej implementacji, List<T>powinien użyć ArrayList<T>.
supercat

2
@ArtB Kilka powodów. Po pierwsze, nie ma języka, w którym konwencja jest ładnym krótkim markerem na klasie CFoo : Foo. Ta opcja nie jest tak naprawdę dostępna. Po drugie , pojawia się dziwna niespójność, ponieważ niektóre klasy miałyby znacznik, a inne nie, w zależności od tego, czy mogą istnieć inne implementacje tego samego interfejsu. CFoo : Fooale SqlStore : Store. Z tym mam jeden problem Impl, który jest po prostu brzydszym markerem. Może gdyby istniał język z konwencją zawsze dodawania C(lub cokolwiek), mogłoby to być lepsze niżI
Ben Aaronson

27

Nie chodzi tylko o konwencje nazewnictwa. C # nie obsługuje wielokrotnego dziedziczenia, więc to starsze użycie notacji węgierskiej ma niewielką, choć przydatną zaletę, gdy dziedziczysz od klasy podstawowej i implementujesz jeden lub więcej interfejsów. Więc to...

class Foo : BarB, IBarA
{
    // Better...
}

... jest lepszy od tego ...

class Foo : BarB, BarA
{
    // Dafuq?
}

IMO


7
Warto zauważyć, że Java starannie omija ten problem, używając różnych słów kluczowych do dziedziczenia klas i implementacji interfejsu, tj . inheritsVs. implements
Konrad Rudolph

6
@KonradRudolph masz na myśli extends.
OrangeDog

2
@Andy Wartością dodaną jest to, że możemy uniknąć szyku węgierskiej notacji, zachowując przy tym całą jasność wyrażoną w tej odpowiedzi.
Konrad Rudolph

2
Naprawdę nie powinno być zamieszania; jeśli odziedziczysz klasę, MUSI ona być pierwsza na liście, przed listą zaimplementowanych interfejsów. Jestem prawie pewien, że jest to wymuszone przez kompilator.
Andy,

1
@Andy ... jeśli odziedziczysz klasę, MUSI ona być pierwsza na liście. To świetnie, ale bez prefiksu nie wiedziałbyś, że masz do czynienia z kilkoma interfejsami lub klasą podstawową i interfejsem ...
Robbie Dee

15

Nie nie nie.

Konwencje nazewnictwa nie są funkcją twojego fandomu wujka Boba. Nie są one funkcją języka, języka C # ani żadnego innego.

Są funkcją twojej bazy kodu. W znacznie mniejszym stopniu twój sklep. Innymi słowy, pierwszy w bazie kodu ustanawia standard.

Tylko wtedy możesz zdecydować. Potem bądź konsekwentny. Jeśli ktoś zacznie być niekonsekwentny, zdejmij pistolet do krojenia i każ mu aktualizować dokumentację, aż się nawróci.

Czytając nową bazę kodu, jeśli nigdy nie widzę Iprzedrostka, czuję się dobrze, niezależnie od języka. Jeśli widzę jeden na każdym interfejsie, czuję się dobrze. Jeśli czasem go zobaczę, ktoś zapłaci.

Jeśli znajdziesz się w rzadkim kontekście ustawiania tego precedensu dla bazy kodu, zachęcam do rozważenia tego:

Jako klasa klienta zastrzegam sobie prawo do tego, żeby nie obchodzić mnie to, z czym rozmawiam. Potrzebuję tylko imienia i listy rzeczy, które mogę zadzwonić pod to imię. Nie mogą się one zmienić, chyba że tak powiem. Jestem właścicielem tej części. To, o czym rozmawiam, interfejs czy nie, nie jest moim działem.

Jeśli wślizgniesz się Iw to imię, klient nie będzie się tym przejmował. Jeśli nie I, klient nie dba o to. To, o czym mówi, może być konkretne. Może nie. Ponieważ nie wzywa newgo w żaden sposób, nie ma znaczenia. Jako klient nie wiem. Nie chcę wiedzieć

Teraz, gdy małpa kodowa patrzy na ten kod, nawet w Javie, może to być ważne. W końcu, jeśli muszę zmienić implementację na interfejs, mogę to zrobić bez powiadamiania klienta. Jeśli nie ma Itradycji, mogę nawet jej nie zmienić. Co może być problemem, ponieważ teraz musimy ponownie skompilować klienta, ponieważ chociaż źródło nie przejmuje się plikiem binarnym. Coś łatwego do przeoczenia, jeśli nigdy nie zmieniłeś nazwy.

Może to nie jest dla ciebie problem. Może nie. Jeśli tak, to dobry powód, aby się tym przejmować. Ale ze względu na zamiłowanie do zabawek biurkowych nie twierdzimy, że powinniśmy to robić na ślepo, ponieważ jest to sposób, w jaki robi się to w pewnym języku. Albo mają cholernie dobry powód, albo ich to nie obchodzi.

Nie chodzi o życie z nim na zawsze. Chodzi o to, żeby nie dać mi bzdury, że baza kodu nie jest zgodna z twoją konkretną mentalnością, chyba że jesteś przygotowany na rozwiązanie „problemu” wszędzie. Jeśli nie masz dobrego powodu, nie powinienem podążać drogą najmniejszego oporu wobec jednolitości, nie przychodź do mnie, głosząc zgodność. Mam lepsze rzeczy do zrobienia.


6
Spójność jest kluczowa, ale w języku o typie statycznym i przy nowoczesnych narzędziach refaktoryzacji zmiana nazw jest dość łatwa i bezpieczna. Więc jeśli pierwszy programista dokonał złego wyboru nazywania, nie musisz żyć z nim wiecznie. Ale możesz zmienić nazewnictwo we własnej bazie kodu, ale nie możesz tego zmienić w bibliotekach frameworkowych ani bibliotekach stron trzecich. Ponieważ prefiks I (lubię to czy nie) jest ustaloną konwencją w świecie .net, lepiej jest postępować zgodnie z konwencją, niż jej nie przestrzegać.
JacquesB

Jeśli używasz C #, zobaczysz te I. Jeśli Twój kod ich używa, zobaczysz je wszędzie. Jeśli Twój kod ich nie używa, zobaczysz je z kodu frameworka, co prowadzi dokładnie do miksu, którego nie chcesz.
Sebastian Redl,

8

Jest jedna drobna różnica między Javą a C #, która jest tutaj istotna. W Javie domyślnie każdy członek jest wirtualny. W języku C # każdy element jest domyślnie zaplombowany - z wyjątkiem elementów interfejsu.

Założenia, które się z tym wiążą, mają wpływ na wytyczną - w Javie każdy typ publiczny powinien być uważany za niekończący, zgodnie z zasadą substytucji Liskowa [1]. Jeśli masz tylko jedną implementację, nazwiesz klasę Parser; jeśli uznasz, że potrzebujesz wielu implementacji, po prostu zmienisz klasę na interfejs o tej samej nazwie i zmienisz nazwę konkretnej implementacji na coś opisowego.

W języku C # głównym założeniem jest to, że kiedy dostajesz klasę (nazwa nie zaczyna się od I), to jest klasa, którą chcesz. Pamiętaj, że nie jest to w przybliżeniu 100% dokładne - typowym kontrprzykładem byłyby takie klasy Stream(które naprawdę powinien byłby być interfejsem lub kilkoma interfejsami), a każdy ma swoje własne wytyczne i pochodzenie z innych języków. Istnieją również inne wyjątki, takie jak dość powszechnie stosowany Baseprzyrostek oznaczający klasę abstrakcyjną - podobnie jak w przypadku interfejsu, wiesz, że typ powinien być polimorficzny.

Istnieje również przyjemna funkcja użyteczności polegająca na pozostawieniu nazwy bez prefiksu I dla funkcjonalności związanej z tym interfejsem bez konieczności uciekania się do tworzenia interfejsu jako klasy abstrakcyjnej (co zaszkodziłoby z powodu braku wielokrotnego dziedziczenia klas w języku C #). Zostało to spopularyzowane przez LINQ, który wykorzystuje IEnumerable<T>jako interfejs i Enumerablejako repozytorium metod mających zastosowanie do tego interfejsu. Nie jest to konieczne w Javie, gdzie interfejsy mogą również zawierać implementacje metod.

Ostatecznie Iprefiks jest szeroko stosowany w świecie C #, a przez to w świecie .NET (ponieważ zdecydowanie większość kodu .NET jest napisana w języku C #, warto stosować się do wytycznych C # dla większości publicznych interfejsów). Oznacza to, że prawie na pewno będziesz pracować z bibliotekami i kodem, który jest zgodny z tą notacją, i warto przyjąć tradycję, aby zapobiec niepotrzebnym nieporozumieniom - to nie tak, że pominięcie prefiksu poprawi kod :)

Zakładam, że rozumowanie wuja Boba było takie:

IBananajest abstrakcyjnym pojęciem banana. Jeśli może istnieć jakaś klasa implementująca, która nie miałaby lepszej nazwy niż Banana, abstrakcja jest całkowicie pozbawiona znaczenia i powinieneś porzucić interfejs i po prostu użyć klasy. Jeśli istnieje lepsza nazwa (powiedzmy LongBananalub AppleBanana), nie ma powodu, aby nie używać jej Bananajako nazwy interfejsu. Dlatego użycie Iprzedrostka oznacza, że ​​masz niepotrzebną abstrakcję, co sprawia, że ​​kod jest trudniejszy do zrozumienia bez żadnych korzyści. A ponieważ ścisłe OOP sprawi, że zawsze będziesz kodować przeciwko interfejsom, jedynym miejscem, gdzie nie zobaczysz Iprefiksu na typie, będzie konstruktor - dość bezsensowny hałas.

Jeśli zastosujesz to do przykładowego IParserinterfejsu, możesz wyraźnie zobaczyć, że abstrakcja znajduje się całkowicie na terytorium „bez znaczenia”. Albo jest coś specyficznego o konkretnej implementacji parsera (np JsonParser, XmlParser...), czy też po prostu użyć klasy. Nie ma czegoś takiego jak „domyślna implementacja” (chociaż w niektórych środowiskach rzeczywiście ma to sens - zwłaszcza COM), albo istnieje konkretna implementacja, albo potrzebujesz abstrakcyjnej metody klasy lub rozszerzenia dla „domyślnych”. Jednak w języku C #, chyba że twoja baza kodu już pomija Iprefiks -f, zachowaj go. Po prostu zanotuj za każdym razem, gdy zobaczysz kod podobny class Something: ISomething- oznacza to, że ktoś nie jest zbyt dobry w przestrzeganiu YAGNI i tworzeniu rozsądnych abstrakcji.

[1] - Technicznie rzecz biorąc, nie jest to specjalnie wspomniane w pracy Liskova, ale jest to jedna z podstaw oryginalnej pracy OOP i podczas mojego czytania Liskova nie zakwestionowała tego. W mniej ścisłej interpretacji (tej przyjętej przez większość języków OOP) oznacza to, że każdy kod używający typu publicznego, który jest przeznaczony do podstawienia (tj. Nie-końcowy / zapieczętowany) musi działać z dowolną zgodną implementacją tego typu.


3
Nitpick: LSP nie mówi, że każdy typ powinien być nie-końcowy. Mówi tylko, że w przypadku typów, które nie ostateczne, konsumenci muszą mieć możliwość przejrzystego korzystania z podklas. - I oczywiście Java ma także typy końcowe.
Konrad Rudolph

@KonradRudolph Dodałem przypis na ten temat; dzięki za opinie :)
Luaan

4

Na przykład, jak należy nazwać tych dwóch? Parser i ConcreteParser? Parser i ParserImplementation?

W idealnym świecie nie powinieneś poprzedzać swojego imienia krótką ręką („Ja ...”), ale po prostu pozwól, aby nazwa wyrażała pojęcie.

Przeczytałem gdzieś (i nie mogę go zdobyć) opinię, że ta konwencja ISomething prowadzi do zdefiniowania koncepcji „IDollar”, gdy potrzebna jest klasa „Dollar”, ale poprawnym rozwiązaniem byłoby pojęcie zwane po prostu „Walutą”.

Innymi słowy, konwencja daje łatwość nazywania rzeczy, a łatwość jest subtelnie błędna .


W prawdziwym świecie klienci twojego kodu (który może być po prostu „ty z przyszłości”) muszą być w stanie przeczytać go później i zapoznać się z nim tak szybko (lub przy minimalnym wysiłku), jak to możliwe (daj klientom kodu, czego oczekują).

Konwencja ISomething wprowadza cruft / bad names. To powiedziawszy, cruft nie jest prawdziwym cruft *), chyba że konwencje i praktyki stosowane przy pisaniu kodu nie są już aktualne; jeśli konwencja mówi „użyj ISomething”, najlepiej użyć go, aby dostosować się (i lepiej pracować) do innych programistów.


*) Mogę uciec od powiedzenia tego, ponieważ „cruft” nie jest zresztą dokładną koncepcją :)


2

Jak wspomniano w innych odpowiedziach, prefiks nazwy interfejsu Ijest częścią wytycznych kodowania dla platformy .NET. Ponieważ w klasach C # i VB.NET częściej występują interakcje z konkretnymi klasami niż z ogólnymi interfejsami, są one najwyższej klasy w schematach nazewnictwa i dlatego powinny mieć najprostsze nazwy - stąd IParserdla interfejsu i Parserdomyślnej implementacji.

Ale w przypadku języków Java i podobnych, w których preferowane są interfejsy zamiast konkretnych klas, wujek Bob ma rację, że Ipowinny zostać usunięte, a interfejsy powinny mieć najprostsze nazwy - Parserna przykład dla interfejsu analizatora składni. Ale zamiast nazwy opartej na rolach ParserDefaultklasa powinna mieć nazwę opisującą sposób implementacji parsera :

public interface Parser{
}

public class RegexParser implements Parser {
    // parses using regular expressions
}

public class RecursiveParser implements Parser {
    // parses using a recursive call structure
}

public class MockParser implements Parser {
    // BSes the parsing methods so you can get your tests working
}

Jest to, na przykład, w jaki sposób Set<T>, HashSet<T>i TreeSet<T>są nazywane.


5
Interfejsy są również preferowane w języku C #. Kto powiedział ci, że preferowane jest używanie konkretnych typów w dotnet?
RubberDuck,

@RubberDuck Jest ukryty w niektórych założeniach, które narzuca ci język. Np. Fakt, że członkowie są sealeddomyślnie i musisz je jawnie virtual. Wirtualność to szczególny przypadek w języku C #. Oczywiście, ponieważ zalecane podejście do pisania kodu zmieniało się na przestrzeni lat, wiele reliktów przeszłości musiało pozostać w celu zachowania zgodności :) Kluczowe jest to, że jeśli otrzymujesz interfejs w C # (który zaczyna się od I), wiesz, że jest to całkowicie typ abstrakcyjny; jeśli dostaniesz brak interfejsu, typowym założeniem jest to, że tego typu chcesz, LSP niech będzie przeklęty.
Luaan

1
Członkowie są domyślnie zapieczętowani, abyśmy mogli jasno powiedzieć, co spadkobiercy mogą przejechać na @Luaan. Wprawdzie czasami jest to PITA, ale nie ma to nic wspólnego z preferencjami dla konkretnych typów. Wirtualny z pewnością nie jest specjalnym przypadkiem w języku C #. Wygląda na to, że miałeś nieszczęście pracować w bazie kodu C # napisanej przez amatorów. Przepraszam, że takie było twoje doświadczenie z językiem. Najlepiej pamiętać, że dev nie jest językiem i vice versa.
RubberDuck

@RubberDuck Hah, nigdy nie powiedziałem, że mi się nie podoba. Wolę to, ponieważ większość ludzi nie rozumie pośrednictwa . Nawet wśród programistów. Domyślnie zapieczętowane jest lepsze . A kiedy zaczynałem od C #, wszyscy byli amatorami, w tym także zespołem .NET :) W „prawdziwym OOP” wszystko powinno być wirtualne - każdy typ powinien być zamienny na typ pochodny, który powinien być w stanie zastąpić dowolne zachowanie . Ale „prawdziwy OOP” został zaprojektowany dla specjalistów, a nie dla osób, które przestawiły się z wymiany żarówek na programowanie, ponieważ to mniej pracy za więcej pieniędzy :)
Luaan

Nie ... Nie. W ogóle nie tak działa „prawdziwy OOP”. W Javie powinieneś poświęcić czas na uszczelnienie metod, których nie należy zastępować, nie pozostawiając tego jak Dziki Zachód, gdzie każdy może przejechać wszystko. LSP nie oznacza, że ​​możesz zastąpić wszystko, co chcesz. LSP oznacza, że ​​możesz bezpiecznie zastąpić jedną klasę inną. Smh
RubberDuck

-8

Masz rację, ponieważ ta konwencja interfejsu I = łamie (nowe) reguły

W dawnych czasach poprzedzałbyś wszystko swoim typem intCounter boolFlag itp.

Jeśli chcesz nazywać rzeczy bez prefiksu, ale także unikaj „ConcreteParser”, możesz użyć przestrzeni nazw

namespace myapp.Interfaces
{
    public interface Parser {...
}


namespace myapp.Parsers
{
    public class Parser : myapp.Interfaces.Parser {...
}

11
Nowy? stary? Czekaj, myślałem, że programowanie dotyczy bardziej racjonalności niż szumu. A może to było w dawnych czasach?

3
nie chodzi tylko o tworzenie konwencji i blogowanie o tym, jak „poprawiają czytelność”
Ewan

8
Uważam, że myślisz o węgierskiej notacji, w której rzeczywiście poprzedziłeś nazwy typami. Ale nie było czasu na napisanie czegoś takiego jak intCounterlub boolFlag. To są niewłaściwe „typy”. Zamiast tego piszesz pszName(wskaźnik na zakończony znakiem NUL ciąg zawierający nazwę), cchName(liczba znaków w ciągu „nazwa”), xControl(x współrzędna formantu), fVisible(flaga wskazująca, że ​​coś jest widoczne), pFile(wskaźnik do plik), hWindow(uchwyt do okna) i tak dalej.
Cody Gray

2
Jest w tym wciąż wiele wartości. Kompilator nie będzie wychwytywał błędu podczas dodawania xControldo cchName. Oba są typu int, ale mają bardzo różną semantykę. Przedrostki czynią tę semantykę oczywistą dla człowieka. Wskaźnik do łańcucha zakończonego przez NUL wygląda dokładnie tak jak wskaźnik do łańcucha w stylu Pascala dla kompilatora. Podobnie Iprefiks interfejsów pojawił się w języku C ++, w którym interfejsy są tak naprawdę tylko klasami (a tak naprawdę w przypadku C, gdzie nie ma czegoś takiego jak klasa lub interfejs na poziomie języka, to tylko konwencja).
Cody Gray

4
@CodyGray Joel Spolsky napisał fajny artykuł, Sprawiając, że zły kod wygląda źle, na temat węgierskiej notacji i sposobów, w jaki został (źle) zrozumiany. Ma podobną opinię: prefiks powinien być typem wyższego poziomu, a nie typem przechowywania surowych danych. On używa słowa „rodzaj”, wyjaśniając, „Używam słowa rodzaj celowo tam, bo Simonyi błędnie użył słowa typu w swojej pracy, a pokolenia programistów źle, co miał na myśli.”
Joshua Taylor
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.