KISS („zachowaj to proste, głupie” lub „utrzymaj to proste głupie”, patrz np. Tutaj ) jest ważną zasadą w tworzeniu oprogramowania, nawet jeśli najwyraźniej wywodzi się z inżynierii. Cytowanie z artykułu w Wikipedii:
Najlepszym przykładem tej zasady jest historia, w której Johnson przekazał zespołowi inżynierów garść narzędzi, z wyzwaniem, że projektowany przez nich samolot odrzutowy musi być naprawiany przez przeciętnego mechanika w terenie w warunkach bojowych przy użyciu tylko tych narzędzi. Stąd „głupi” odnosi się do związku między sposobem, w jaki rzeczy się psują, a zaawansowaniem dostępnym do ich naprawy.
Gdybym chciał zastosować to w dziedzinie tworzenia oprogramowania, zastąpiłbym „odrzutowce” na „oprogramowanie”, „przeciętnego mechanika” na „przeciętnego programistę” i „w warunkach bojowych” na „w ramach oczekiwanego rozwoju / utrzymania oprogramowania warunki ”(terminy, ograniczenia czasowe, spotkania / przerwy, dostępne narzędzia itd.).
Jest więc powszechnie akceptowanym pomysłem, że należy starać się, aby program był prosty (lub głupi , jeśli pominiesz przecinek), aby łatwo później nad nim popracować.
Ale czy zasadę KISS można zastosować także do projektowania języka programowania? Czy znasz jakieś języki programowania, które zostały zaprojektowane specjalnie z myślą o tej zasadzie, tj. „Pozwalają przeciętnemu programistowi w przeciętnych warunkach pracy pisać i utrzymywać jak najwięcej kodu przy minimalnym wysiłku poznawczym”?
Jeśli cytujesz jakiś konkretny język, byłoby dobrze, gdybyś mógł dodać link do jakiegoś dokumentu, w którym projektanci wyraźnie wyrażają ten zamiar. W każdym razie chciałbym dowiedzieć się o (udokumentowanych) intencjach projektantów niż o twoich osobistych opiniach na temat określonego języka programowania.
Odpowiedzi:
Kiedy myślę o minimalizmie, myślę o Lisp i Go . W Lisp masz tylko funkcje i listy, które są tak proste, jak tylko możesz (cóż, jest ich trochę więcej, ale cokolwiek). Myślę jednak, że sprawa Go jest bardziej interesująca.
Go został zaprojektowany tak, aby był prosty (jest to przyzwoity odczyt). Termin, którego używają, to „ortogonalność funkcji”, co oznacza, że każda funkcja powinna być dodana tylko wtedy, gdy zapewnia coś naprawdę wyjątkowego. Wydaje się, że wynika to z zaangażowania autorów ( przychodzą mi na myśl Russ Cox i Rob Pike ) z Plan9 , który był prostą wersją systemu UNIX. (Jeśli interesuje Cię minimalistyczny design, dobrze jest przeczytać artykuł Roba Pike'a na temat prostego systemu okienkowego .)
Oto kilka prostych przykładów składni:
Tylko jedna konstrukcja pętli
Pętla może wyglądać następująco:
Nieskończona pętla
Podczas pętli
Tradycyjny dla pętli
Foreach loop
Przełącznik wielofunkcyjny
Wielokrotny zwrot
Interfejsy
Osadzanie
Kanały
Może być stosowany do implementacji semaforów
Służy do przekazywania wiadomości między wątkami
Może być używany do obsługi zdarzeń asynchronicznych
Wniosek
Nie będę wchodził w każdą część składni, ale mam nadzieję, że zobaczysz, co potrafi minimalizm. Język jest intrygujący nie dlatego, że dodaje mnóstwo nowych funkcji, ale dlatego, że wykorzystuje najlepsze funkcje z innych języków bez żadnych dodatkowych elementów.
Zazwyczaj istnieje jeden „najlepszy” sposób rozwiązania problemu. Na przykład na liście mailingowej wielu użytkowników skarży się na brak generycznych. Po dyskusji zdają sobie sprawę, że wszystko, co chcą zrobić, można zrobić za pomocą interfejsów. Przeczytaj o skutecznym przejściu na przykłady składni idiomatycznej.
Zaletą języków KISS jest możliwość pisania kodu idiomatycznego, ponieważ styl kodu jest ograniczony przez język. Na przykład w Go nie można napisać czegoś takiego:
Musisz użyć nawiasów klamrowych:
Istnieje wiele innych przykładów tego w składni, co ułatwia czytanie kodu innych osób.
Zalety języka KISS w porównaniu z atrakcyjnymi językami:
źródło
for i=1 to 10
lub python:for item in group
for i = 1 to 10
polega na tym, czyi
kiedykolwiek będzie 10. Może to zależeć od języka (bash zawiera 10, python nie). Tradycyjna pętla for jest uniwersalna.Myślę, że Zen Pythona powie, dlaczego Python jest prostym językiem o wiele lepszym niż mogę:
Edytuj w odpowiedzi na @Giorgio
Jak mówi twoje pytanie,
Python jest dla mnie tym, co natychmiast przychodzi mi na myśl. Projekt Pythona jest bezpośrednią odpowiedzią na metodologię Perla, słynnego „Jest więcej niż jeden sposób na to”. To wspaniałe, ponieważ pozwala programistom bardzo łatwo pisać kod, ale nie pomaga w utrzymaniu. Po tym, jak wcześniej zarządziłem (bardzo słabo napisany) program napisany w Perlu, doceniam Python zmuszający zarówno dobre praktyki kodowania, jak i zwięzły język do gardła.
Python również nie zmusza cię do przestrzegania jednej określonej metodologii podczas pisania programów. Mogę zdecydować się na ścisły styl programowania obiektowego lub napisać prosty skrypt do wykonania sekwencyjnego. Nie trzeba inicjować klasy, a następnie wywołać
main()
metodę tak, jak w Javie, trzeba to zrobić. (Również drukowanie w standardzie Python jest wspaniałe, ale jest to raczej punkt zerowy).Wreszcie, metodologia „Dołączone baterie” polegająca na włączeniu ekspansywnej standardowej biblioteki z językiem jest cudowna. Zamiast przeszukiwać zewnętrzne repozytorium pakietów, większość tego, czego potrzebuję, jest już zawarta w języku. Fajnie jest też mieć zewnętrzne repozytorium, ale nie trzeba go przekopywać, aby wykonać podstawową operację.
źródło
import this
polecenia.Głównym kluczem do utrzymania „prostoty” jest rozpoznanie, kiedy złożoność będzie konieczna, i posiadanie części systemu, które najlepiej sobie z tym poradzą, zrobią to. Posiadanie jednego rodzaju odniesienia do obiektu, który nie czyni rozróżnienia między niezmiennymi wartościami, zmiennymi wartościami i bytami, sprawia, że Java jest „prosta”, nie eliminuje potrzeby rozróżniania wartości od bytów; po prostu pozbawia programistów narzędzi, które mogą im w tym pomóc.
Mówiąc bardziej ogólnie, jeśli ktoś chce, aby język programowania lub funkcja obsługiwały wiele przypadków użycia, należy upewnić się, że nie będzie żadnych sytuacji, w których różne zachowania byłyby odpowiednie w różnych przypadkach użycia, ale kompilator nie byłby w stanie stwierdzić je osobno. Dodanie większej liczby typów do języka lub frameworka może wydawać się komplikacją, ale w wielu przypadkach może faktycznie ułatwić.
Rozważmy na przykład bałagan reguł otaczających typy podpisane i niepodpisane w C. Złożoność tych reguł wynika z faktu, że niektóre kody używają niepodpisanych typów liczb całkowitych do reprezentowania liczb, podczas gdy inny kod używa ich do reprezentowania członków zawijanego pierścienia algebraicznego (konkretnie, zestaw liczb całkowitych przystających mod 2ⁿ). Reguły konwersji typów zachowują się w sposób, który czasem jest odpowiedni dla jednego użycia, a czasem w sposób odpowiedni dla drugiego. Posiadanie osobnych typów zawijania i nie zawijania podwoiłoby liczbę typów całkowitych, ale mogłoby uprościć związane z nimi reguły:
Dowolny nie będący liczbą całkowitą typ dowolnego rozmiaru może być przypisany do pierścienia o dowolnym rozmiarze; pierścień można przypisać tylko do pierścienia o równym lub mniejszym rozmiarze.
Operacje inne niż operatory relacyjne, obejmujące niecałkowitą liczbę całkowitą i pierścień, pośrednio przekonwertują liczbę całkowitą na typ pierścienia.
Pierścienie mogą być jednoznacznie rzutowane na liczby lub na większe pierścienie; wartość niepodpisanego pierścienia jest najmniejszą nieujemną liczbą całkowitą, która po dodaniu do zera pierścienia dałaby wartość pierścienia. Wartość podpisanego pierścienia jest liczbą całkowitą najmniejszej wielkości, która po dodaniu do zera pierścienia dałaby wartość pierścienia, przy czym wartość ujemna jest preferowana w przypadku remisu.
Poza wymienionymi powyżej, pierścienie są ograniczone do operacji z pierścieniami tego samego rozmiaru lub mniejszymi.
Operacje na liczbach całkowitych innych niż pierścieniowe różnych typów powinny wyodrębnić liczby do typu, który może pomieścić wszystkie wartości dowolnego argumentu, lub powinien zostać odrzucony przez kompilator, jeśli nie istnieje odpowiedni typ
Zdefiniowanie typów pierścieni wydaje się podwoić liczbę typów całkowitych, ale znacznie uprościłoby pisanie przenośnego kodu. Używanie tego samego typu bez znaku dla liczb i dzwonków zmniejsza liczbę typów, ale prowadzi do skomplikowanych reguł, które praktycznie uniemożliwiają napisanie wydajnego przenośnego kodu.
źródło
Prawdopodobnie Tcl został opracowany zgodnie z tymi wytycznymi. Cały język można opisać tylko w 12 regułach na jednej stronie podręcznika . Jest niezwykle prosty i spójny.
Twórca Tcl twierdził, że jako pierwotne cele:
Z „ Historii Tcl ” - http://www.tcl.tk/about/history.html
źródło
Jeśli język jest poprawiony w projekcie z powodu KISS, nie może się rozwijać. Język, który nie może rosnąć, umrze.
W poniższym wideo Guy Steele sprytnie wyjaśnia, że język programowania musi się rozwijać i dlaczego. Jeśli zastosujesz KISS, to w jaki sposób język może rosnąć, ponieważ po zwolnieniu jego zestaw narzędzi jest naprawiony i nigdy nie może się zmieniać.
To godzinne wideo, ale warte obejrzenia. Jeśli nie wiesz, kim jest Guy Steele, naprawdę powinieneś mówić o projektowaniu języka.
Wybrałem ten film jako odpowiedź, ponieważ uważam, że zastosowanie KISS do projektowania języka jest w ogóle złe i mam nadzieję, że zobaczenie przemówienia znanej osoby zajmującej się projektowaniem języka pomoże poszerzyć twoje zrozumienie przyszłości projektowania języka.
Ponieważ przyszedłeś tutaj, aby dowiedzieć się o projektowaniu języka, a ja dałem ci powód, aby nie korzystać z KISS, to sprawiedliwe, że wskazałem coś, co znajduję w pomocy w projektowaniu języka. Wymiary poznawcze notacji
EDYTOWAĆ
Kiedy napisałem powyższą odpowiedź, była ona oparta na rozumowaniu: jeśli silnik może być obsługiwany tylko za pomocą stałego zestawu narzędzi, to moje przeformułowanie tego znaczenia w odniesieniu do projektu języka jest takie, że język nie może się zmienić po wydaniu. Komentarze wskazują, że nie o to chodziło. Pozwólcie, że przedstawię tę zmodyfikowaną odpowiedź, która będzie bardziej zgodna ze zmienionym zrozumieniem.
Jeśli przyjrzymy się wymiarom poznawczym notacji, to dowiadujemy się, że istnieje wiele konkurencyjnych wymiarów związanych z projektowaniem języka, a nie tylko prostota, a jeśli zbyt mocno skoncentrujesz się na jednym, cierpisz w innych. Z pytaniem, skupia się w dużej mierze na prostotę (KISS) Dobra, a wspierane przez znanego ludu projektu językowego, I przedstawiła mowę przez Guy Steele , aby pokazać, że stara się utrzymać wyłącznie prosty projekt wpłynie na inne wymiary. Co ważniejsze, staram się przekazać, że trzeba spojrzeć na wiele wymiarów i zważyć ich zalety i wady, a nie tylko prostotę.
źródło
Oto duży cytat z Hardcore Visual Basic Bruce'a McKinneya , który z kolei przekazuje słowa do ust projektantów BASIC, Kemeny i Kurtz . Podkreśla moje.
źródło
Dobrze, że wyjaśniłeś, co rozumiesz przez „prosty”, ponieważ moim zdaniem prosty język programowania to taki, który ma minimalną składnię i kilka funkcji (Scheme, Forth, ML), co nie przekłada się bezpośrednio na twoją definicję. Myślę, że naprawdę szukasz projektowania języków z myślą o RAD (szybkie tworzenie aplikacji), a jest ich całkiem sporo. Zobacz ten wątek StackOverflow, na przykład: /programming/66227/what-is-the-best-multi-platform-rad-language
źródło
Dziwi mnie, że nikt jeszcze nie wspominał o C, mimo że stawia on prostotę na pierwszym miejscu na kilka ważnych sposobów, często w tak radykalny sposób, że programiści nie doceniają prostoty:
Nie ma ukrytej magii. Jeśli piszesz
a + b
w C, masz gwarancję, że skompiluje się co najwyżej do jednej instrukcji asemblera.Nawet w stosunkowo prostych językach, takich jak Java, taka prosta instrukcja
a + b
może zająć kilka mikrosekund (jeśli zmienne są łańcuchami). Inne języki dodają do tego wiele, wiele więcej, dzięki ekstremalnemu przykładowi C ++, gdziea + b
może być przeciążony, aby pojawiały się różowe słonie. Nie w C: jeśli nie jest to wywołanie funkcji, nie zajmie to więcej niż kilka nanosekund. Ta przewidywalność działania jest jedną z kluczowych cech C i jest z pewnością formą prostoty.Typy danych są tak proste, jak mogą być, przy jednoczesnym opisywaniu wszystkich interesujących struktur danych, które warto zbudować w pamięci: istnieją tylko podstawowe typy, które procesor może obsłużyć + agregacja (
struct
) + powtarzanie (tablice) + referencje (wskaźniki) ).Prawdą jest, że pod tym względem różne języki oparte na seplenienie są znacznie prostsze niż C. Nie próbują jednak pozwolić programiście swobodnie manipulować pamięcią, podobnie jak C.
Ortogonalność funkcji: Możesz dowolnie łączyć funkcje i będą one działać zgodnie z oczekiwaniami. Wiele języków zawodzi, ponieważ niektóre konstrukcje pojawiają się tylko w określonych kontekstach.
Weźmy na przykład tablice o zmiennej długości w C i C ++: C zezwala na wszędzie czas działania, podczas gdy najbardziej liberalne żądania rozszerzenia standardu C ++ pozwalają tylko w pewnych kontekstach, takich jak tablice automatyczne, a nawet tylko w pierwszym wymiarze. Dzięki temu C może obsługiwać prawdziwe wielowymiarowe tablice o rozmiarach znanych tylko w czasie wykonywania, podczas gdy programiści C ++ są zmuszeni do pisania
data[k + (j + i*lineLength)*lineCount]
w kółko.Innym przykładem tego jest wskaźnik: Wskaźnik danych w C to tak naprawdę nic więcej lub mniej niż tylko zmienna zawierająca adres pamięci innej zmiennej. Ponieważ sam wskaźnik jest zmienną, podwójny wskaźnik jest dobrze zdefiniowaną rzeczą. To znaczy biorąc pod uwagę co
int
iint*
czym jest, jasne jest, coint**
musi być. Porównaj to z referencjami w C ++, w których absolutnie nie masz pojęcia, coint&&
ma znaczenieint
iint&
!)Prawdą jest, że właśnie ta prostota sprawiła, że C tak bardzo nienawidzi: prostota języka daje programistom więcej swobody niż jest dla nich dobra, co prowadzi do wielu problemów związanych z nieokreślonym zachowaniem i błędnymi wskazówkami. Zwłaszcza prostota ortogonalności, która pozwala programiście zdefiniować zmienną
int (*array[m])(struct foo* (*arg)[n])
tego typu, która ma tendencję do wywoływania bólów głowy u czytelników, ponieważ naprawdę złożone rzeczy mogą być wyrażone w bardzo zwięzłej formie przez liberalne połączenie kilku prostych cech . Jest to rodzaj prostoty, w której C wyróżnia się i która daje mu reputację trudnego języka.Ponadto prostota języka zmusza programistę do napisania o wiele więcej kodu niż języków bogatych w funkcje, zapewniając bardziej podatny grunt dla rozkwitów błędów. Niemniej jednak pozostaje najprostszym możliwym językiem wysokiego poziomu, jeśli twoim głównym celem jest zaprogramowanie prawdziwego komputera, a nie jakiejś maszyny wirtualnej.
źródło
Java Wikipedia - chociaż uproszczenie nie zostało wyraźnie powiedziane w Wikipedii, wielokrotnie wspomniano o uproszczeniu i było oryginalnym celem projektowym, ponieważ jedynym poważnym językiem zdolnym do OO (termin używany luźno) w tamtych czasach był C ++, który, jak wszyscy wiemy, jest potężny ale ma więcej niż kilka pułapek dla nieostrożnych.
JVM został pomyślany jako sposób na uproszczenie rozwoju na wielu platformach, a „Napisz raz uruchom w dowolnym miejscu” stało się mantrą Java na kilka lat - ponownie, celem było proste wdrożenie tego frameworka.
Uważam, że C # należy do tej kategorii uproszczenia języka.
źródło
Hm ... to jest trudne pytanie, na które należy odpowiedzieć „pozytywnie”, ponieważ kiedy myślę o prostocie projektowania języka programowania (i czym „łatwiej” pracować), od razu myślę o:
Istnieje wiele języków, które robią te rzeczy dobrze - ale w mojej głowie pojawia się język, który nie radzi sobie dobrze „jako język programowania”: PHP.
[Oświadczenie - napisałem PHP, a PHP jest nadal moim „idź do języka” dla prostych projektów internetowych. To jest krytyka miłości ...]
Po pierwsze, PHP ma się dobrze w środowisku, w którym zwykle działa na serwerach internetowych. Jest łatwy w konfiguracji, łatwy w utrzymaniu itp.
Gdzie walczę z PHP: kiedy chcesz zrobić coś „niezwykłego” - coś, czego zwykle nie robisz regularnie (w przypadku, gdy myślę, że to konsumowanie usługi internetowej SOAP - nie coś, co mam dużo z PHP), masz do czynienia z dwiema opcjami:
1) Różne rozszerzenia open source do PHP. Model obiektowy PHP jest na tyle luźny, że projektowanie interfejsu również nie jest zbyt spójne w zależności od biblioteki, od dewelopera do programisty. W konfrontacji z zestawem kodu, w którym ktoś korzystał z biblioteki, o której nigdy nie słyszałeś, spędzasz dużo czasu zastanawiając się, co to do cholery robi, ponieważ język pozwala na luźne tworzenie API / bibliotek.
2) Funkcje „wbudowane” - których jest wiele . Przeszedłem przez kilka króliczych dziur, albo znajdując inną bibliotekę, albo implementując trochę funkcjonalności, aby jakoś później się natknąć
impossiblyfound_basefunction()
Moim zdaniem prostota to konsekwencja.
źródło
Teraz podejście KISS do języków programowania jest zabawnym pojęciem, przynajmniej jeśli uważasz, że języki programowania są warstwą abstrakcji w zestawie instrukcji procesora itp. Jeśli nie zdefiniujesz dokładniej „KISS”. Mówię tu tylko, że wózek KISS jest w pełni zastosowany do samochodu.
Teraz inną interpretacją KISS może być coś w rodzaju „elegancko wykonane bez zbędnych ozdób i niezbyt skomplikowane”. Szczególnie można argumentować, że nie powinno być zbyt wielu konkretnych przypadków na podobne rzeczy itp. Zwykle matematyka jest całkiem dobra w sprowadzaniu rzeczy do swojej istoty, i - o dziwo - matematycy spędzili trochę czasu myśląc o programowaniu i komputerach .
Do programowania istnieją 2 dość znane modele abstrakcyjne:
Zabawne jest to: chociaż maszyna Turinga ma dość prosty układ, nie jest to system łatwy w obsłudze i nie sądzę, że kwalifikuje się do „inteligentnego KISS”. Ale Lambda Calculus ma więcej wspólnego z językami programowania, które znamy - a dzięki pionierskim funkcjom rachunku lambda Lisp i Scheme dotarł do wielu języków.
Lisp i Scheme są NAPRAWDĘ proste, przynajmniej pod względem składniowym. Składnia jest poważnym problemem związanym z językami programowania (prawdopodobnie dlatego są ciągle wymyślane na nowo). W przypadku C ++ ludzki mózg prawie nie jest w stanie przewidzieć, w jaki sposób kompilator interpretuje niektóre linie źródłowe).
Lisps całkowicie zmniejszają złożoność syntaktyczną, wprowadzając jedną wspólną formę poleceń:
Może to być wywołanie metody, takie jak
a także gałąź if, pętla itp.
(cały kod jest pseudo-Lisp / dialekt agnostyczny)
Formularz
można również interpretować jako listę
I to jest podstawa prostoty i piękna Lisps. Ponieważ listy zagnieżdżone (jak w
if
przykładzie instrukcji) stanowią drzewa i można je łatwo zrozumieć zarówno przez maszynę, jak i człowieka przed maszyną.Inną cechą Lisps są makra, nie będę wchodził tutaj w nieprzyzwoite szczegóły, ale ponieważ nie ma różnicy składniowej między normalnymi wywołaniami funkcji a "Składnią (jajko dla pętli, deklaracja zmiennej itp.), Wszystko, co parser musi obsłużyć w innych języki programowania) możesz stworzyć własną składnię. Makra to w istocie Manipulacje drzewem, które tworzą twój program.
Myślę, że Lisp ma KISS do programowania. To, że możesz manipulować składnią za pomocą makr, doprowadziło do zjawiska, które Lisp ewoluowało dość dynamicznie. Potrzebujesz nowej funkcji języka, takiej jak - powiedzmy orientacja obiektowa - po prostu napisz system OOP z makrami!
Podczas gdy C zostało przedłużone rondo 2 razy z funkcjami OOP (C ++, Obj. C), Lisp został przedłużony wiele razy, w końcu zwyciężył.
To kolejne dziwactwo na temat Lisp, ewoluuje (patrz Clojure i Clojurescript, aby uzyskać ciekawe nowe Mutacje lisp).
Ze względu na swoje właściwości KISS niektórzy preferują Lisps. Podobnie jak kontury Fogusa w jego projekcie języka edukacyjnego ( http://blog.fogus.me/2013/01/21/enfield-a-programming-language-designed-for-pedagogy/ )
źródło