Jak upowszechnić wiedzę na temat programowania ogólnego wśród członków zespołu?


20

Pozostaję w środowisku, w którym ludzie wierzą:

  1. Generics Java to funkcja używana wyłącznie do pisania bibliotek, a nie do prawdziwego kodowania.
  2. C ++ jest językiem programowania OO; templatejest funkcją opcjonalną i możliwą do uniknięcia

Chociaż osoby te polegają w dużej mierze na bibliotekach napisanych przy użyciu programowania ogólnego (np. STL, kontenery Java). Jeśli napiszę kod za pomocą templates lub generics, recenzent kodu najprawdopodobniej go odrzuci i skomentuje, aby napisać go w sposób „właściwy / zrozumiały / elegancki” .

Taka mentalność ma zastosowanie od zwykłego programisty do najwyższego rangą menedżera. Nie ma wyjścia, ponieważ w 90% przypadków ludzie ci lobbują.

Jaki jest najlepszy sposób ( nie wymaganie od gardła ) wyjaśniania, praktyczne podejście do pisania kodu, które stanowi OO i ogólne programowanie jednocześnie?


11
Życzę powodzenia, ale prawdopodobnie będziesz musiał odejść, jeśli chcesz.
The Muffin Man

3
@TheMuffinMan, masz rację. Opuściłem to miejsce pracy i teraz mam własną firmę. Tutaj mam pełną kontrolę nad kodowaniem!
iammilind

Odpowiedzi:


14

Nadal są ludzie na świecie, którzy nie używają jave generics w „zwykłym kodowaniu”. Mogę w to uwierzyć za pomocą szablonów C ++, ale ogólne? Nie są nawet trudne do nauczenia / używania. Poważnie najlepsze funkcje Java i C ++ to odpowiednio ogólne i szablony.

Najlepszym sposobem, aby przekonać ludzi do rzeczy, jest przekonujący argument, nie grożenie i racja.

Dopóki nie robisz czegoś takiego jak używanie szablonów jako języka programowania, parametryczny polimorfizm (generyczne / szablony) jest prawie na pewno dobry.

1. Unika kopiowania kodu.

To oczywiste, ale kod polimorficzny jest kodem ogólnym. Dlatego nazywa się to lekami generycznymi.

2. Obsługuje lepsze sprawdzanie statyczne.

Bez polimorfizm parametryczny skończyć pisanie takich rzeczy public Object clone()lub public boolean equals(object b)które są nie tylko obrzydliwości, mają typy, które nie dostarczają informacji o tym, co robią, i zawsze kończy się wyrzucanie wyjątków w każdym miejscu. Alternatywa dla parametrycznego polimorfizmu jest rzucana wszędzie

3. Nieparametryczny polimorfizm OOP zasadniczo nie jest w stanie poprawnie obsługiwać „metod binarnych”.

Używasz ich często.

4. To najlepsza praktyka

W Javie stosowanie ogólnych jest uważane za najlepszą praktykę (patrz Efektywna Java autorstwa Josh Bloch). Główni myśliciele C ++, tacy jak Sutter i Alexandrescu, również zachęcają do korzystania z szablonów do rozwiązywania różnych problemów.

5. Pasuje do paradygmatu OO.

Ludzie często tego nie zauważają, ale kombinacja podtypów i rodzajów generuje system DUŻO bardziej wyrazisty i zorientowany obiektowo niż jakikolwiek inny system z jednym z nich.

Rozważ miksy Scali. Są to miłe funkcje, które pozwalają łączyć obiekty z części składowych. Ogólne i szablony mogą symulować niektóre z tych korzyści. Załóżmy na przykład, że jeden z twoich obiektów korzysta z bazy danych. Dobry projekt pozwoliłby ci wydzielić dostęp do bazy danych do osobnej klasy. Jeśli zrobisz to dobrze, nie tylko pozwala to na wyśmiewanie magazynu danych (klucz do testowalności), ale także oznacza, że ​​możesz dodawać alternatywne implementacje, takie jak ta nowa baza danych bez sql. Tutaj jednak możesz mieć problem, bez względu na to, z której implementacji korzystasz, uzyskasz różne możliwości obiektu biznesowego.

Generics na ratunek!

   public class Business<S extends Datastore>{
      private S store; ...
   }

Teraz możesz zacząć statycznie różnicować swoje Businessobiekty w oparciu o możliwość korzystania z funkcji specyficznych dla bazy danych. Nadal potrzebujesz sprawdzania czasu wykonywania i przesyłania, ale możesz zacząć budować DUŻO lepszy kod.

i

6. Normalny kod nie istnieje.

Istnieją tylko trzy rzeczy we wszechświecie programowania:

  1. biblioteki,
  2. konfiguracje i
  3. zły kod.

Jeśli nie myślisz o swoim kodzie, jakby był biblioteką, masz poważne kłopoty, gdy zmieniają się wymagania dotyczące twojego projektu. Architektura jest (prawdopodobnie) sztuką projektowania dobrych interfejsów API.

Uważam to podejście za oszałamiające. Po przyzwyczajeniu się do programowania z typami sparametryzowanymi, nieużywanie ich sprawia, że ​​wszystko jest uciążliwe. I Java i C ++ mają kilka trudnych miejsc, które pomagają naprawić.


7
I podobnie jak przekonanie, że normal codenie istnieje i że istnieją tylko trzy rodzaje: libraries, configurationsi bad code. Jest to rozumowanie idealistyczne, choć wciąż musisz wyjaśnić to swoim kolegom, którzy mogą nie być tak idealistyczni jak ty. Zgadzam się jednak, że używanie sparametryzowanych typów jest po prostu niesamowite, kiedy się zorientujesz.
Spoike

3
Heck, nawet szablony C ++ nie są tak trudne w użyciu, jeśli nie użyjesz ich do celów metaprogramowania szablonów. :-)
In silico

-1 za sugerowanie, że każdy, kto zdecyduje się nie używać ogólnych, robi to tylko dlatego, że nie wie, jak działa ta funkcja.
tp1

biorąc pod uwagę możliwość niewłaściwego użycia, powiedziałbym, że ograniczenie / niestosowanie generycznych / szablonów może być znacznie lepszą decyzją, niż można to przypisać.
Ryathal

Ludzie, którzy odmawiają używania generycznych / szablonów do inżynierii oprogramowania na dużą skalę, przypadkowo i nieuchronnie zbudują „drugi język” - interpreter działający w Javie, który implementuje dowolny „język biznesowy”, jaki mają na myśli. en.wikipedia.org/wiki/Inner-platform_effect
rwong

16

Jest to wyspecjalizowana forma bardziej ogólnego pytania „jak przekonać swoich przełożonych do korzystania z nowszej i lepszej technologii / sposobu tworzenia rzeczy?”

Niestety nie sądzę, że możesz i nie jestem pewien, czy powinieneś. Jest to z definicji ich wybór, ponieważ płacą ci za robienie rzeczy w określony przez siebie sposób, a nie w dowolny sposób. Najlepsze, co możesz zrobić, to zasugerować, że ta technologia jest dostępna, wiele osób jej używa i wydaje się, że jest to droga przyszłości. Możesz nawet wspomnieć o fakcie, który oni oczywiście powinni już wiedzieć: że najlepiej jest, aby ludzie nie dopuścili do stagnacji swoich umiejętności. Ale to wszystko: jeśli tego nie kupią, nic nie możesz zrobić.

Mogą mieć inne względy, których ty nie masz, ponieważ nie myślisz na ich poziomie. Myślisz jako inżynier, mogą myśleć bardziej w kategoriach biznesowych, a nawet zasobów ludzkich.

  • Czy leki generyczne (lub cokolwiek innego) zwiększą wartość swojego produktu? Prawdopodobnie nie.

  • Czy leki generyczne (lub cokolwiek innego) utrudnią ludziom, których już zatrudniali, wykonywanie swojej pracy? Tak.

  • Czy leki generyczne skrócą czas wprowadzania produktów na rynek? Może byłby to jedyny inżynier. Ale jeśli cała grupa inżynierów musi zostać przeszkolona w zakresie generycznych, zanim w domu zostanie napisany inny wiersz kodu, nie.

Warto rozważyć zmianę pracy. W mojej ostatniej pracy jako pierwsza korzystałem z generycznych w Javie i na szczęście nie mieli z tym problemu; wyrazili zaniepokojenie, że generycy sprawiają, że kod „jest trudniejszy do odczytania”, ale pozwalają mi na to. Znajdź taką pracę.


9

Przekazałbym zalety generyczne recenzentowi kodu i innym współpracownikom przed każdą recenzją:

1) Umożliwiając ci określenie typów, na które działa klasa ogólna lub metoda ogólna, funkcja ogólna przenosi ciężar bezpieczeństwa typu z Ciebie na kompilator. Nie ma potrzeby pisania kodu w celu przetestowania poprawnego typu danych, ponieważ jest on wymuszany w czasie kompilacji. Konieczność rzutowania typu i możliwość wystąpienia błędów w czasie wykonywania są zmniejszone.

2) Produkty generyczne zapewniają bezpieczeństwo typu bez kosztów wielu implementacji.

Zatem [1] i [2] zmniejszają ryzyko błędu w kodzie. Oszczędza to czas programisty, a tym samym pieniądze firmy.

Jeśli czytelność jest problemem, niezręczność korzystania z typów ogólnych może być zagrożona. Jest to jeden z powodów, dla których warto rozszerzyć wytyczne dotyczące kodowania. Można to zrobić w kontekście dnia roboczego, a nie tylko w celu rozszerzenia bibliotek (jednak pomysłem jest refaktoryzacja w trakcie pracy i zaznaczenie potencjalnych metod dla bibliotek w kodzie, aby ułatwić ich późniejsze rozpoznanie). Dlatego nie byłoby powodu, aby nie używać ich w kontekście dnia roboczego.

Dodałbym kilka stwierdzeń o tym, jak inni programiści nie mają problemów z generycznymi: Generics są szeroko stosowane w Javie i wielu innych językach, takich jak C #. Dla każdego poważnego programisty życie byłoby trudne bez tego rodzaju bezpiecznych elementów konstrukcyjnych.

Niemniej jednak możesz wziąć pod uwagę, że niektórzy deweloperzy mogą nie być do zera. Zarząd mógł podjąć świadomą decyzję o ochronie projektów w przeszłości, tym samym chroniąc tych ludzi przed niebezpiecznymi obszarami. W tym przypadku zarówno niewinni, jak i winni zwykle ponoszą winę, ponieważ rzadko przeprowadza się wystarczającą analizę lub mikro-zarządzanie.

Jeśli przedstawisz dobry argument i nie otrzymasz w zamian uzasadnionej odpowiedzi, potajemnie zacznij szukać innej firmy, która poważnie traktuje programowanie.


7

O ile nie jesteś architektem / specjalistą technologicznym, trudno będzie wprowadzić nakaz używania ogólnych / szablonów. Naprawdę powinieneś zaproponować ogólne / szablonowe rozwiązanie na długo przed przeglądem kodu, najlepiej przed jego wdrożeniem.

Co możesz zrobić, to zademonstrować, dlaczego w niektórych przypadkach powinieneś użyć generycznego. Jeśli potrafisz wykazać korzyści, twoi koledzy mogą się zgodzić. Możliwe powody, dla których warto używać ogólnych / szablonów, to:

  • Powinno to pozwolić Ci napisać mniej kodu do powtarzalnych zadań
  • Ułatwia to pracę programistów
  • Wymusza wzorzec ustawiony przez architekta rozwiązania
  • Zawiera on typowe funkcje, które zmusiłyby programistów do nie kopiowania i wklejania kodu (tj. Unikania problemu podwójnej konserwacji)
  • W rozsądnej przyszłości jest to dowód twojego kodu (choć trudno jest uzasadnić tę drogę)

W ostatnim projekcie Java z powodzeniem dodałem ogólną klasę abstrakcyjną, ponieważ spełnia ona pewne podstawowe rzeczy: ułatwiała pracę innym członkom zespołu, egzekwowała wzorzec zaproponowany przez architekta i zawierała wspólny kod, którego programiści nie musieli kopiuj i wklej. Był to prosty wzorzec, który architekt napisał o tych dość kompetentnych ludziach, którzy nadal się mylili (z powodu złożoności rzeczywistego systemu w grze), ale ogólne znaki wskazują, do której klasy idzie.

Oczywiście nie mogę pochwalić się prawdziwym przykładem bez naruszenia umowy o zachowaniu poufności. Ale jako przykład tego, co zrobiłem, byłoby zrobienie wzorca strategii i egzekwowanie go za pomocą generyków. Oto wzorzec strategii:

wprowadź opis zdjęcia tutaj

Aby programiści mogli wymusić ten wzorzec, możesz dodać typ ogólny Context, że powinien używać czegoś, co ma Strategytyp. Pod względem kodu wyglądałoby to mniej więcej tak:

// declare the generic Context class that has a type "S" 
// that is an upper bound class of Strategy
public class Context <S extends Strategy> {
    S strategy;

    // Constructor with an initial strategy
    public Context(S initialStrategy) {
        this.strategy = initialStrategy;
    }

    public void doSomething() {
      strategy.execute(); // assumes that Strategy has an execute() method.
    }

    public void setStrategy(S strategy) {
        this.strategy = strategy;
    }
}

O ile mi wiadomo, możesz to zrobić w dowolny sposób. Upewnij się, że możesz przetestować swój projekt ogólny / szablon za pomocą testów jednostkowych, aby sprawdzić, czy działa, aby mieć pewność co do projektu kodu.

Jeśli twoim kolegom nie podoba się ten pomysł, nie bierz go do siebie, być może nie było dla nich tak łatwego rozwiązania, jak ci się wydawało. Dlatego powinieneś zaproponować ogólne / szablonowe rozwiązanie przed jego wdrożeniem. Nadal musisz współpracować z kolegami, aby rozwiązać rzeczywisty problem w inny sposób.


Uwielbiam schemat! Z jakiego narzędzia korzystałeś?
yannis

@YannisRizos Użyłem yuml.me, który tworzy diagramy z wprowadzania tekstu. Usługa beta jest w tej chwili trochę wadliwa (możesz jednak przesłać wygenerowane zdjęcie do swojego posta za pomocą wygenerowanego linku).
Spoike

dodany do zakładek, dziękuję za udostępnienie. chociaż tak naprawdę nie chcę uczyć się kolejnej składni, choć jest to uproszczone, wygląda fajnie i w pewnym momencie spróbuję.
yannis

@YannisRizos Och, sam ciągle zapominam o składni. Dlatego jest przydatna strona z próbkami . Odkryłem, że szybsze pisanie prostych schematów klas w yuml jest szybsze niż używanie Visio.
Spoike

@YannisRizos yUml to fajne narzędzie. Oto kilka innych przykładów tego, co można z nim zrobić: carnotaurus.philipcarney.com/tagged/yUML
CarneyCode

4

Zawsze istnieje kilka sposobów na zrobienie tego samego. Jeśli korzystanie z szablonów jest niewłaściwe użycie szablonów, powinno to zakończyć się niepowodzeniem przeglądu kodu.

Jeśli jednak kod nie przejdzie przeglądu, ponieważ nie rozumieją szablonów, problem jest innego rodzaju. W takim przypadku doradzaj im (w miły sposób), aby nauczyli się szablonów.


4

To, z czym masz do czynienia, to zbiór uprzedzeń. Ludzie wolą status quo, rozwinęło się przemyślenie grupy, a spór toczył się kilka razy, aby ludzie zakorzenili się w swoich przekonaniach.

Jedną z najbardziej skutecznych strategii jest skupienie się na niewielkim zwycięstwie. W książce przeczytałem następujący przykład : autor był zagorzałym użytkownikiem spoza Apple. Nie lubiła ich i nie chciała mieć z nimi nic wspólnego. Prowadziła wiele dyskusji z ludźmi o postawie pro-Apple, a każda z nich po prostu zepchnęła obcasy głębiej w ziemię. Potem ktoś kupił jej iPoda shuffle i w ten sposób jej uprzedzenia zniknęły. Nie sprawiało, że chciała kupować tylko produkty Apple, ale twarda, zakorzeniona postawa anty-Apple została zastąpiona bardziej zrównoważonym punktem widzenia. Było miejsce na kompromis, a ona w końcu powoli przechodziła na Apple.

Nie próbuj więc przekonywać wszystkich naraz: przyniesie to odwrotny skutek. Skup się na jednej drobiazgu, a reszta stanie się sama. Po prostu pozbądź się dwustronnej natury argumentu, aby ludzie mogli przechodzić krok po kroku, zamiast wszystkich naraz.

Konkretny punkt, na którym należy się skupić, zależy od twojej sytuacji, ale oto jeden pomysł: podział, który szkicujesz między bibliotekami a „prawdziwym kodem”, wydaje się bardzo nienaturalny. Moim zdaniem programista tworzący aplikację powinien poświęcić 80% swojego czasu na bibliotekę dla typu aplikacji, którą tworzy, a 20% na wykorzystanie tej biblioteki do zbudowania aplikacji. Cały kod, który warto przechowywać, należy traktować jako bibliotekę. Sugerowałbym przełożonym, aby uogólnili część kodu w bibliotece wewnętrznej (jeśli jeszcze tego nie zrobiłeś). Zgodnie z ich logiką powinni używać do tego ogólnych, a według powyższego szacunku 80% kodu może znaleźć się w bibliotece. Gdy wszyscy przyzwyczają się do używania leków generycznych z drugiej strony, powinni się do tego przyzwyczaić, a uprzedzenia powinny zniknąć.


Dzięki Peter, była to bardzo wnikliwa odpowiedź. Twoje myśli odnoszą się nie tylko do mojego pytania, ale także do ogólnej filozofii naszego codziennego życia.
iammilind

2

Uwaga „zrozumiałe”. Jeśli recenzent kodu nie widzi korzyści z generics, wówczas wszystkie <<<>>>-tuff to po prostu niezrozumiały hałas, który jest niepotrzebny.

Proponuję rzucić okiem na to, ile faktycznie obecnych błędów (otwartych lub ostatnio naprawionych), które zawiera baza błędów, których można by uniknąć, używając ogólnych. Poszukaj wyjątków ClassCast.

Zauważ też, że jeśli nie masz żadnych błędów, których można by uniknąć za pomocą ogólnych, wtedy twoi koledzy mają taki punkt, że nie potrzebujesz ich.


2

Zrobiłbym to łatwo. Kilka lat temu przeniosłem się z Java 1.4 do 1.6, a generics to prawdziwy wstrząs. Jest to proste i bardzo pomocne, jeśli próbujesz żonglować kilkoma kolekcjami, mapami i innymi strukturami. Jednak pisanie klas, które przyjmują dane ogólne jako parametry, manipuluje nimi i przekazuje je do innych klas, szybko staje się monumentalnie mylące. Czuję wielką satysfakcję z tego, że wszystko działa, ale zastanawiam się, czy warto poświęcić dodatkowy czas i wysiłek. Obawiam się również, że spora liczba programistów Java nigdy tak naprawdę nie zrozumie tego.

Jeszcze kilka przypadkowych myśli z mojej dotychczasowej podróży:

  • ClassCastExceptions występują w czasie wykonywania, ale zwykle pojawiają się w pierwszych kilku uruchomieniach i są łatwe do naprawienia.
  • Każdy artykuł, który przeczytałem na temat leków generycznych, stwierdza, że ​​czasami po prostu nie działają i trzeba od @SuppressWarnings(value="unchecked")czasu do czasu ich używać . Skąd wiesz, że jesteś poza limitami leków generycznych, czy po prostu jesteś głupi i musisz się bardziej zastanowić?
  • Może być trudne zastosowanie @SuppressWarnings(value="unchecked")tylko do jednej linii.
  • Do jednej z moich klas dodałem kilka fantazyjnych generyków. Znałem kilku programistów, którzy mogliby ulepszyć klasę, zanim ją dopracowałem, którzy nigdy nie mogliby jej dotknąć i uzyskać czystą kompilację później.

Generics wyczyścił mój kod zbyt wiele razy i ostrzegał mnie przed problemami, abym go odrzucił, ale widzę też dłuższy czas programowania, dodatkowy czas poświęcony na szkolenie, a programiści Java zmuszeni do pracy w C #, C i Visual Basic. ..lub Java 1.4. Skoncentruję się na pisaniu kodu, który Twoi współpracownicy mogą zrozumieć. Jeśli potrafisz podać jakieś zrozumiałe informacje ogólne, świetnie. Uważam, że generycy Java są szansą / problemem, który nie został jeszcze wyjaśniony.

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.