Tak naprawdę nie piszę dużych projektów. Nie prowadzę ogromnej bazy danych ani nie obsługuję milionów wierszy kodu.
Mój kod to przede wszystkim rzeczy „skryptowe” - rzeczy do testowania funkcji matematycznych lub symulacji czegoś - „programowanie naukowe”. Najdłuższe programy, nad którymi pracowałem do tej pory, to kilkaset wierszy kodu, a większość programów, nad którymi pracuję, to około 150.
Mój kod to też bzdury. Zrozumiałem to innego dnia, gdy próbowałem znaleźć plik, który napisałem jakiś czas temu, ale że prawdopodobnie nadpisałem i że nie używam kontroli wersji, co prawdopodobnie powoduje, że wielu z was wzdryga się z bólu z powodu mojej głupoty.
Styl mojego kodu jest zawiły i jest wypełniony przestarzałymi komentarzami wskazującymi alternatywne sposoby zrobienia czegoś lub skopiowanymi wierszami kodu. Podczas gdy nazwy zmiennych zawsze zaczynają się bardzo ładnie i opisowo, gdy dodaję lub zmieniam rzeczy, np. Coś nowego, co ktoś chce przetestować, kod nakłada się na wierzch i zastępuje, a ponieważ czuję, że to powinno być przetestowane szybko, kiedy ja mam frameworkę, zaczynam używać kiepskich nazw zmiennych, a plik przechodzi do puli
W projekcie, nad którym teraz pracuję, jestem w fazie, w której wszystko to wraca, by mnie ugryźć na wielką skalę. Ale problem polega na tym (oprócz korzystania z kontroli wersji i tworzenia nowego pliku dla każdej nowej iteracji i rejestrowania go gdzieś w pliku tekstowym, co prawdopodobnie zdecydowanie pomoże sytuacji). Naprawdę nie wiem, jak postępować w celu poprawy mój rzeczywisty styl kodowania.
Czy testowanie jednostkowe jest konieczne do pisania mniejszych fragmentów kodu? Co powiesz na OOP? Jakie metody są dobre do szybkiego pisania dobrego, czystego kodu podczas „programowania naukowego”, a nie do pracy przy większych projektach?
Zadaję te pytania, ponieważ często samo programowanie nie jest zbyt skomplikowane. Chodzi bardziej o matematykę lub naukę, którą testuję lub badam przy programowaniu. Na przykład, czy klasa jest niezbędna, gdy dwie zmienne i funkcja prawdopodobnie mogłyby się tym zająć? (Należy wziąć pod uwagę, że ogólnie są to sytuacje, w których prędkość programu jest preferowana na szybszym końcu - jeśli wykonujesz 25 000 000 kroków czasowych symulacji, tak jakbyś chciał).
Być może jest to zbyt szerokie, a jeśli tak, przepraszam, ale patrząc na książki o programowaniu, często wydają się być adresowane do większych projektów. Mój kod nie potrzebuje OOP, i jest już dość cholernie krótki, więc nie jest taki jak „och, ale plik zostanie zmniejszony o tysiąc linii, jeśli to zrobimy!” Chcę wiedzieć, jak „zacząć od nowa” i programować czysto w tych mniejszych, szybszych projektach.
Z przyjemnością przedstawię bardziej szczegółowe informacje, ale im bardziej ogólna rada, tym bardziej przydatna, jak sądzę. Programuję w Pythonie 3.
Ktoś zasugerował duplikat. Wyjaśnię, że nie mówię o całkowitym ignorowaniu standardowych standardów programowania. Oczywiście istnieje powód, dla którego istnieją te standardy. Ale z drugiej strony, czy naprawdę ma sens pisanie kodu, który mówi OOP, gdy można by zrobić pewne standardowe rzeczy, byłby znacznie szybszy do napisania i byłby podobny poziom czytelności z powodu krótkiego program?
Są wyjątki. Ponadto prawdopodobnie istnieją standardy programowania naukowego wykraczające poza zwykłe standardy. Też pytam o to. Nie chodzi o to, czy normalne standardy kodowania powinny być ignorowane podczas pisania kodu naukowego, chodzi o pisanie czystego kodu naukowego!
Aktualizacja
Pomyślałem, że dodam aktualizację „nie całkiem tydzień później”. Wszystkie twoje porady były niezwykle pomocne. Teraz używam kontroli wersji - git, z git kraken dla interfejsu graficznego. Jest bardzo łatwy w użyciu i drastycznie wyczyścił moje pliki - nie trzeba już trzymać starych plików lub starych wersji kodu komentowanych „na wszelki wypadek”.
Zainstalowałem także pylint i uruchomiłem go na całym kodzie. Początkowo jeden plik uzyskał wynik ujemny; Nie jestem nawet pewien, jak to było możliwe. Mój główny plik zaczął się od ~ 1,83 / 10, a teraz ma ~ 9,1 / 10. Cały kod jest teraz dość dobrze zgodny ze standardami. Przebiegłem to także na własne oczy, aktualizując zmienne nazwy, które poszły ... hmm ... nie tak i szukałem sekcji do refaktoryzacji.
W szczególności zadałem ostatnie pytanie na tej stronie w sprawie refaktoryzacji jednej z moich głównych funkcji, a teraz jest o wiele czystsze i znacznie krótsze: zamiast długiej, rozdętej, wypełnionej / jeśli jeszcze wypełnionej funkcji, jest teraz mniejsza niż połowa rozmiar i znacznie łatwiej zrozumieć, co się dzieje.
Kolejnym krokiem jest wdrożenie „testów jednostkowych”. Rozumiem przez to plik, który mogę uruchomić na moim głównym pliku, który przegląda wszystkie zawarte w nim funkcje za pomocą instrukcji aser i try / wyjątki, co prawdopodobnie nie jest najlepszym sposobem na zrobienie tego i powoduje wiele duplikatów kodu, ale będę czytał dalej i spróbuję wymyślić, jak to zrobić lepiej.
Znacząco zaktualizowałem również dokumentację, którą już napisałem, i dodałem dodatkowe pliki, takie jak arkusz kalkulacyjny programu Excel, dokumentacja i powiązany dokument do repozytorium github. Teraz wygląda to trochę jak prawdziwy projekt programistyczny.
Więc ... Myślę, że to wszystko do powiedzenia: dziękuję .
Odpowiedzi:
Jest to dość powszechny problem dla naukowców. Często to widziałem i zawsze wynika to z faktu, że programowanie jest czymś, co wybieracie jako narzędzie do wykonywania swojej pracy.
Twoje skrypty to bałagan. Idę wbrew zdrowemu rozsądkowi i powiem, że zakładając, że programujesz sam, nie jest tak źle! Nigdy więcej nie dotkniesz większości tego, co piszesz, więc spędzanie zbyt wiele czasu na pisaniu ładnego kodu zamiast tworzenia „wartości” (więc wynik skryptu) nie zrobi wiele dla ciebie.
Nadejdzie jednak czas, w którym musisz wrócić do czegoś, co zrobiłeś i zobaczyć dokładnie, jak coś działa. Ponadto, jeśli inni naukowcy będą musieli przejrzeć Twój kod, naprawdę ważne jest, aby był on tak jasny i zwięzły, jak to możliwe, aby każdy mógł go zrozumieć.
Twoim głównym problemem będzie czytelność, więc oto kilka wskazówek, jak poprawić:
Nazwy zmiennych:
Naukowcy uwielbiają używać zwięzłych notacji. Wszystkie równania matematyczne zwykle używają pojedynczych liter jako zmiennych i nie zdziwiłbym się, widząc wiele bardzo krótkich zmiennych w kodzie. To bardzo szkodzi czytelności. Kiedy wrócisz do swojego kodu, nie będziesz pamiętać, co reprezentują y, ja i x2, i spędzasz dużo czasu próbując to rozgryźć. Zamiast tego spróbuj jawnie nazwać zmienne, używając nazw, które reprezentują dokładnie to, czym są.
Podziel swój kod na funkcje:
Teraz, gdy zmieniłeś nazwę wszystkich swoich zmiennych, twoje równania wyglądają okropnie i mają wiele linii.
Zamiast pozostawiać je w głównym programie, przenieś to równanie do innej funkcji i odpowiednio je nazwij. Teraz zamiast dużej i pomieszanej linii kodu będziesz mieć krótkie instrukcje, które dokładnie powiedzą, co się dzieje i jakiego równania użyłeś. Poprawia to zarówno twój główny program, ponieważ nie musisz nawet patrzeć na faktyczne równanie, aby wiedzieć, co zrobiłeś, i sam kod równania, ponieważ w osobnej funkcji możesz nazwać swoje zmienne, jak chcesz, i wrócić do bardziej znane pojedyncze litery.
W tym myśleniu postaraj się znaleźć wszystkie fragmenty kodu, które coś reprezentują, zwłaszcza jeśli jest to coś, co musisz zrobić wiele razy w kodzie, i podziel je na funkcje. Dowiesz się, że Twój kod będzie szybko łatwiejszy do odczytania i że będziesz mógł korzystać z tych samych funkcji bez pisania więcej kodu.
Lukier na torcie, jeśli te funkcje są potrzebne w większej liczbie programów, możesz po prostu stworzyć dla nich bibliotekę, a będziesz mieć je zawsze dostępne.
Zmienne globalne:
Kiedy byłem początkujący, pomyślałem, że to świetny sposób na przekazywanie danych potrzebnych w wielu punktach mojego programu. Okazuje się, że istnieje wiele innych sposobów przekazywania informacji, a jedyne, co robią zmienne globalne, to przyprawianie ludzi o bóle głowy, ponieważ jeśli przejdziesz do przypadkowego punktu programu, nigdy nie dowiesz się, kiedy ta wartość była ostatnio używana lub edytowana, i śledzenie go będzie uciążliwe. Staraj się ich unikać, gdy tylko jest to możliwe.
Jeśli twoje funkcje muszą zwrócić lub zmodyfikować wiele wartości, utwórz klasę z tymi wartościami i przekaż je jako parametr, lub spraw, aby funkcja zwróciła wiele wartości (z nazwanymi krotkami) i przypisz te wartości do kodu wywołującego.
Kontrola wersji
Nie poprawia to bezpośrednio czytelności, ale pomaga wykonać wszystkie powyższe czynności. Ilekroć wprowadzasz jakieś zmiany, zobowiązuj się do kontroli wersji (lokalne repozytorium Git będzie wystarczające), a jeśli coś nie działa, spójrz na to, co zmieniłeś lub po prostu wycofaj! Ułatwi to refaktoryzację kodu i będzie siatką bezpieczeństwa, jeśli przypadkowo coś zepsujesz.
Mając to wszystko na uwadze, możesz napisać przejrzysty i bardziej efektywny kod, a także szybciej znaleźć możliwe błędy, ponieważ nie będziesz musiał przedzierać się przez gigantyczne funkcje i niechlujne zmienne.
źródło
Fizyk tutaj. Byłem tam
Argumentowałbym, że twój problem nie dotyczy wyboru narzędzi lub paradygmatów programowania (testowanie jednostkowe, OOP, cokolwiek innego). Chodzi o nastawienie , sposób myślenia. Fakt, że twoje zmienne nazwy są na początku dobrze wybrane, a ostatecznie są gówno, ujawnia dość. Jeśli myślisz o swoim kodzie jako „uruchom raz, a następnie wyrzuć”, to nieuchronnie będzie to bałagan. Jeśli myślisz o tym jako o dziele rzemiosła i miłości, będzie pięknie.
Uważam, że istnieje tylko jeden przepis na napisanie czystego kodu: napisz go dla człowieka, który go przeczyta, a nie dla tłumacza, który go uruchomi. Tłumacz nie dba o to, czy Twój kod jest bałaganem, ale obchodzi go czytelnik .
Jesteś naukowcem Prawdopodobnie możesz poświęcić dużo czasu na polerowanie artykułu naukowego. Jeśli twój pierwszy projekt wygląda na zawiły, przebudujesz go, dopóki logika nie popłynie w najbardziej naturalny sposób. Chcesz, aby koledzy go przeczytali i przekonali się, że argumenty są jasne. Chcesz, aby Twoi uczniowie mogli się z tego uczyć.
Pisanie czystego kodu jest dokładnie takie samo. Pomyśl o swoim kodzie jako szczegółowym objaśnieniu algorytmu, który tylko przypadkowo zdarza się do odczytu maszynowego. Wyobraź sobie, że zamierzasz opublikować go jako artykuł, który ludzie będą czytać. Zamierzasz nawet pokazać to na konferencji i poprowadzić publiczność po linii. Teraz przećwicz prezentację . Tak, linia po linii ! Żenujące, prawda? Więc posprzątaj swoje slajdy (err ... mam na myśli kod) i powtórz próbę. Powtarzaj, aż będziesz zadowolony z wyniku.
Byłoby jeszcze lepiej, jeśli po próbach możesz pokazać swój kod prawdziwym ludziom, a nie tylko wyobrażonym ludziom i swojemu przyszłemu. Przechodzenie przez nią linia po linii nazywa się „chodzeniem po kodzie” i nie jest to głupia praktyka.
Oczywiście wszystko to kosztuje. Napisanie czystego kodu zajmuje dużo więcej czasu niż napisanie niepotrzebnego kodu. Tylko Ty możesz ocenić, czy korzyści przewyższają koszty w konkretnym przypadku użycia.
Jeśli chodzi o narzędzia, powiedziałem wcześniej, że nie są one tak ważne. Gdybym jednak musiał wybrać jeden, powiedziałbym, że kontrola wersji jest najbardziej przydatna.
źródło
Kontrola wersji prawdopodobnie zapewni Ci najwyższy zwrot z każdej zainwestowanej złotówki. Nie służy tylko do przechowywania długoterminowego, jest świetny do śledzenia krótkoterminowych eksperymentów i powrotu do ostatniej działającej wersji, przechowywania notatek po drodze.
Kolejne najbardziej przydatne są testy jednostkowe. Rzeczą w testach jednostkowych jest to, że nawet podstawy kodu z milionami wierszy kodu są testowane jednostkowo po jednej funkcji na raz. Testy jednostkowe wykonuje się na małym poziomie, na najniższym poziomie abstrakcji. Oznacza to, że zasadniczo nie ma różnicy między testami jednostkowymi napisanymi dla małych baz kodu a testami używanymi dla dużych. Jest ich po prostu więcej.
Testy jednostkowe to najlepszy sposób, aby powstrzymać się od zepsucia czegoś, co już działało, gdy naprawisz coś innego, lub przynajmniej powiedzieć ci szybko, kiedy to zrobisz. Są one w rzeczywistości bardziej przydatne, gdy nie jesteś tak wykwalifikowanym programistą, albo nie wiesz, jak lub nie chcesz pisać bardziej szczegółowego kodu, który jest tak skonstruowany, aby błędy były mniej prawdopodobne lub bardziej oczywiste.
Pomiędzy kontrolą wersji a pisaniem testów jednostkowych, kod stanie się znacznie bardziej przejrzysty. Po osiągnięciu płaskowyżu można nauczyć się innych technik czystszego kodowania.
źródło
Prawdopodobnie sam byś to wymyślił, ale jeśli musisz „ gdzieś to wszystko zapisać w pliku tekstowym ”, nie używasz systemu kontroli wersji w pełni. Użyj czegoś takiego jak Subversion, git lub Mercurial i napisz dobrą wiadomość zatwierdzenia przy każdym zatwierdzeniu, a będziesz miał dziennik, który służy plikowi tekstowemu, ale nie można go oddzielić od repozytorium.
Poza tym korzystanie z kontroli wersji jest najważniejszą rzeczą, którą możesz zrobić z powodu, o którym żadna z istniejących odpowiedzi nie wspomina: odtwarzalności wyników . Jeśli możesz użyć wiadomości z dziennika lub dodać notatkę do wyników z numerem rewizji, możesz być pewien, że będziesz w stanie zregenerować wyniki, a będziesz w lepszej pozycji, aby opublikować kod na papierze.
Testowanie jednostek nigdy nie jest konieczne, ale jest użyteczne, jeśli (a) kod jest wystarczająco modułowy, aby można było testować jednostki, a nie całość; (b) możesz tworzyć testy. Idealnie byłoby, gdybyś mógł ręcznie napisać oczekiwany wynik, zamiast generować go za pomocą kodu, chociaż generowanie go za pomocą kodu może przynajmniej dać testy regresji, które pokażą, czy coś zmieniło jego zachowanie. Zastanów się, czy testy są bardziej podatne na błędy niż testowany kod.
OOP to narzędzie. Użyj go, jeśli to pomaga, ale nie jest to jedyny paradygmat. Zakładam, że tak naprawdę znasz programowanie proceduralne: jeśli tak jest, to w opisanym kontekście myślę, że przydałoby Ci się więcej studiując programowanie funkcjonalne niż OOP, aw szczególności dyscyplinę unikania skutków ubocznych, tam gdzie to możliwe. Python można pisać w bardzo funkcjonalnym stylu.
źródło
Na studiach napisałem sam kod wymagający algorytmu. To trochę trudne orzechy do zgryzienia. Mówiąc grubo, wiele konwencji programistycznych opiera się na idei umieszczania informacji w bazie danych, pobierania ich we właściwym czasie, a następnie masowania tych danych w celu przedstawienia ich użytkownikowi, zwykle przy użyciu biblioteki do dowolnej matematyki lub matematyki. algorytmiczne części tego procesu. W przypadku tych programów wszystko, co słyszałeś o OOP, dzielenie kodu na krótkie funkcje i czynienie wszystkiego łatwo zrozumiałym na pierwszy rzut oka, tam gdzie to możliwe, jest doskonałą radą. Ale to nie do końca działa w przypadku kodu obciążonego algorytmem lub kodu, który implementuje złożone obliczenia matematyczne i niewiele więcej.
Jeśli piszesz skrypty do wykonywania obliczeń naukowych, prawdopodobnie masz w pracy zapisane równania lub algorytmy. Jeśli używasz nowych pomysłów, które odkryłeś sam, mam nadzieję, że opublikujesz je w swoich własnych artykułach. W takim przypadku reguła jest następująca: Chcesz, aby Twój kod czytał tak dużo, jak to możliwe, opublikowane równania. Oto odpowiedź na Software Engineering.SE z ponad 200 głosami popierającymi to podejście i wyjaśniającymi, jak to wygląda: Czy istnieje wymówka dla krótkich nazw zmiennych?
Innym przykładem jest kilka świetnych fragmentów kodu w Simbody , narzędziu do symulacji fizyki wykorzystywanym do badań i inżynierii fizyki. Te fragmenty mają komentarz pokazujący równanie używane do obliczeń, a następnie kod, który odczytuje jak najbliżej implementowanych równań, jak to możliwe.
ContactGeometry.cpp
:ContactGeometry_Sphere.cpp
:źródło
λ
lubφ
zamiast brzydkiegolambda_
lubphy
...Tak więc moją codzienną pracą jest publikacja i konserwacja danych badawczych dla systemu University of California. Kilku ludzi wspomniało o odtwarzalności i myślę, że to jest właśnie ten zasadniczy problem: udokumentowanie kodu w sposób, w jaki dokumentujesz wszystko, czego ktoś potrzebuje, aby odtworzyć eksperyment, a najlepiej napisanie kodu, który ułatwi to komuś innemu. odtworzyć eksperyment i sprawdzić wyniki pod kątem źródeł błędów.
Ale coś, o czym nie wspomniałem, co uważam za ważne, polega na tym, że agencje finansujące coraz częściej patrzą na publikację oprogramowania jako część publikacji danych oraz na uczynienie publikacji oprogramowania wymogiem otwartej nauki.
W tym celu, jeśli chcesz czegoś konkretnego, skierowanego raczej do badaczy niż do zwykłych programistów, nie mogę wystarczająco polecić organizacji Software Carpentry . Jeśli możesz wziąć udział w jednym z ich warsztatów , świetnie; jeśli masz tylko czas / dostęp do przeczytania niektórych artykułów na temat najlepszych praktyk w dziedzinie naukowego przetwarzania danych , to też dobrze. Z tego ostatniego:
Ogólny zarys zalecanych przez nich praktyk:
Artykuł szczegółowo opisuje każdy z tych punktów.
źródło
Osobista odpowiedź:
robię dużo skryptów również do celów naukowych. W przypadku mniejszych skryptów po prostu staram się przestrzegać ogólnych dobrych praktyk programistycznych (tj. Używając kontroli wersji, ćwicząc samokontrolę przy użyciu nazw zmiennych). Jeśli po prostu piszę coś, aby szybko otworzyć lub wizualizować zestaw danych, nie zawracam sobie głowy OOP.
Odpowiedź ogólna:
„To zależy”. Jeśli jednak zastanawiasz się, kiedy zastosować koncepcję programowania lub paradygmaty, oto kilka rzeczy do przemyślenia:
# 1: Zapoznaj się z tym, co tam jest:
Mimo że „tylko” piszesz skrypty (i naprawdę zależy ci tylko na komponencie naukowym), powinieneś poświęcić trochę czasu na poznanie różnych koncepcji i paradygmatów programowania. W ten sposób możesz mieć lepsze pojęcie o tym, czego powinieneś / nie powinieneś chcieć używać i kiedy. To może brzmieć nieco zniechęcająco. Być może nadal masz pytanie: „Od czego zacząć / od czego zacząć?” Staram się wyjaśnić dobry punkt wyjścia w następnych dwóch punktach.
# 2: Zacznij naprawiać to, co wiesz, że jest złe:
osobiście zacznę od rzeczy, o których wiem, że są złe. Zdobądź kontrolę nad wersją i zacznij dyscyplinować się, aby być lepszym dzięki tym nazwom zmiennych (jest to poważna walka). Naprawianie tego, co wiesz, że jest złe, może wydawać się oczywiste. Jednak z mojego doświadczenia wynika, że naprawienie jednej rzeczy prowadzi mnie do czegoś innego i tak dalej. Zanim się zorientowałem, odsłoniłem 10 różnych rzeczy, które robiłem źle i wymyśliłem, jak je naprawić lub jak wdrożyć je w czysty sposób.
# 3: Znajdź partnera programistycznego:
jeśli „zaczynanie od nowa” nie wiąże się z podjęciem formalnych zajęć, rozważ nawiązanie współpracy z programistą i poproszenie go o sprawdzenie kodu. Nawet jeśli nie rozumieją naukowej części tego, co robisz, być może będą w stanie powiedzieć ci, co możesz zrobić, aby uczynić kod bardziej eleganckim.
# 4: Poszukaj konsorcjów:
Nie wiem, w jakim obszarze naukowym się znajdujesz. Ale w zależności od tego, co robisz w świecie naukowym, spróbuj poszukać konsorcjów, grup roboczych lub uczestników konferencji. Sprawdź, czy istnieją jakieś standardy, nad którymi pracują. Może to prowadzić do niektórych standardów kodowania. Na przykład wykonuję wiele prac geoprzestrzennych. Przeglądanie dokumentów konferencyjnych i grup roboczych zaprowadziło mnie do Open Geospatial Consortium . Jedną z rzeczy, które robią, jest praca nad standardami rozwoju geoprzestrzennego.
Mam nadzieję że to pomogło!
Uwaga dodatkowa: Wiem, że użyłeś OOP jako przykładu. Nie chciałem, żebyś myślał, że utknąłem tylko na tym, jak radzić sobie z pisaniem kodu za pomocą OOP. Po prostu łatwiej było napisać odpowiedź, kontynuując ten przykład.
źródło
Polecam trzymać się zasady uniksowej: Keep It Simple, Stupid! (POCAŁUNEK)
Lub, mówiąc inaczej: Rób jedną rzecz na raz i rób to dobrze.
Co to znaczy? Przede wszystkim oznacza to, że twoje funkcje powinny być krótkie. Każda funkcja, która nie może być w pełni zrozumiana w celu, użyciu i implementacji w ciągu kilku sekund, jest zdecydowanie za długa. Prawdopodobnie robi kilka rzeczy naraz, z których każda powinna być funkcją własną. Więc podziel to.
Jeśli chodzi o linie kodu, moja heurystyka jest taka, że 10 linii to dobra funkcja, a wszystko powyżej 20 jest najprawdopodobniej badziewiem. Inni ludzie mają inną heurystykę. Ważną częścią jest ograniczenie długości do czegoś, co można właściwie uchwycić w jednej chwili.
Jak dzielisz długą funkcję? Najpierw poszukaj powtarzających się wzorców kodu. Następnie rozłóż te wzorce kodu, nadaj im opisową nazwę i obserwuj, jak kod się kurczy . Naprawdę najlepszym refaktoryzowaniem jest refaktoryzacja, która zmniejsza rozmiar kodu.
Jest to szczególnie prawdziwe, gdy dana funkcja została zaprogramowana za pomocą funkcji kopiuj-wklej. Ilekroć widzisz taki powtarzający się wzór, od razu wiesz, że prawdopodobnie powinien on zostać przekształcony we własną funkcję. Jest to zasada „ nie powtarzaj się” (DRY) . Za każdym razem, gdy naciskasz kopiuj-wklej, robisz coś złego! Zamiast tego utwórz funkcję.
Niektóre funkcje mogą być długie, ponieważ wykonują kilka różnych czynności jedna po drugiej. Nie są to naruszenia DRY, ale można je również podzielić. Rezultatem jest często funkcja wysokiego poziomu, która wywołuje garść funkcji, które realizują poszczególne kroki pierwotnych funkcji. Zasadniczo zwiększy to rozmiar kodu, ale dodane nazwy funkcji działają cuda, czyniąc kod bardziej czytelnym. Ponieważ teraz masz funkcję najwyższego poziomu, której wszystkie kroki są wyraźnie nazwane. Również po tym podziale jest jasne, który krok działa na których danych. (Argumenty funkcji. Nie używasz zmiennych globalnych, prawda?)
Dobrą heurystyką dla tego rodzaju podziału funkcji sekcyjnych jest zawsze, gdy masz ochotę napisać komentarz sekcji lub gdy znajdziesz kod sekcji w swoim kodzie. Jest to najprawdopodobniej jeden z punktów, w których należy podzielić funkcję. Komentarz do sekcji może również służyć do inspirowania nazwy nowej funkcji.
Zasady KISS i DRY mogą zabrać Cię daleko. Nie musisz zaczynać od OOP itp., Często możesz osiągnąć wielkie uproszczenia, po prostu stosując te dwa. Jednak na dłuższą metę opłaca się wiedzieć o OOP i innych paradygmatach, ponieważ zapewniają one dodatkowe narzędzia, których można użyć, aby poprawić kod programu.
Na koniec zapisz każdą akcję z zatwierdzeniem. Uwzględniasz coś w nowej funkcji, to jest zatwierdzenie . Łączysz dwie funkcje w jedną, ponieważ naprawdę robią to samo, to jest zatwierdzenie . Jeśli zmienisz nazwę zmiennej, jest to zatwierdzenie . Zobowiązuj się często. Jeśli mija dzień, a ty się nie popełniasz, prawdopodobnie zrobiłeś coś złego.
źródło
Zgadzam się z innymi, że kontrola wersji rozwiąże wiele problemów od razu. Konkretnie:
Powiedziałbym: nie przemyśl tego: po prostu użyj git. Trzymaj się prostych poleceń (np. Tylko jednej
master
gałęzi), być może użyj GUI i powinieneś być w porządku. Jako bonus możesz użyć gitlab, github itp. Do darmowego publikowania i tworzenia kopii zapasowych;)Powodem, dla którego napisałem tę odpowiedź, było poruszenie dwóch rzeczy, których możesz spróbować, o których nie wspomniałem powyżej. Pierwszym jest użycie twierdzeń jako lekkiej alternatywy dla testów jednostkowych. Testy jednostkowe zwykle siedzą „na zewnątrz” testowanej funkcji / modułu / czegokolwiek: zazwyczaj wysyłają pewne dane do funkcji, odbierają wynik z powrotem, a następnie sprawdzają niektóre właściwości tego wyniku. Jest to ogólnie dobry pomysł, ale może być niewygodny (szczególnie w przypadku kodu „wyrzucania”) z kilku powodów:
Asercje nie mają tych wad, ponieważ są sprawdzane podczas normalnego wykonywania programu. W szczególności:
Jako czynnik podaje się szybkość, w którym to przypadku sprawdzanie asercji może być niepożądane w tej pętli (ale nadal przydatne do sprawdzania konfiguracji i późniejszego przetwarzania). Jednak prawie wszystkie implementacje asercji umożliwiają ich wyłączenie; na przykład w Pythonie można je najwyraźniej wyłączyć, uruchamiając z tą
-O
opcją (nie wiedziałem o tym, ponieważ nigdy wcześniej nie czułem potrzeby wyłączania moich twierdzeń). Polecam, aby pozostawić je nadomyślnie; jeśli cykl kodowania / debugowania / testowania zwalnia, być może lepiej będzie przetestować mniejszy podzbiór danych lub wykonać mniejszą liczbę iteracji podczas symulacji lub cokolwiek innego. Jeśli skończysz z wyłączaniem asercji w uruchomieniach nietestowych ze względu na wydajność, pierwszą rzeczą, którą zalecam, jest sprawdzenie, czy faktycznie są one źródłem spowolnienia! (Bardzo łatwo jest się łudzić, jeśli chodzi o wąskie gardła w wydajności)Moja ostatnia rada to skorzystanie z systemu kompilacji, który zarządza twoimi zależnościami. Osobiście używam do tego Nixa , ale słyszałem też dobre rzeczy o Guixie . Istnieją również alternatywy, takie jak Docker, które są znacznie mniej przydatne z naukowego punktu widzenia, ale być może są nieco bardziej znane.
Systemy takie jak Nix dopiero ostatnio stają się (trochę) popularne, a niektórzy mogą uważać je za przesadne z powodu „wyrzucania” kodu, jak to opisujesz, ale ich korzyść z odtwarzalności obliczeń naukowych jest ogromna. Rozważ skrypt powłoki do przeprowadzenia eksperymentu, taki jak ten (np.
run.sh
):Zamiast tego możemy przepisać go na „pochodną” Nix, jak to (np.
run.nix
):Między nimi
''...''
znajduje się kod bash, taki sam, jaki mieliśmy wcześniej, z tym wyjątkiem, że${...}
można go użyć do „łączenia” treści innych ciągów (w tym przypadku./.
, które rozwiną się do ścieżki zawierającej katalogrun.nix
).with import ...
Linia importuje Nix w standardowej biblioteki , która zapewniarunCommand
do uruchamiania kodu bash. Możemy uruchomić nasz eksperyment przy użyciunix-build run.nix
, który wyznaczy ścieżkę podobną do/nix/store/1wv437qdjg6j171gjanj5fvg5kxc828p-output.csv
.Co nas to kupuje? Nix automatycznie skonfiguruje „czyste” środowisko, które ma dostęp tylko do rzeczy, o które wyraźnie prosiliśmy. W szczególności nie ma dostępu do zmiennych takich jak
$HOME
żadne oprogramowanie systemowe, które zainstalowaliśmy. To uniezależnia wynik od szczegółów naszego aktualnego komputera, takich jak zawartość~/.config
lub wersje programów, które zainstalowaliśmy; AKA rzeczy, które uniemożliwiają innym osobom powielanie naszych wyników! Właśnie dlatego to dodałemcp
polecenie, ponieważ projekt nie będzie domyślnie dostępny. Może to wydawać się denerwujące, że oprogramowanie systemowe nie jest dostępne dla skryptu Nix, ale działa też w drugą stronę: nie potrzebujemy niczego zainstalowanego w naszym systemie (poza Nix), aby korzystać z niego w skrypcie; po prostu o to poprosimy, a Nix uruchomi się i pobierze / skompiluje / cokolwiek będzie konieczne (większość rzeczy zostanie pobrana jako pliki binarne; standardowa biblioteka jest również ogromna!). Na przykład, jeśli chcemy kilka konkretnych pakietów Python i Haskell, dla niektórych konkretnych wersji tych języków, a także inne śmieci (bo dlaczego nie?):To samo
nix-build run.nix
uruchomi to, pobierając wszystko, o co poprosiliśmy w pierwszej kolejności (i buforuj wszystko, na wypadek, gdybyśmy chcieli później). Dane wyjściowe (dowolny wywołany plik / katalog$out
) będą przechowywane przez Nix, czyli ścieżkę, którą wypluwa. Jest identyfikowany przez kryptograficzny skrót wszystkich danych wejściowych, o które poprosiliśmy (zawartość skryptu, inne pakiety, nazwy, flagi kompilatora itp.); te inne pakiety są identyfikowane skrótami ich danych wejściowych i tak dalej, że mamy pełny łańcuch proweniencji dla wszystkiego, od razu do wersji GCC, która skompilowała wersję GCC, która skompilowała bash, i tak dalej!Mam nadzieję, że pokazałem, że to dużo nas kupuje za kod naukowy i jest dość łatwo zacząć. Zaczynają też być traktowane bardzo poważnie przez naukowców, np. (Najlepszy hit w Google) https://dl.acm.org/citation.cfm?id=2830172, więc może być cenną umiejętnością do kultywowania (tak jak programowanie)
źródło
Bez wchodzenia w pełnoprawną kontrolę wersji + pakowanie + testy jednostkowe, które są dobrymi praktykami programistycznymi, które powinieneś spróbować w pewnym momencie osiągnąć, jednym z pośrednich rozwiązań, które moim zdaniem pasowałoby, jest użycie Jupiter Notebook . Wydaje się, że lepiej to integruje z obliczeniami naukowymi.
Ma tę zaletę, że możesz mieszać swoje myśli z kodem; wyjaśnianie, dlaczego podejście jest lepsze niż inne, i pozostawianie starego kodu w niezmienionej postaci w sekcji ad-hoc. Poza tym prawidłowe użycie komórek w naturalny sposób prowadzi do fragmentacji kodu i uporządkowania go w funkcje, które mogą pomóc w jego zrozumieniu.
źródło
Najlepsze odpowiedzi są już dobre, ale chciałem odpowiedzieć bezpośrednio na niektóre pytania.
Rozmiar kodu nie jest bezpośrednio związany z potrzebą testów jednostkowych. Jest to powiązane pośrednio: testy jednostkowe są bardziej wartościowe w złożonych bazach kodów, a małe bazy kodów nie są na ogół tak złożone jak większe.
Testy jednostkowe sprawdzają się w przypadku kodu, w którym łatwo popełnić błąd lub gdy będzie wiele implementacji tego kodu. Testy jednostkowe niewiele pomagają w bieżącym rozwoju, ale wiele robią, aby zapobiec popełnianiu błędów w przyszłości, które powodują, że istniejący kod nagle zachowuje się nieprawidłowo (nawet jeśli tego nie dotknąłeś).
Załóżmy, że masz aplikację, w której biblioteka A wykonuje wyrównywanie liczb, a biblioteka B stosuje twierdzenie Pitagorasa. Oczywiście, B zależy od A. Musisz naprawić coś w bibliotece A, i powiedzmy, że wprowadzasz błąd, który dzieli liczby na kwadraty, zamiast ich kwadratu.
Biblioteka B nagle zacznie źle się zachowywać, być może wprowadzając wyjątki lub po prostu dając nieprawidłowe wyniki. A kiedy spojrzysz na historię wersji biblioteki B, zobaczysz, że jest nietknięta. Problematycznym rezultatem końcowym jest to, że nie masz żadnych wskazówek co do tego, co może pójść źle, i będziesz musiał debugować zachowanie B, zanim zdasz sobie sprawę, że problem jest w A. To zmarnowany wysiłek.
Wprowadź testy jednostkowe. Testy te potwierdzają, że biblioteka A działa zgodnie z przeznaczeniem. Jeśli wprowadzisz błąd w bibliotece A, który powoduje, że zwraca on złe wyniki, wówczas testy jednostkowe go wychwycą. Dlatego nie utkniesz przy próbie debugowania biblioteki B.
Jest to poza twoim zasięgiem, ale w ciągłym rozwoju integracji testy jednostkowe są wykonywane za każdym razem, gdy ktoś popełni jakiś kod, co oznacza, że będziesz wiedział, że coś złamałeś jak najszybciej.
Szczególnie w przypadku skomplikowanych operacji matematycznych testy jednostkowe mogą być błogosławieństwem. Wykonujesz kilka przykładowych obliczeń, a następnie piszesz testy jednostkowe, które porównują obliczoną moc wyjściową i rzeczywistą moc wyjściową (w oparciu o te same parametry wejściowe).
Pamiętaj jednak, że testy jednostkowe nie pomogą ci stworzyć dobrego kodu, ale raczej go utrzymają . Jeśli zwykle piszesz kod raz i nigdy go nie odwiedzasz, testy jednostkowe będą mniej korzystne.
OOP to sposób myślenia o różnych podmiotach, na przykład:
Porównaj to z tym, jak funkcjonalny programista myśli o rzeczach:
Jabłka i Pomarańcze. Żadna z nich nie jest obiektywnie lepsza od drugiej. Jedną interesującą rzeczą do odnotowania jest to, że w przypadku OOP
Vendor
jest wspomniana dwa razy, ale odnosi się do tej samej rzeczy. Jednak dla programowania funkcyjnego,talktoVendor()
apayVendor()
to dwie odrębne rzeczy.To pokazuje różnicę między podejściami. Jeśli między tymi dwoma akcjami występuje dużo wspólnej logiki specyficznej dla dostawcy, wówczas OOP pomaga zmniejszyć duplikację kodu. Jeśli jednak nie ma wspólnej logiki między nimi, połączenie ich w jedną
Vendor
jest daremną pracą (a zatem programowanie funkcyjne jest bardziej wydajne).Najczęściej obliczenia matematyczne i naukowe są odrębnymi operacjami, które nie opierają się na niejawnej wspólnej logice / formułach. Z tego powodu programowanie funkcjonalne jest częściej używane niż OOP.
Twoje pytanie sugeruje, że definicja „dobrego, czystego kodu” zmienia się niezależnie od tego, czy zajmujesz się programowaniem naukowym, czy pracujesz nad większymi projektami (zakładam, że masz na myśli przedsiębiorstwo).
Definicja dobrego kodu nie zmienia się. Konieczność uniknięcia złożoności (które mogą być wykonywane przez pisanie czystego kodu), jednak nie zmienia.
Ten sam argument powraca tutaj.
Rozróżnia mnie tutaj, ale kiedy patrzysz wstecz na istniejący kod, patrzysz zarówno na matematykę, jak i programowanie. Jeśli któryś jest wymyślony lub złożony, będziesz miał trudności z jego odczytaniem.
Pomijając zasady OOP, głównym powodem, dla którego piszę klasy do przechowywania kilku wartości danych, jest to, że upraszcza deklarowanie parametrów metody i zwracanie wartości. Na przykład, jeśli mam wiele metod, które używają lokalizacji (para lat / lon), to szybko zmęczy mnie konieczność pisania
float latitude, float longitude
i wolę pisaćLocation loc
.Jest to jeszcze bardziej skomplikowane, gdy weźmie się pod uwagę, że metody generalnie zwracają jedną wartość (chyba że istnieją funkcje specyficzne dla języka w celu zwrócenia większej liczby wartości), a rzeczy takie jak lokalizacja chciałyby zwrócić dwie wartości (lat + lon). To zachęca do stworzenia
Location
klasy upraszczającej kod.Inną ciekawą rzeczą do odnotowania jest to, że możesz używać OOP bez mieszania wartości danych i metod. Nie każdy programista się tutaj zgadza (niektórzy nazywają to antypatternem), ale możesz mieć anemiczne modele danych, w których masz oddzielne klasy danych (pola wartości w sklepie) i klasy logiki (metody w sklepie).
To oczywiście widmo. Nie musisz być całkowicie anemiczny, możesz go użyć, jeśli uznasz to za stosowne.
Na przykład metoda, która po prostu łączy imię i nazwisko osoby, nadal może być umieszczona w
Person
samej klasie, ponieważ nie jest to tak naprawdę „logika”, ale raczej obliczona wartość.Klasa jest zawsze tak duża, jak suma jej pól. Biorąc przykład
Location
ponownie, który składa się z dwóchfloat
wartości, należy zauważyć, że pojedynczyLocation
obiekt zajmie tyle pamięci, co dwie osobnefloat
wartości.W tym sensie nie ma znaczenia, czy używasz OOP, czy nie. Ślad pamięci jest taki sam.
Sama wydajność również nie jest dużą przeszkodą do pokonania. Różnica między np. Używaniem metody globalnej lub metody klasowej nie ma nic wspólnego z wydajnością środowiska wykonawczego, ale ma wszystko wspólnego z generowaniem kodu bajtowego w czasie kompilacji.
Pomyśl o tym w ten sposób: to, czy napiszę przepis na ciasto w języku angielskim czy hiszpańskim, nie zmienia faktu, że ciasto zajmie 30 minut (= wydajność w czasie wykonywania). Jedyne, co zmienia język przepisu, to sposób, w jaki kucharz miesza składniki (= kompiluje kod bajtowy).
W przypadku Pythona nie trzeba jawnie kompilować kodu przed jego wywołaniem. Jeśli jednak nie wykonasz wstępnej kompilacji, kompilacja nastąpi podczas próby wykonania kodu. Kiedy mówię „środowisko uruchomieniowe”, mam na myśli samą realizację, a nie kompilację, która może poprzedzać wykonanie.
źródło
Korzyści z czystego kodu naukowego
Pomocne może być rozważenie kodu z perspektywy przyszłego programisty.
Z mojego doświadczenia,
Czysty kod powinien ułatwić weryfikację wyników
Możesz podzielić swój program, aby poszczególne algorytmy mogły być testowane osobno.
Unikaj pisania funkcji z sprzecznymi z intuicją skutkami ubocznymi, gdy jedna niepowiązana operacja powoduje, że inna operacja zachowuje się inaczej. Jeśli nie możesz tego uniknąć, udokumentuj, czego potrzebuje Twój kod i jak go skonfigurować.
Czysty kod może służyć jako przykładowy kod dla przyszłych programistów
Jasne komentarze (w tym te, które pokazują, jak należy wywoływać funkcje) i dobrze rozdzielone funkcje mogą mieć ogromną różnicę w tym, ile czasu zajmuje dopiero rozpoczynanie pracy (lub przyszłość użytkownika), aby zrobić coś pożytecznego z pracy.
Oprócz tego stworzenie prawdziwego „API” dla algorytmu może sprawić, że będziesz lepiej przygotowany, jeśli zdecydujesz się przekształcić skrypty w prawdziwą bibliotekę, z której będzie mógł korzystać ktoś inny.
Rekomendacje
Wzory matematyczne „Cytuj” za pomocą komentarzy.
John Smith Method from Some Book 1st Ed. Section 1.2.3 Pg 180
: jeśli znalazłeś formułę na stronie internetowej lub w gazecie, również to przytocz.Mądrze używaj komentarzy
Jeśli możesz poprawić czytelność swojego kodu, używając dobrych nazw zmiennych / nazw funkcji, zrób to najpierw. Pamiętaj, że komentarze pozostaną na zawsze, dopóki ich nie usuniesz, więc staraj się robić komentarze, które nie będą nieaktualne.
Użyj opisowych nazw zmiennych
xBar_AverageVelocity
Napisz kod, aby uruchomić program ze znanymi dobrymi i znanymi złymi danymi.
Myślę, że testowanie jednostkowe może być pomocne. Myślę, że najlepszą formą testowania jednostkowego kodu naukowego jest seria testów, które działają na znanych złych i dobrych danych.
Napisz kod, aby uruchomić algorytm i sprawdź, jak daleko wynik odbiega od oczekiwanych. Pomoże to znaleźć (potencjalnie bardzo złe i trudne do znalezienia) problemy, w których przypadkowo utrwalisz kod powodujący fałszywie dodatni wynik lub popełnisz błąd, który powoduje, że funkcja zawsze zwraca tę samą wartość.
Pamiętaj, że można to zrobić na dowolnym poziomie abstrakcji. Na przykład możesz przetestować cały algorytm dopasowania wzorca lub przetestować funkcję, która oblicza odległość między dwoma wynikami w procesie optymalizacji. Najpierw zacznij od obszarów, które są najbardziej istotne dla twoich wyników i / lub części kodu, które najbardziej Cię interesują.
Ułatw dodawanie nowych przypadków testowych, rozważ dodanie funkcji „pomocnika” i efektywnie uporządkuj dane wejściowe. Może to oznaczać zapisanie danych wejściowych do pliku, aby można było łatwo ponownie uruchomić testy, ale należy bardzo uważać, aby uniknąć fałszywych wyników pozytywnych lub stronniczych / trywialnie rozwiązanych przypadków testowych.
Zastanów się nad użyciem czegoś takiego jak cross-validation , zobacz ten post na cross- validation , aby uzyskać więcej informacji.
Użyj kontroli wersji
Polecam korzystanie z kontroli wersji i hosting repozytorium na stronie zewnętrznej. Istnieją witryny, które będą hostować repozytoria za darmo.
Zalety:
Zachowaj ostrożność podczas kopiowania / wklejania kodu
Kopiowanie / wklejanie kodu pozwala zaoszczędzić czas, ale jest to jedna z najniebezpieczniejszych rzeczy, które możesz zrobić, zwłaszcza jeśli jest to kod, którego sam nie napisałeś (np. Jeśli jest to kod od kolegi).
Gdy tylko uruchomisz i przetestujesz kod, zalecam bardzo ostrożne przejrzenie go, aby zmienić nazwy zmiennych lub skomentować wszystko, czego nie rozumiesz.
źródło
Narzędzia handlu są zwykle wymyślane, aby rozwiązać potrzebę. Jeśli potrzebujesz, skorzystaj z narzędzia, jeśli nie, najprawdopodobniej nie musisz.
W szczególności programy naukowe nie są celem końcowym, są środkiem. Piszecie program, aby rozwiązać problem, który macie teraz - nie spodziewacie się, że ten program będzie używany przez innych (i będzie musiał być utrzymany) za dziesięć lat. Samo to oznacza, że nie musisz myśleć o żadnym z narzędzi, które pozwalają obecnemu deweloperowi zapisywać historię innych, takich jak kontrola wersji, lub przechwytywać funkcje kodu, takie jak testy jednostkowe.
Co by ci wtedy przyniosło korzyści?
źródło
Oprócz dobrych rad już tutaj, możesz rozważyć cel swojego programowania, a zatem to, co jest dla Ciebie ważne.
„Chodzi o matematykę lub naukę, które testuję lub badam w ramach programowania”.
Jeśli celem jest eksperymentowanie i testowanie czegoś dla własnego zrozumienia, a wiesz, jakie powinny być wyniki, twój kod jest w zasadzie szybkim wyrzuceniem, a twoje obecne podejście może wystarczyć, choć może być ulepszone. Jeśli wyniki nie są zgodne z oczekiwaniami, możesz wrócić i sprawdzić.
Jeśli jednak wyniki kodowania informują o kierunku badań i nie wiesz, jakie powinny być wyniki, poprawność staje się szczególnie ważna. Błąd w kodzie może prowadzić do wyciągania błędnych wniosków z eksperymentu, co ma różne złe implikacje dla ogólnych badań.
W takim przypadku rozbicie kodu na łatwo zrozumiałe i weryfikowalne funkcje za pomocą testów jednostkowych da ci solidniejsze klocki konstrukcyjne, dające większe zaufanie do twoich wyników i może uratować cię od dalszej frustracji.
źródło
Mimo że kontrola wersji i testy jednostkowe służą do utrzymania uporządkowanego i funkcjonalnego kodu, nie pomagają w pisaniu czystszego kodu.
Jeśli chcesz powstrzymać się od pisania niechlujnego kodu, potrzebujesz narzędzia, które działa tam, gdzie zdarzają się bałagany: podczas pisania kodu. Popularny rodzaj narzędzia, które to robi, nazywa się linter. Nie jestem programistą python, ale wygląda na to, że Pylint może być dobrym rozwiązaniem.
Liniowiec sprawdza napisany kod i porównuje go z konfigurowalnym zestawem najlepszych praktyk. Jeśli linijka ma regułę, że zmienne muszą być
camelCase
, a ty ją zapiszeszsnake_case
, oznaczy to jako błąd. Dobre lintery mają reguły od „deklarowanych zmiennych należy użyć” do „Cyklomatyczna złożoność funkcji musi być mniejsza niż 3”.Większość edytorów kodu można skonfigurować tak, aby uruchamiały linijkę za każdym razem, gdy zapisujesz, lub po prostu podczas pisania, i wskazywały na problemy. Jeśli wpiszesz coś podobnego
x = 7
,x
zostanie podświetlone, wraz z instrukcją użycia dłuższej, lepszej nazwy (jeśli tak skonfigurowałeś). Działa to jak sprawdzanie pisowni w większości edytorów tekstu, co utrudnia ignorowanie i pomaga budować lepsze nawyki.źródło
Wszystko, co wymieniłeś, jest narzędziem w metaforycznym zestawie narzędzi. Jak wszystko w życiu, różne narzędzia są odpowiednie do różnych zadań.
W porównaniu z innymi dziedzinami inżynierii oprogramowanie działa z wieloma pojedynczymi elementami, które same w sobie są dość proste. Instrukcja przypisania nie ocenia się inaczej w zależności od wahań temperatury w pomieszczeniu.
if
Oświadczenie nie koroduje na miejsce i wracać to samo po pewnym czasie. Ale ponieważ poszczególne elementy są tak proste, a oprogramowanie stworzone przez ludzi, elementy te są łączone w coraz większe kawałki, aż wynik będzie tak duży i złożony, że osiągnie granice tego, co ludzie mogą mentalnie zarządzać.W miarę rozwoju projektów komputerowych ludzie je badali i tworzyli narzędzia do zarządzania tą złożonością. OOP jest jednym z przykładów. Coraz więcej abstrakcyjnych języków programowania to kolejny sposób. Ponieważ znaczna część pieniędzy na oprogramowanie robi więcej więcej , narzędzia do osiągnięcia tego są tym, co zobaczycie i przeczytacie. Ale wygląda na to, że te sytuacje cię nie dotyczą.
Więc nie myśl, że musisz to robić. Pod koniec dnia kod jest tylko środkiem do celu. Niestety, najlepszą perspektywą na to, co jest, a co nie jest właściwe, jest praca nad niektórymi większymi projektami, ponieważ o wiele trudniej jest wiedzieć, czego brakuje, gdy zestaw narzędzi jest twoim umysłem.
W każdym razie nie martwiłbym się, że nie użyję OOP ani innych technik, o ile twoje skrypty są małe. Wiele opisanych przez ciebie problemów to tylko ogólne profesjonalne umiejętności organizacyjne, tzn. Nietracenie starego pliku jest czymś, z czym muszą sobie poradzić wszystkie dziedziny.
źródło
Oprócz wszystkich dobrych podanych dotychczas sugestii, jedną z praktyk, których nauczyłem się z czasem i które uważam za niezbędne, jest bardzo swobodne dodawanie szczegółowych komentarzy do kodu. Jest to dla mnie najważniejsza rzecz, kiedy wracam do czegoś po długim czasie. Wyjaśnij sobie, co myślisz. Zajmuje to trochę czasu, ale jest stosunkowo łatwe i przeważnie bezbolesne.
Czasami mam dwa lub trzy razy więcej wierszy komentarzy niż w kodzie, szczególnie gdy koncepcje lub techniki są dla mnie nowe i nie potrafię się wytłumaczyć.
Wykonuj kontrolę wersji, popraw swoje praktyki itp. ... wszystkie powyższe. Ale wytłumacz sobie wszystko, kiedy będziesz. Działa naprawdę dobrze.
źródło
Jakie cechy są ważne dla tego rodzaju programu?
Prawdopodobnie nie ma znaczenia, czy łatwo go utrzymać, czy rozwinąć, ponieważ są szanse, że tak się nie stanie.
Prawdopodobnie nie ma znaczenia, jak wydajna jest.
Prawdopodobnie nie ma znaczenia, czy ma świetny interfejs użytkownika, czy jest zabezpieczony przed złośliwymi atakami.
Może mieć znaczenie, że jest czytelny: że ktoś czytający Twój kod może łatwo przekonać się, że robi to, co twierdzi.
To na pewno ma znaczenie, że jest poprawne. Jeśli program daje niepoprawne wyniki, to twoje naukowe wnioski wyskakują z okna. Ale musi tylko poprawnie przetworzyć dane wejściowe, o które tak naprawdę prosisz; naprawdę nie ma większego znaczenia, czy przewróci się, jeśli otrzyma ujemne wartości danych wejściowych, czy wszystkie wartości danych są dodatnie.
Ważne jest również to, że utrzymujesz pewien poziom kontroli zmian. Twoje wyniki naukowe muszą być powtarzalne, a to oznacza, że musisz wiedzieć, która wersja programu dała wyniki, które zamierzasz opublikować. Ponieważ jest tylko jeden programista, kontrola zmian nie musi być bardzo skomplikowana, ale musisz upewnić się, że możesz wrócić do punktu w czasie i odtworzyć swoje wyniki.
Więc nie martw się o paradygmaty programowania, orientację obiektową, elegancję algorytmiczną. Nie martw się o przejrzystość i czytelność oraz o możliwość śledzenia zmian w czasie. Nie martw się o interfejs użytkownika. Nie przejmuj się testowaniem każdej możliwej kombinacji parametrów wejściowych, ale wykonaj wystarczająco dużo testów, aby mieć pewność (i aby inni byli pewni), że twoje wyniki i wnioski są prawidłowe.
źródło
Pracowałem w podobnym środowisku z naukowcami, którzy piszą dużo kodu (matematyki / nauk ścisłych), ale ich postęp jest powolny z tych samych powodów, które opisujesz. Zauważyłem jednak jedną konkretną rzecz, która poszła dobrze, która moim zdaniem może ci również pomóc: zbudować i utrzymywać zbiór specjalistycznych bibliotek, których można używać w wielu projektach. Te biblioteki powinny zapewniać funkcje narzędziowe, dzięki czemu Twój projekt będzie specyficzny dla problematycznej domeny.
Na przykład, być może będziesz musiał poradzić sobie z wieloma transformacjami współrzędnych w twojej dziedzinie (ECEF, NED, lat / lon, WGS84 itp.), Więc funkcja taka
convert_ecef_to_ned()
powinna przejść do nowego projektu o nazwieCoordinateTransformations
. Poddaj projekt kontroli wersji i umieść go na serwerach swojego działu, aby inne osoby mogły go używać (i mam nadzieję, że go ulepszą). Następnie po kilku latach powinieneś mieć solidny zbiór bibliotek z projektami zawierającymi tylko kod specyficzny dla konkretnego problemu / dziedziny badań.Kilka bardziej ogólnych porad:
źródło
Oto moje opinie i bardzo duży wpływ na moją własną ścieżkę.
Kodowanie często rodzi dogmatyczne perspektywy, w jaki sposób należy robić rzeczy. Zamiast technik i narzędzi, myślę, że musisz spojrzeć na skumulowane wartości i koszty, aby wybrać odpowiednią strategię.
Pisanie dobrego, czytelnego, debugowalnego, solidnego kodu zajmuje dużo czasu i wysiłku. W wielu przypadkach, biorąc pod uwagę ograniczony horyzont planowania, nie warto tego robić (paraliż analizy).
Jeden kolega miał ogólną zasadę; jeśli robisz zasadniczo to samo po raz trzeci, zainwestuj wysiłek, w przeciwnym razie właściwa jest szybka i brudna robota.
Testowanie jest niezbędne, ale w przypadku jednorazowych projektów wystarczy samo spojrzenie w oczy. Do wszystkiego, co istotne, niezbędne są testy i infrastruktura testowa. Wartość polega na tym, że uwalnia cię podczas kodowania, a koszt polega na tym, że jeśli test koncentruje się na konkretnej implementacji, wówczas testy również wymagają konserwacji. Testy przypominają również o tym, jak mają działać rzeczy.
W przypadku moich własnych skryptów jednorazowych (często takich jak sprawdzanie poprawności prawdopodobieństwa lub podobnych) znalazłem dwie małe rzeczy bardzo przydatne: 1. Dołącz komentarz pokazujący, w jaki sposób kod jest używany. 2. Dołącz krótki opis, dlaczego napisałeś kod. Te rzeczy są strasznie oczywiste, gdy piszesz kod, ale oczywistość marnuje się z czasem :-).
OOP polega na ponownym użyciu kodu, abstrakcji, enkapsulacji, faktorowaniu itp. Bardzo przydatne, ale łatwo się zgubić, jeśli tworzenie wysokiej jakości kodu i projektu nie jest twoim ostatecznym celem. Produkcja wysokiej jakości produktów wymaga czasu i wysiłku.
źródło
Chociaż uważam, że testy jednostkowe mają swoje zalety, mają one wątpliwą wartość dla rozwoju naukowego - często są po prostu zbyt małe, aby oferować dużą wartość.
Ale naprawdę lubię testy integracyjne kodu naukowego:
Wyizoluj małą część kodu, która mogłaby działać samodzielnie, np. Potok ETL. Następnie napisz test, który dostarcza danych, uruchom potok etl (lub tylko krok), a następnie sprawdź, czy wynik odpowiada twoim oczekiwaniom. Podczas gdy testowana porcja może zawierać dużo kodu, test wciąż zapewnia wartość:
Często używam tej techniki i często uzyskuję względnie czytelną funkcję główną, ale podfunkcje są często dość długie i brzydkie, ale można je szybko modyfikować i zmieniać z powodu solidnych granic we / wy.
źródło
Zwykle pracuję na bardzo dużej bazie. Używamy wszystkich narzędzi, o których wspomniałeś. Ostatnio zacząłem pracować nad niektórymi skryptami Pythona dla pobocznego projektu. Są to najwyżej od kilkudziesięciu do kilkuset linii. Z przyzwyczajenia oddałem swoje skrypty do kontroli źródła. Jest to przydatne, ponieważ mogę tworzyć gałęzie do testowania eksperymentów, które mogą nie działać. Mogę rozwidlać, jeśli muszę powielić kod i zmodyfikować go w innym celu. To pozostawia oryginał taktowny na wypadek, gdy będę musiał go ponownie wydać.
Do „testów jednostkowych” mam tylko kilka plików wejściowych, które mają na celu wygenerowanie znanego wyjścia, które sprawdzam ręcznie. Prawdopodobnie mógłbym to zautomatyzować, ale wydaje mi się, że zajęłoby to więcej czasu niż zaoszczędziłbym, robiąc to. Prawdopodobnie zależy to od tego, jak często muszę modyfikować i uruchamiać skrypty. Tak czy inaczej, jeśli to działa, zrób to. Jeśli to więcej kłopotów niż jest warte, nie marnuj czasu.
źródło
W przypadku pisania kodu - podobnie jak w przypadku pisania w ogólności - główne pytanie brzmi:
Rzeczy, takie jak formalne wytyczne kodowania, nie mają sensu, gdy jesteś jedynym odbiorcą.
Z drugiej strony pomocne byłoby napisanie kodu w taki sposób, aby Twoja przyszłość była w stanie go zrozumieć od razu.
Tak więc „dobry styl” byłby tym, który najbardziej ci pomoże. To, jak ten styl powinien wyglądać, to odpowiedź, której nie mogę udzielić.
Myślę, że nie potrzebujesz testów OOP ani testów jednostkowych dla plików 150 LOC. Dedykowany VCS byłby interesujący, jeśli masz jakiś ewoluujący kod. W przeciwnym razie a
.bak
robi lewę. Te narzędzia są lekarstwem na chorobę, której możesz nawet nie mieć.Być może powinieneś napisać kod w taki sposób, aby nawet czytając go w stanie nietrzeźwym, potrafiłeś go czytać, rozumieć i modyfikować.
źródło