Jak uniknąć typowych „dynamicznych błędów językowych”?

42

Niedawno przelałem kilka godzin na JavaScript, ponieważ chciałem skorzystać z ogromnej bazy użytkowników. W ten sposób zauważyłem wzór, który większość ludzi przypisuje dynamicznym językom. Sprawia, że ​​wszystko działa naprawdę szybko, ale gdy kod osiągnie określony rozmiar, tracisz dużo czasu na błędy związane z pisaniem, pisownią i refaktoryzacją. Błędy, które normalnie oszczędziłby mi kompilator. I nie każ mi szukać błędów w logice, kiedy popełniłem literówkę w innym module.

Biorąc pod uwagę niewiarygodne śledzenie JavaScript i innych dynamicznie pisanych języków, jestem przekonany, że moje podejście jest nie tak. Czy to tylko cena, którą musisz zapłacić?

Mówiąc bardziej zwięźle:

  • Jak podchodzisz do projektu JavaScript (lub innego dynamicznego języka w tym przypadku) z ~ 2000 LOC?
  • Czy istnieją narzędzia, które zapobiegną popełnianiu tych błędów? Próbowałem przepływu przez Facebook i JSHint, które nieco pomagają, ale nie łapią literówek.
TomTom
źródło
2
Chociaż istnieją sposoby, aby złagodzić koszty, tam koszty .
dcastro
29
Spróbowałbym napisać Twój program w języku o typie statycznym, który kompiluje się w javascript, takim jak Typescript, Scala.js lub Elm.
dcastro
6
testowanie, testowanie, więcej testów i raporty dotyczące zasięgu.
njzk2
7
~ 2000 LOC to mały projekt. Powinien łatwo pasować do tego, co robi dynamiczny język łatwo i dobrze. Jeśli zmagasz się z tego rodzaju projektem wielkości, masz bardziej podstawowy problem ze swoimi umiejętnościami programistycznymi niż cokolwiek, co dotyczy konkretnie języków dynamicznych.
Jack Aidley,
5
@JackAidley Disagreed. OP służy do koncentrowania się na problemach wysokiego poziomu, a nie do tego, czy identyfikator jest poprawnie napisany. To jest umiejętność programowania. Zapewnienie poprawnej pisowni może być wykonane przez środkową równiarkę i / lub wsparcie narzędzia.
mucaho,

Odpowiedzi:

37

Mówiąc konkretnie o JavaScript, możesz zamiast tego użyć TypeScript . Oferuje niektóre rzeczy, o których mówisz. Cytując stronę internetową:

Typy umożliwiają programistom JavaScript korzystanie z wysoce produktywnych narzędzi i praktyk programistycznych, takich jak sprawdzanie statyczne i refaktoryzacja kodu podczas tworzenia aplikacji JavaScript.

Jest to tylko nadzbiór JS, co oznacza, że ​​niektóre z istniejącego kodu będą dobrze działać z TS:

TypeScript zaczyna się od tej samej składni i semantyki, którą znają dziś miliony programistów JavaScript. Użyj istniejącego kodu JavaScript, dołącz popularne biblioteki JavaScript i wywołaj kod TypeScript z JavaScript.

VinArrow
źródło
11
... a TypeScript to w zasadzie Ecmascript 6.
Robert Harvey
11
Ten cytat boli. To po prostu pokazuje, że Microsoft zawsze był firmą zajmującą się językami statycznymi, która po prostu nie rozumie języków dynamicznych. „Typy umożliwiają… refaktoryzację kodu”? Naprawdę? Czy dział PR firmy Microsoft zdaje sobie sprawę, że refaktoryzacja kodu jako praktyka została wynaleziona w Smalltalk (język dynamiczny) i istniała jeszcze wcześniej w Forth (język bez typu)? Czy pierwsze automatyczne narzędzie do refaktoryzacji było częścią IDE Smalltalk, zanim jeszcze języki statyczne miały IDE? Czy współczesne IDE Smalltalk mają narzędzia refaktoryzujące co najmniej tak potężne, jeśli nie bardziej jak Java, C # i C ++? No chodź.
Jörg W Mittag,
5
TypeScript sam w sobie jest świetnym językiem, dlaczego musisz próbować popychać go z takim nonsensem?
Jörg W Mittag,
29
@ Jörg nie tyle o Smalltalk wiem, ale każdy IDE dla JavaScript lub Python Widziałem to mile za co dobre IDE for Java lub C # może zrobić. Są też pewne rzeczy, których po prostu nie da się zrobić w dynamicznym języku (niektóre z najbardziej popularnych refaktoryzacji): Powiedzmy, że masz funkcję publiczną foo(x) { return x.bar;}lub coś w tym rodzaju. Ponieważ nie ma informacji o typie, a funkcja jest publiczna (stąd nie możesz znać wszystkich wywołujących), nie możesz dowiedzieć się, czy nazwa paska powinna zostać zmieniona na baz, jeśli zmienisz nazwę klasy.
Voo
10
Ta odpowiedź mówi, że rozwiązaniem „dynamicznych błędów językowych” nie jest wcale używanie dynamicznego języka.
bgusach
19

Istnieje kilka metod, które mogą pomóc:

Testów jednostkowych

Napisz testy jednostkowe, jeśli to możliwe. Opieranie się wyłącznie na ręcznym testowaniu lub znajdowaniu błędów w środowisku naturalnym jest metodą „chybić trafił”.

Użyj ram

Zamiast tworzyć własne i ryzykować wprowadzenie błędów, w miarę możliwości używaj ustalonych ram.

Preferuj języki CSS / wysokiego poziomu

Gdzie możesz scedować funkcjonalność na CSS lub inny język wysokiego poziomu, w którym piszesz.

Refaktor

Refaktoryzacja w celu zmniejszenia ilości kodu. Mniej kodu = mniej miejsc na błędy.

Ponowne użycie

Wykorzystaj istniejący kod tam, gdzie możesz. Nawet jeśli kod nie jest dokładnie zgodny, lepiej jest skopiować, wkleić i zmodyfikować niż pisać coś na nowo.

IDE

Współczesne środowiska IDE mają na ogół przynajmniej obsługę Javascript. Niektóre edytory tekstu obsługują również Javascript.

Robbie Dee
źródło
5
Chociaż jest to prawda, twoja rada dotyczy zasadniczo każdego języka programowania i ma na celu naprawienie błędów logicznych, a nie tych, które wynikają z języków dynamicznych.
edmz
1
„Twoja rada dotyczy zasadniczo każdego języka programowania” . Bardzo prawdziwe - podobnie jak przejście od projektów hobbystycznych do pełnotłustych rozwiązań dla przedsiębiorstw, które wymaga coraz większej liczby ograniczeń, podobnie - im więcej napisanych skryptów Javascript, tym więcej dyscypliny potrzeba, jeśli koła się nie ruszają szybko zejść. Eric Lippert opisuje to bardzo dobrze.
Robbie Dee,
4
„Preferuj CSS / języki wysokiego poziomu” - tak naprawdę nie rozumiem, co ten bit oznacza w odniesieniu do JavaScript: czy mówisz o przenoszeniu elementów (np. Animacji?) Do arkuszy stylów zamiast kodu JS? Jak CSS odnosi się do języków wysokiego poziomu?
anotherdave
@anotherdave Wiele z tego, co kiedyś stanowczo było domeną Javascript, można teraz osiągnąć w CSS3. Niektóre funkcje mogłyby również zostać przeniesione na język wyższego poziomu, który podlegałby bardziej rygorystycznym kontrolom.
Robbie Dee,
4
@anotherdave Wiele z tego, co ludzie robią z JavaScript, jest obce i nieodpowiednie. Biblioteki, które zapewniają standardowe narzędzia językowe, frameworki, które zapewniają niewiele więcej standardowych elementów HTML, kod replikujący podstawowe funkcje, takie jak kotwice, emulacja MVC, stylizacja, reimplementacja DOM, abstrakcja AJAX, renderowanie prostych obiektów (reimplementacja SVG), funkcje wypełniania, które nie z korzyścią dla użytkownika… Powinieneś zminimalizować ilość JS, którą piszesz. Jeśli możesz to zrobić bez JS, zrób to bez JS.
bjb568
2

Jedno narzędzie , które nie zostały jeszcze wymienione jest prosta, plik-lokalny lub całego projektu wyszukiwania tekstu .

Brzmi prosto, ale kiedy dołączasz wyrażenia regularne, możesz wykonać podstawowe lub zaawansowane filtrowanie, np. Wyszukać słowa znajdujące się w dokumentacji lub kodzie źródłowym.

Było to dla mnie skuteczne narzędzie (oprócz analizatorów statycznych), a biorąc pod uwagę rozmiar twojego projektu 2k LOC, który moim zdaniem nie jest szczególnie duży, powinien być cudowny.

Mucaho
źródło
2
grepiść w daleką podróż. Chyba że nie robisz zbyt dziwnych dynamicznych rzeczy, to załatwia sprawę. Jednak wydaje się to bardzo ręczne, jeśli jesteś przyzwyczajony do IDE dla języków o typie statycznym.
bgusach
1

Obecnie refaktoryzuję kilka tysięcy wierszy kodu w dużym projekcie AngularJS. Jednym z największych problemów jest ustalenie dokładnej umowy danej funkcji. Czasami kończyłem czytać dokumentację API, ponieważ elementy surowej odpowiedzi API były przypisywane do zmiennych, które przechodziły przez 6 warstw kodu przed modyfikacją i zwracały przez kolejne 6 warstw kodu.

Moja pierwsza rada to zaprojektowanie na podstawie umowy . Wprowadź określone dane wejściowe, uzyskaj określone wyniki, unikaj efektów ubocznych i udokumentuj te oczekiwania za pomocą TypeScript lub przynajmniej JSDoc.

Moja druga rada to wdrożenie jak największej liczby kontroli. Przestrzegamy standardu AirBnB i używamy eslint na całej naszej bazie kodu. Zatwierdzanie haków weryfikuje, że zawsze przestrzegamy standardu. Oczywiście dysponujemy baterią testów jednostkowych i akceptacyjnych, a wszystkie zatwierdzenia muszą zostać zweryfikowane przez partnera.

Przejście z edytora tekstu (Sublime Text) na odpowiedni IDE (WebStorm) również znacznie ułatwiło pracę z kodem w ogóle. WebStorm użyje JSDoc, aby podpowiedzieć o oczekiwanych typach parametrów i zgłosić błąd, jeśli podasz niewłaściwy typ lub użyjesz wartości zwracanej w niewłaściwy sposób.

W JavaScript nowe funkcje, takie jak symbole i getter / setters, mogą pomóc w egzekwowaniu określonego poziomu jakości poprzez dodanie asercji do przypisania zmiennej (np. Upewnij się, że liczba całkowita znajduje się w zasięgu lub że obiekt danych ma określone atrybuty).

Niestety nie sądzę, aby istniało prawdziwe rozwiązanie zapobiegające dynamicznym błędom językowym, a jedynie szereg środków, które mogą pomóc zmniejszyć ich częstotliwość.

Nicolas Bouliane
źródło
0

Moja odpowiedź na pytanie „Jak podchodzisz do projektu JavaScript (lub innego dynamicznego języka w tym przypadku) z ~ 2000 LOC?”

Tworzę aplikacje formularzy PDF. Do mojego projektu rozwoju oprogramowania JavaScript (bez względu na rozmiar kodu źródłowego) podchodzę przy użyciu elementów sieciowych i adnotacji Petri. Metoda nie jest powiązana z żadną konkretną technologią języka programowania. Dlatego można go używać w innych „językach programowania”.

Tworzę schemat logiki aplikacji. Aby utrzymać porządek na schemacie, dodaję większość moich adnotacji do formularza, którego używam ze schematem. Wpisy w formularzu zawierają odniesienia do właściwości lub funkcji. Następnie wypisuję kod źródłowy na podstawie informacji na schemacie i wpisów w formularzu. Metoda jest systematyczna, ponieważ każdy zapisany kod źródłowy jest bezpośrednio mapowany z diagramu i wpisów w formularzu. Kod źródłowy można łatwo sprawdzić, ponieważ podczas pisania kodu przestrzegam również konwencji nazewnictwa i kodowania.

Na przykład wybrałem konwencję, że wszystkie funkcje są prototypami. Jeśli wydajność stanie się problemem, można ją poprawić, deklarując funkcje w konstruktorze. Do niektórych właściwości używam tablic. Ponownie, jeśli wydajność staje się problemem, można ją poprawić, stosując bezpośrednie odniesienia.

Używam również eval. Może to znacznie zmniejszyć rozmiar kodu źródłowego. Z powodu problemów z wydajnością używam eval na początku lub w części inicjalizacji mojej aplikacji; Nigdy nie używam go w „logice środowiska wykonawczego” - to kolejna konwencja kodowania, którą stosuję.

John Frederick Chionglo
źródło