Chciałbym dodać odpowiedź na to pytanie, ponieważ ostatnio przeszedłem przez dobrą, złą, ale przeważnie brzydką Javę i mam całkiem nowe mnóstwo rażących nadmiernych uogólnień na temat Java i deweloperów Java vs. JS i JS devs, które mogą być oparte na czymś nieco przypominającym użyteczną prawdę.
Istnieją IDE, ale pomocne może być zrozumienie, dlaczego nie było ich wielu
Próbowałem Webstorm teraz, kiedy zainteresowałem się tworzeniem Node i nie jest wcale tak źle, że go kupiłem, ale nadal mam tendencję do otwierania plików js w Scite częściej niż WS. Powodem tego jest to, że możesz zrobić o wiele więcej za dużo mniej w JS, ale także dlatego, że praca interfejsu użytkownika daje natychmiastową informację zwrotną, narzędzia programistyczne dla przeglądarki (w szczególności Chrome i Firebug) są naprawdę doskonałe, a (uwzględnianie kontekstów innych niż przeglądarka ) ponowne uruchomienie zmienionego kodu jest szybkie i łatwe bez kroku kompilacji.
Kolejną rzeczą, o której jestem dość przekonany, jest to, że IDE w zasadzie tworzą własne wymagania, włączając niechlujny kod, na który tak naprawdę nie można sobie pozwolić w JavaScript. Chcesz dowiedzieć się, jak zarządzamy w JS? Pomocne może być rozpoczęcie pisania czegoś, co nie jest trywialne w Javie bez IDE, i zwrócenie szczególnej uwagi na rzeczy, które musisz zacząć robić i myśleć o tym, aby faktycznie móc utrzymać / zmodyfikować ten kod bez przenoszenia IDE Naprzód. IMO, te same rzeczy są nadal niezbędne do napisania łatwego do utrzymania kodu, niezależnie od tego, czy masz IDE, czy nie. Gdybym musiał napisać 4-letni program nauczania, nie pozwoliłby ci dotknąć IDE przez pierwsze dwa lata w interesie, aby nie przekreślić narzędzi i zależności.
Struktura
Doświadczeni deweloperzy JS zajmujący się złożonymi aplikacjami mogą i strukturyzują swój kod. W rzeczywistości jest to jedna rzecz, w której musimy być lepsi w początkowej historii, w której brakowało IDE do odczytania dla nas kodu, ale także dlatego, że potężnie ekspresyjne języki mogą bardzo szybko wyrażać całkowicie niemożliwe do utrzymania bazy kodów katastrof, jeśli nie kodujesz w przemyślany sposób.
Właściwie miałem dość stromą krzywą uczenia się w zrozumieniu naszej bazy kodu Java, dopóki w końcu nie zdałem sobie sprawy, że żaden z nich nie był prawidłowym OOP. Zajęcia były niczym więcej jak wiązkami luźno powiązanych metod zmieniających globalnie dostępne dane siedzące w fasoli lub DTO lub statycznych getterach / setterach. To w zasadzie ta sama stara bestia, którą OOP miał zastąpić. Przestałem więc w zasadzie szukać i myśleć o kodzie. Właśnie nauczyłem się klawiszy skrótu i przeszukiwałem mesy, a wszystko poszło znacznie płynniej. Jeśli więc nie masz już nawyku, pomyśl o OOD znacznie intensywniej.
Dobrze zbudowana aplikacja JS na najwyższym poziomie będzie zwykle składać się ze złożonych funkcji (np. JQuery) i obiektów oddziałujących ze sobą. Twierdziłbym, że cechą dobrze skonstruowanej, łatwej w obsłudze aplikacji w dowolnym języku jest to, że jest doskonale czytelna, czy patrzysz na nią za pomocą IDE czy Notepad ++. Jest to jeden z głównych powodów, dla których jestem bardzo krytyczny wobec wstrzykiwania zależności i pierwszego testowego TDD.
I w końcu puść lekcje. Dowiedz się dziedziczenia prototypowego. W rzeczywistości jest dość elegancki i łatwy do wdrożenia, gdy rzeczywiście potrzebujesz dziedziczenia. Uważam jednak, że metody kompozycyjne działają znacznie lepiej w JS i osobiście zaczynam chorować i mam nocne lęki EXTJS za każdym razem, gdy widzę więcej niż jeden lub dwa poziomy dziedziczenia w dowolnym języku.
Najpierw podstawowe zasady
Mówię o podstawowych rzeczach, z których powinny wynikać wszystkie inne dobre praktyki: SUCHE, YAGNI, zasada najmniejszego zdziwienia, czyste oddzielenie problematycznych domen, pisanie do interfejsu i pisanie czytelnego kodu to mój rdzeń osobisty. Coś nieco bardziej złożonego, co przemawia za porzuceniem tych praktyk, powinno być uważane za Kool Aid w dowolnym języku, ale szczególnie w języku takim jak JavaScript, w którym niezwykle łatwo jest pozostawić dziedzictwo bardzo mylącego kodu dla następnego faceta. Luźne sprzężenie, na przykład, jest świetnym rozwiązaniem, dopóki nie posuniesz się tak daleko, że nie możesz nawet powiedzieć, gdzie zachodzi interakcja między obiektami.
Nie bój się pisania dynamicznego
W JavaScript nie ma wielu podstawowych typów. W przeważającej części zasady dynamicznego rzutowania są praktyczne i proste, ale warto się ich nauczyć, abyś mógł lepiej nauczyć się zarządzać przepływem danych bez zbędnych rzutowań i bezcelowych procedur sprawdzania poprawności. Zaufaj mi. Typy ścisłe doskonale nadają się do problemów z wydajnością i wykrywaniem problemów podczas kompilacji, ale nie chronią cię przed niczym.
Poznaj bzdury dzięki funkcjom i zamknięciom JS
Pierwszorzędne funkcje JS są prawdopodobnie głównym powodem, dla którego JS wygrał nagrodę „Jedyny język warty dotarcia z nagrodą po stronie klienta”. I tak, faktycznie była konkurencja. Są także centralną cechą JS. Konstruujemy z nimi obiekty. Wszystko ma zakres funkcji. I mają przydatne funkcje. Możemy badać parametry za pomocą słowa kluczowego arguments. Możemy tymczasowo dołączyć i odpalić je w kontekście bycia metodami innych obiektów. I sprawiają, że podejście do rzeczy jest nieprzyzwoicie łatwe do wdrożenia. W skrócie, sprawili, że JS była absolutną bestią w zmniejszaniu złożoności i dostosowywaniu różnych implementacji samego JS (ale głównie DOM API) bezpośrednio u źródła.
Ponownie oceń wzorce / praktyki przed przyjęciem
Funkcje pierwszej klasy i typy dynamiczne sprawiają, że wiele bardziej złożonych wzorców projektowych jest całkowicie bezcelowe i niewygodne w JS. Niektóre prostsze wzorce są jednak niezwykle przydatne i łatwe do wdrożenia, biorąc pod uwagę bardzo elastyczny charakter JS. Adaptery i dekoratory są szczególnie przydatne i znalazłem singletony pomocne w złożonych fabrykach widgetów interfejsu użytkownika, które działają również jako menedżery zdarzeń dla elementów interfejsu użytkownika, które budują.
Podążaj za wiodącym językiem i rób więcej za mniej
Uważam, że jeden z głównych honorów Javy argumentuje gdzieś, że gadatliwość jest w rzeczywistości pozytywną cechą, która ułatwia zrozumienie kodu dla wszystkich stron. Bzdury. Gdyby tak było, łatwiej byłoby czytać w języku legalnym. Tylko pisarz może ułatwić zrozumienie tego, co napisali, i możesz to zrobić tylko od czasu do czasu wrzucając się do butów drugiego faceta. Przyjmij więc te dwie zasady. 1. Bądź tak bezpośredni i jasny, jak to możliwe. 2. Dotrzyj już do tego cholernego punktu. Zwycięstwo polega na tym, że czysty, zwięzły kod to rzędy wielkości łatwiejsze do zrozumienia i utrzymania niż coś, w którym trzeba przejść dwadzieścia pięć warstw, aby przejść od wyzwalacza do faktycznie pożądanego działania. Większość wzorców, które opowiadają się za tego rodzaju rzeczami w bardziej rygorystycznych językach, są w rzeczywistości obejściem ograniczeń, których nie ma JavaScript.
Wszystko jest plastyczne i to jest w porządku
JS jest prawdopodobnie jednym z najmniej protekcjonistycznych języków w popularnym użyciu. Przyjmij to. To działa dobrze. Na przykład możesz pisać obiekty z niedostępnymi trwałymi „prywatnymi” zmiennymi, po prostu deklarując zwykłe zmienne w funkcji konstruktora, i robię to często. Ale to nie ma na celu ochrony mojego kodu ani jego użytkowników „przed sobą” (mogliby po prostu zastąpić go własną wersją w czasie wykonywania). Ale raczej ma to zasygnalizować zamiar, ponieważ założeniem jest, że ten drugi facet jest wystarczająco kompetentny, aby nie chcieć rozplątywać żadnych zależności i zobaczy, że nie powinieneś bezpośrednio się do tego zwracać, być może z ważnego powodu.
Nie ma ograniczeń wielkości, tylko problematyczne domeny
Największym problemem, jaki mam ze wszystkimi bazami kodów Java, które widziałem, jest nadmiar plików klasowych. Przede wszystkim SOLID to tylko mylące powtórzenie tego, co powinieneś już wiedzieć o OOP. Klasa powinna obsługiwać określony zestaw powiązanych problemów. Nie ma jednego problemu z jedną metodą. To po prostu bierze zły stary łańcuch C func-spaghetti tylko z dodatkiem całej bezcelowej składni klasy do rozruchu. Nie ma limitu rozmiaru ani metody. Jeśli dodanie czegoś do już długiej funkcji, klasy lub konstruktora ma sens, ma sens. Weź jQuery. Jest to zestaw narzędzi o długości całej biblioteki w jednej funkcji i nie ma w tym nic złego. To, czy nadal potrzebujemy jQuery, wymaga rozsądnej debaty, ale jeśli chodzi o design,
Jeśli Java jest wszystkim, co wiesz, zagłębiaj się w coś ze składnią inną niż C
Kiedy zacząłem zadzierać z Pythonem, ponieważ podobało mi się to, co słyszałem o Django, nauczyłem się oddzielać składnię od projektowania języka. W rezultacie łatwiej było zrozumieć Javę i C jako sumę ich części do projektowania języka, a nie sumę rzeczy, które robią inaczej z tą samą składnią. Przyjemnym efektem ubocznym jest to, że im lepiej rozumiesz inne języki w zakresie projektowania, tym lepiej rozumiesz mocne i słabe strony tego, który znasz najlepiej dzięki kontrastowi.
Wniosek
Teraz, biorąc to wszystko pod uwagę, trafmy wszystkie twoje problemy:
- Nie ma bezpośredniego sposobu znalezienia punktu wejścia funkcji (innego niż wyszukiwanie tekstowe, co może skutkować kolejnymi poszukiwaniami metod wyższych w hierarchii wywołań, po których dwóch lub trzech zapomniałeś, gdzie zacząłeś)
Chrome i Firebug faktycznie mają funkcję śledzenia połączeń. Ale zobacz także moje uwagi na temat struktury i zachowania zwięzłości i bezpośredniości. Im więcej możesz pomyśleć o swojej aplikacji jako o większych, dobrze zamkniętych konstrukcjach oddziałujących na siebie, tym łatwiej jest ustalić, czyja to wina, gdy coś pójdzie nie tak. Powiedziałbym, że dotyczy to również Javy. Posiadamy klasyczne konstruktory funkcji, które doskonale nadają się do obsługi tradycyjnych problemów OOP.
function ObjectConstructor(){
//No need for an init method.
//Just pass in params and do stuff inside for instantiation behavior
var privateAndPersistent = true;
//I like to take advantage of function hoisting for a nice concise interface listing
this.publicAndPointlessEncapsulationMurderingGetterSetter
= publicAndPointlessEncapsulationMurderingGetterSetter;
//Seriously though Java/C# folks, stop with the pointless getter/setters already
function publicAndPointlessEncapsulationMurderingGetterSetter(arg){
if(arg === undefined){
return privateAndPersistent;
}
privateAndPersistent = arg;
}
}
ObjectConstructor.staticLikeNonInstanceProperty = true;
var instance = new ObjectConstructor();//Convention is to capitalize constructors
W moim kodzie prawie nigdy nie używam literałów obiektowych {}
jako strukturalnych komponentów aplikacji, ponieważ nie mogą one mieć wewnętrznych (prywatnych) zmiennych i wolę zamiast tego zarezerwować je do wykorzystania jako struktury danych. Pomaga to ustalić oczekiwania, które zachowają jasność intencji. (jeśli widzisz curlies, to dane, a nie element architektury aplikacji).
- Parametry są przekazywane do funkcji, bez możliwości dowiedzenia się, jakie właściwości i funkcje są dostępne w tym parametrze (poza faktycznym uruchomieniem programu, nawigacją do punktu, w którym funkcja jest wywoływana, i użyciem konsoli console.logs do wyprowadzenia wszystkich właściwości dostępny)
Ponownie zobacz nowoczesne narzędzia przeglądarki. Ale także, dlaczego ponowne uruchomienie programu jest takie bezproblemowe? Przeładowanie jest czymś, co deweloper sieciowy po stronie klienta zwykle uderza co kilka minut, ponieważ nie kosztuje to absolutnie nic. Jest to kolejny punkt, w którym struktura aplikacji może być pomocna, ale jest to jeden niekorzystny kompromis JS, który musisz uruchomić własną weryfikację, gdy egzekwowanie umów jest krytyczne (coś, co robię tylko w punktach końcowych narażonych na inne rzeczy, których moja baza kodów nie robi kontrola). IMO, kompromis jest wart korzyści.
- Powszechne stosowanie anonimowych funkcji jako wywołań zwrotnych, które często prowadzi do spaghetti mylących ścieżek kodu, których nie można szybko nawigować.
Tak, to źle na wszystko, co nie jest trywialne. Nie rób tego Nazwij swoje funkcje, dzieci. Łatwiej jest też prześledzić różne rzeczy. Możesz zdefiniować, ocenić (wymagane do przypisania) i przypisać prostą, trywialną funkcję zgodnie z:
doSomethingWithCallback( (function callBack(){}) );
Teraz Chrome będzie miał dla ciebie nazwę, gdy śledzisz połączenia. Dla nietrywialnej funkcji zdefiniowałbym ją poza wywołaniem. Zauważ też, że anonimowe funkcje przypisane do zmiennej są nadal anonimowe.
- I oczywiście JSLint wychwytuje pewne błędy przed uruchomieniem, ale nawet to nie jest tak przydatne jak posiadanie czerwonych falistych linii pod twoim kodem bezpośrednio w przeglądarce.
Nigdy nie dotykam tego. Crockford podarował społeczności pewne dobre rzeczy, ale JSLint przekracza linię w preferencjach stylistycznych i sugeruje, że pewne elementy JavaScript są złymi elementami bez szczególnie dobrego powodu, IMO. Zdecydowanie zignoruj tę jedną rzecz dotyczącą klas regEx i klas negacji, po których następuje * lub +. Symbole wieloznaczne działają słabiej i możesz łatwo ograniczyć powtarzanie za pomocą {}. Zignoruj także wszystko, co mówi o konstruktorach funkcji. Możesz łatwo owinąć je fabryką, jeśli nowe słowo kluczowe Ci przeszkadza. CSSLint (nie Crockforda) jest jeszcze gorszy na froncie złych rad. Zawsze bierz ludzi, którzy wykonują wiele mówień z odrobiną soli. Czasami przysięgam, że po prostu chcą ustanowić autorytet lub wygenerować nowy materiał.
I znowu, musisz nauczyć się tego, czego nauczyłeś się z tej troski związanej z czasem pracy. (jest to częsty przypadek, gdy widziałem wielu deweloperów Java / C #) Jeśli dwa lata później przeszkadzają ci błędy w czasie wykonywania, chcę, abyś usiadł i spam przeładował się w przeglądarce, dopóki się nie zatopi. nie ma podziału na czas kompilacji / czas działania (zresztą i tak nie jest widoczny - JS działa teraz na JIT). Wykrywanie błędów w czasie wykonywania jest nie tylko w porządku, ale niezwykle korzystne jest tak tanie i łatwe przeładowywanie spamu oraz wykrywanie błędów w każdym punkcie zatrzymania, do którego dojdziesz.
I daj się nabrać na te narzędzia programistyczne Chrome. Są wbudowane bezpośrednio w webkit. Kliknij prawym przyciskiem myszy w Chrome. Sprawdź element. Przeglądaj zakładki. Dużo mocy debugowania z możliwością zmiany kodu w konsoli w czasie wykonywania jest jedną z najpotężniejszych, ale mniej oczywistych opcji. Świetny również do testowania.
W powiązanej notatce błędy są Twoimi przyjaciółmi. Nigdy nie pisz pustej instrukcji catch. W JS nie ukrywamy ani nie chowamy błędów (a przynajmniej nie powinniśmy kaszleć YUI / kaszlu ). Zajmujemy się nimi. Cokolwiek mniej spowoduje ból debugowania. A jeśli napiszesz instrukcję catch, aby ukryć potencjalne błędy produkcyjne, przynajmniej po cichu zaloguj błąd i udokumentuj, jak uzyskać dostęp do dziennika.