Automatyczne programowanie: napisz kod, który pisze kod [zamknięty]


105

Po przeczytaniu książki The Pragmatic Programmer , jednym z argumentów, które uznałem za najbardziej interesujące, było „pisanie kodu, który pisze kod”.

Próbowałem przeszukać Internet, by znaleźć więcej wyjaśnień lub artykułów na ten temat, i chociaż znalazłem kilka dobrych artykułów na ten temat, wciąż nie znalazłem żadnej konkretnej implementacji kodu ani dobrych przykładów.

Wydaje mi się, że wciąż nie jest to tak powszechny argument, coś, co nie ma dokumentacji lub nie jest zaakceptowane przez tak wielu ludzi, i chciałbym dowiedzieć się więcej na ten temat.

Co sądzisz na ten temat? Czy to coś, co naprawdę zwiększy Twoją wydajność? Jakie są dobre zasoby na ten temat, wśród książek, blogów, pokazów slajdów itp.?


Niektóre przykłady kodu byłyby bardzo mile widziane, aby umożliwić mi lepsze zrozumienie jego implementacji.


Oto strona wiki na ten temat z różnymi istotnymi technikami programowania, takimi jak Meta Programowanie, Programowanie generatywne i Generowanie kodu.


32
Kiedyś napisałem kod, który napisał kod, który napisał kod ... :)
Benjol

9
@Benjol: Czy pisałeś w Lisp?
compman

11
Ponadto języki po stronie serwera robią to cały czas, generując HTML, CSS i JavaScript. Możesz mieć skrypt po stronie serwera, który tworzy skrypt po stronie serwera, który tworzy html z javascript, który tworzy więcej html, i nikt nie zwróci na to uwagi ze względu na jego powszechność .
zzzzBov

8
Jeśli jeszcze tego nie zrobiłeś, sprawdź serię artykułów IBM developerWorks: Sztuka metaprogramowania Część 1 , Część 2 i Część 3 .
John Tobler,

3
AtomWeaver ( atomweaver.com ) jest dobrym przykładem automatycznego programowania: Najpierw tworzysz mini-programy wielokrotnego użytku w Lua. Następnie modelujesz swój system, ponownie wykorzystując te zasoby. AtomWeaver następnie tka program Lua, który zawiera twoje „mini-generatory” w celu wygenerowania końcowego kodu źródłowego systemu. Następnie możesz ulepszyć swój model i ponownie wygenerować.
Rui Curado

Odpowiedzi:


49

W świecie Lisp dość często widuje się kod, który pisze kod, który pisze kod (i tak dalej). Tak więc każdy projekt Lisp lub Scheme o odpowiedniej wielkości będzie dobrym przykładem kodu. Polecam spojrzeć na kompilator Racket i źródła uruchomieniowe , a także na Bigloo , ich biblioteki są po prostu genialne.

Jeśli chodzi o produktywność: używam metaprogramowania jako dominującej techniki w prawie wszystkich moich pracach programistycznych, co wyraźnie pomaga, zarówno zmniejszając rozmiar kodu, jak i zwiększając jego czytelność. Kluczem jest używanie języków specyficznych dla domeny , a metaprogramowanie jest jednym z najbardziej wydajnych sposobów ich implementacji.


67

Wolę pójść trochę dalej i zamiast pisać kod, który pisze kod, piszę kod, który generuje obiekty, metody i funkcje. Można to osiągnąć na przykład za pomocą makr Lisp lub funkcji dynamicznej modyfikacji programu Ruby.

Mała różnica polega na tym, że nie kończysz się plikami źródłowymi, które zostały automatycznie wygenerowane. Zwykle pliki te nie są czytelne dla ludzi i nie można ich modyfikować, więc po co się z nimi przejmować. Nie podoba mi się pomysł powiększenia bazy kodu o coś, czego nie mogę kontrolować.

Jedną książką, którą lubiłem czytać na ten temat, był Metaprogramowanie Ruby (jeśli znasz język Ruby)


Edytuj po następującym pytaniu w komentarzu:

Dlaczego miałoby być użyteczne, że nadal muszę kodować kod generujący? Czy powinienem napisać kod zdolny do generowania różnych rzeczy w zależności od danych wejściowych użytkownika, aby móc go wielokrotnie używać?

Po pierwsze, metaprogramowanie nie jest celem, ale narzędziem. Nie używaj metaprogramowania, ponieważ „cool” lub „X powiedział, że każdy programista powinien go używać”.

Myślę, że dobrym powodem do użycia metaprogramowania jest uogólnienie jakiegoś wspólnego wzorca (wzorzec jako coś, który się powtarza), który znalazłeś w kodzie i którego nie mogą osiągnąć żadne inne zwykłe techniki programowania (dziedziczenie, wzorce projektowe itp.).

Jak powiedział Jordan , jednym z typowych przypadków użycia jest obsługa bazy danych i ORM (Object Relation Mapping). Jeszcze raz w Ruby powinieneś spojrzeć na ActiveRecord, który jest doskonałym przykładem metaprogramowania zastosowanego do ORM.

Jako ostatnia uwaga:

Nie myśl „Chcę zastosować metaprogramowanie, gdzie mogę to zastosować w swoim kodzie?”.

Pomyśl „Widzę ten wzór, który powtarza się w całym moim kodzie, nie mogę znaleźć sposobu, aby zmienić kod na coś mniejszego i bardziej przydatnego. Może metaprogramowanie może mi pomóc?”


3
@Jose: Najczęściej generujesz kod za pomocą szablonów. Jest na przykład prędkość apache (N-) lub szablony Visual Studio T4. Następnie masz program, który przekazuje metadane do twoich szablonów i tworzy nowe pliki. To całkiem proste i robię to cały czas, aby generować szkielety interfejsu użytkownika, byty itp.
Falcon

2
@Jose Faeti, przyjrzyj się makrom Lisp (lub Clojure lub Nemerle, w zależności od preferencji platformy).
SK-logic

1
Dodałbym, że metaprogramowanie może zastąpić jakiś wzorzec, taki jak polisa lub stan, ale bez kosztów w czasie wykonywania. Dotyczy to nie tylko problemów, których nie można osiągnąć przy zwykłym refaktoryzacji, ale czasem lepszej alternatywy.
deadalnix

1
@Jose Faeti: Widzę, że znasz trochę Pythona. Ma także możliwości metaprogramowania, chociaż tak naprawdę nie korzystałem z nich. Spójrz na niebezpiecznie zaawansowany Python PDF
Kit

3
@ Falcon: IMO to najgorszy sposób na wygenerowanie kodu; jest bardzo kiepski w przypadku języków bez wbudowanej funkcji metaprogramowania. Zamiast generować Java lub C #, lepiej byłoby napisać ten kod w języku JVM lub .NET wyższego poziomu.
kevin cline,

19

Co więcej, użyj kodu napisanego przez kogoś innego, który pisze kod za Ciebie.

Automatyzacja kodu jest ogólnie dobra dla ORM i innych kodów interakcji z bazami danych, i oczywiście do powtarzalnego, ale podobnego budowania kodu.

Oczywiście, jeśli budujesz wiele podobnie wyglądających klas, być może mógłbyś osiągnąć to samo w dynamicznym języku, ale dygresuję.

Obejmuje to wiele osób, chociaż często można znaleźć oprogramowanie oznaczone jako generatory kodu.

Zobacz firmy i produkty, takie jak CodeSmith i MyGeneration, lub przejrzyj ten artykuł w Wikipedii: http://en.wikipedia.org/wiki/Comparison_of_code_generation_tools


6
Nie jest lepiej. Twój cenny mały, tak bardzo własny kod nie może być właściwie zarządzany przez narzędzie do generowania kodu innego bloka, ponieważ ten inny blob nie wie nic o twoich szczegółach. Najbardziej produktywnym zastosowaniem metaprogramowania jest implementacja języków specyficznych dla domeny - i jak sugeruje nazwa, są one specyficzne dla twojej bardzo problematycznej domeny, nie mogą być zaimplementowane przez nikogo poza tobą.
SK-logic

@ SK-logic: co z kodem wygenerowanym przez ORM? Jest generowany przez inne narzędzie / bibliotekę i nadal spełnia wiele potrzeb projektu.
David

@David, szczerze mówiąc, nie jestem do końca przekonany co do ogólnych ORM. W przeszłości miałem z nimi tak wiele problemów, często uciekając się do implementacji moich małych, specyficznych ORM.
SK-logic

1
@Jordan, wszystkie te narzędzia są zbyt szczegółowe (a co gorsza - oparte na tekście , tj. Gorsze z założenia). Mówię o właściwym metaprogramowaniu.
SK-logic

1
@AtillaOzgur, mogą być „bardzo dobrzy”, prawda. Ale nie są lepsze niż eDSL. Samodzielne generowanie kodu jest oczywiście znacznie bardziej ograniczone i znacznie mniej elastyczne niż metaprogramowanie makr.
SK-logic

16

Jednym z klasycznych przykładów jest lex i yacc. Ich głównym celem jest uniknięcie znoju pisania jakiegokolwiek parsera. Po drodze znacznie przyspieszają tworzenie złożonych parserów z wieloma regułami i stanami, a także unikają błędów zaskoczenia popełnianych przez ludzi.

Taki jest także pomysł c, który jest narzędziem do pisania asemblera. To samo dotyczy każdego języka wysokiego poziomu, który chcesz nazwać. W przypadku narzędzi, które piszą kod, istnieje kilka prostych paradygmatów.

Właściwe IDE pomaga, udostępniając dokumentację na wyciągnięcie ręki, inteligentne automatyczne uzupełnianie i fragmenty kodu. IDE zawierają również różne szablony, więc nie musisz uruchamiać programu od zera. Istnieją programy do pobierania schematu uml i wykańczania klas w języku wysokiego poziomu.

Wreszcie możesz napisać własne narzędzia do generowania kodu w ramach swojego zestawu problemów. Tak zaczęły się Lex i Yacc. Z tego powodu istnieje jakikolwiek język specyficzny dla danej domeny. Tworzysz niektóre elementy składowe, które opisują twoje rozwiązanie w łatwiejszym do zrozumienia kodzie, kończąc typowe czynności lub skomplikowane sekcje za pomocą prostych poleceń. Nie szukasz rozwiązania każdego problemu, wystarczy łatwiejsze zdefiniowanie konkretnego problemu.

W pewnym sensie wszystko, co robisz ponad warstwą binarną, to automatyzacja kodu.


To naprawdę ładny widok. Podsumowując, jest to kolejna z wielu metod, które programiści próbują wykorzystać, aby ułatwić sobie działanie i skupić się na wyższym poziomie kodowania, zamiast na szczegółach kodu składniowego.
Jose Faeti

1
@Jose Faeti Artykuł w Wikipedii en.wikipedia.org/wiki/Automatic_programming zawiera linki do różnych różnych narzędzi, jeśli jesteś zainteresowany bardziej szczegółowymi informacjami. Sugerowałbym także przeczytanie lex i yacc, ponieważ jest tam nieco więcej dokumentacji i opisu.
Spencer Rathbun

W wystarczająco mocnych językach (np. C ++ w przeciwieństwie do C) narzędzia zewnętrzne, takie jak lex i yacc, nie są potrzebne.
kevin cline,

YACC nie pisze „żadnego parsera”. Zapisuje jeden konkretny rodzaj parsera (LALR), który jest bardzo trudny do uzyskania bez automatycznej pomocy. Istnieje inny typ parsera (zejście rekurencyjne), który jest znacznie łatwiejszy do napisania i poprawienia, a odpowiednio łatwiejszy do odczytania i zrozumienia, co się dzieje.
Mason Wheeler,

@MasonWheeler Rodzaj parsera dotyczył gramatyki, którą można stworzyć w celu rozwiązania problemów w szerokim, nieprecyzyjnym znaczeniu. Czytając go rok później, nie jest tak jasne, jak bym tego chciał. Nie jestem jednak pewien, czy zgadzam się z tobą, że parsery LL (*) są łatwiejsze do pisania i używania.
Spencer Rathbun,

13

Metaprogramowanie

Metaprogramowanie jest kontrowersyjną techniką w wielu sklepach. Powodem jest, jak każde potężne narzędzie, wielkość pomocy lub krzywdy jest duża.

Plusy

  • Bardziej ekspresyjny, mniej kodu do pisania i konserwacji (często o rząd wielkości lub więcej)
  • Spójność, bardziej spójne zachowanie w klasie problemów, które rozwiązujesz za pomocą kodu
  • Wydajność, mniej kodu dla rozwiązania większej przestrzeni problemowej

Cons

  • Złożoność może być bardzo skomplikowana, mimo że kodu jest mniej
  • Bezpieczeństwo, kiedyś bezpieczeństwo typu i analiza statyczna zostaną poświęcone
  • Błędy wpływają bardziej, małe błędy będą miały większy wpływ

Jestem wielkim fanem metaprogramowania, ale robię to od dłuższego czasu. Dla mnie kompromis polegający na zmniejszeniu rozmiaru kodu i spójnym zachowaniu bardziej niż rekompensuje ryzyko. Mniej kodu oznacza mniej błędów, mniej kodu do utrzymania, i zazwyczaj mogę bardzo szybko dodać duże elementy funkcjonalności.

Nie oznacza to jednak, że uważam, że wszyscy programiści powinni się w to zaangażować. Widziałem i musiałem naprawiać duże problemy powstałe w wyniku metaprogramowania. Zwykle od momentu, gdy ludzie, którzy nie rozumieją tej koncepcji i próbowali rozszerzyć funkcjonalność lub po prostu naprawić błąd. Wymaga szczególnego sposobu myślenia, który jest przynajmniej zorientowany na szczegóły. Pytanie o zastosowanie technik metaprogramowania powinno być decyzją zespołu . Jeśli masz członków zespołu, którzy nie rozumieją, nie masz do tego temperamentu lub są po prostu przeciwni, żaden z zespołów nie powinien używać metaprogramowania.


Dzięki za przydatne uwagi! Czy możesz zasugerować mi naprawdę proste i podstawowe zadanie, które będę w stanie wykonać za pomocą metaprogramowania, co pozwoli mi zaoszczędzić czas w porównaniu do normalnego kodowania, na przykład kodu?
Jose Faeti

haha, przypominam sobie błąd, który miałem kilka lat temu w GCC. 162 wiersze, aby umieścić komunikat o błędzie na moim ekranie. Metaprogramowanie rekurencyjne FTW!
deadalnix

6
Złożoność metaprogramowania jest wysoce przereklamowana. Nie ma w tym absolutnie nic skomplikowanego, o ile korzystasz z odpowiednich narzędzi. A DSL są o wiele łatwiejsze do debugowania i obsługi niż typowy kod typu „kocioł”. Nie rozumiem też, dlaczego należy poświęcać bezpieczeństwo typu - jest dokładnie odwrotnie, DSL mogą mieć również specyficzne dla domeny, bardzo wydajne systemy typów.
SK-logic

2
@ SK-logic: Nie wszystkie języki dobrze obsługują metaprogramowanie. Czasami więc poświęca się bezpieczeństwo typu (np. C) . Również metaprogramowanie to nie tylko DSL. Obejmuje to takie elementy, jak programowanie stylu wysyłki, generyczne, curry, inspekcja obiektów, dynamiczna aplikacja itp. Jeśli chodzi o złożoność, myślę, że łatwo nam (osobom z doświadczeniem w metaprogramowaniu) powiedzieć, że to nie jest skomplikowane. Widziałem inne problemy ze zrozumieniem wszystkich przypadków, w których kod zostanie wykonany. Zależy to głównie od ich doświadczenia i zastosowanej techniki.
dietbuddha

@dietbuddha, czy mógłbyś wyjaśnić, dlaczego ktoś poświęca bezpieczeństwo swojego własnego DSL, bez względu na to, jak to jest realizowane? Możesz napisać ad hoc interpreter w czystym C z silnym systemem typów (zobacz na przykład Uściski). Możesz napisać generator kodu kierujący na C, który sam sprawdza wszystkie typy, nie polegając na systemie typów języka docelowego. Dla złożoności: większość ludzi robi to w niepotrzebnie skomplikowany sposób, podczas gdy wszystkie te same metodologie projektowania można zastosować do generowania kodu, jak w „normalnym” programowaniu. Prawie nie jest wymagana nowa wiedza.
SK-logic

9

Większość kodu pisze kod. Na przykład kod php pomaga pisać HTML. Biblioteka php pdo pomaga pisać wywołania SQL. Plikowe funkcje wejścia / wyjścia zapisują kod do komunikacji z systemem operacyjnym. Nawet zwykłe wywołanie funkcji jest odniesieniem do innego bloku kodu, który jest wykonywany. Tak więc wywołania funkcji piszą kod.

Mówiąc ogólnie, możemy myśleć o komputerach jako pisaniu kodów, które zapisują kody rekurencyjnie, tworząc stos, który kończy się, gdy napotyka na fizyczną rzeczywistość kodów podłączonych do sprzętu.


3
Nie nazwałbym html językiem programowania. Jest to składnia dokumentów
Simon Bergot

3
@ Simon jest interesującym punktem. Istnieje wiele różnych mocy ekspresji dla różnych kodów, których używamy. Kod może pisać w słabszym języku, silniejszym języku lub własnym języku.
Ben Haley

5

Jak to zrobić, różni się w zależności od twoich wymagań. Zakładając, że używasz generowania kodu statycznego, możesz samodzielnie napisać całą infrastrukturę lub użyć istniejącego generatora, takiego jak CodeSmith lub MyGeneration. Korzystając z nich, wystarczy napisać wymagane szablony.

Mój ostatni projekt z tym związany był kilkoma podstawowymi ekranami CRUD ASP.NET (do tego dobre jest generowanie kodu). Proces poszedł zdefiniować encje jako metadane w plikach xml. Napisz szablony obejmujące różne wymagane artefakty (klasy jednostek, repozytoria, klasy usług, kontrolki asp.net, strony asp.net itp.). Uruchom proces generowania i stylizuj dane wyjściowe.

Pisanie szablonów wiąże się z pewnym nakładem, ale można je ponownie wykorzystać w kolejnych podobnych projektach. Podobnie zmiany w podstawowych danych są obsługiwane przez zmianę metadanych i ponowne uruchomienie generowania, dzięki czemu zmiany są prostsze i szybsze do wdrożenia.

Co do testowania. Ponieważ jest to system oparty na szablonie, będziesz musiał poświęcić trochę czasu na wstępne sprawdzenie poprawności wyniku procesu, jeśli szablon jest nieprawidłowy, wszystkie dane wyjściowe z tego szablonu będą podobnie błędne. Gdy będziesz zadowolony z tego, możesz także użyć generatorów kodu do stworzenia podstawowych testów z metadanych xml, które możesz następnie rozszerzyć o specjalne przypadki. Pamiętaj jednak, że może być konieczne ręczne przetestowanie kodu w celu spełnienia określonych wymagań, generowanie kodu ogranicza pracę, ale nie eliminuje jej całkowicie.


5

W naszej firmie korzystamy z narzędzi, które faktycznie generują klasy C ++ lub C # z danymi pobranymi z Internetu. Klasy te są kontenerami danych i zawierają dużą liczbę obiektów na listach.


Coś takiego jak fragmenty kodu znalezione w IDE, na przykład Visual Studio?
Jose Faeti

@Jose Nasze narzędzie to tylko aplikacja do konwersji danych HTML na klasę. Dlatego zamiast pobierać dane za każdym razem, gdy aplikacja się uruchamia, pobieramy je raz i tworzymy z niego klasę.
Holli

5

Metaprogramowanie jest częścią programowania od dłuższego czasu. Weź pod uwagę nie tylko narzędzia takie jak SWIG lub projektanci WYSIWYG, które tworzą kod, ale także narzędzia w języku, takie jak preprocesor C, a nawet szablony C ++ i ogólne C # / Java - nie wspominając już o Reflection.

W rzeczywistości można argumentować, że każdy kompilator jest tylko kolejnym metaprogramem - przyjmują tekst programu i kod wyjściowy maszyny lub kodu VM. A życie bez kompilatorów? Sowa


Zgadza się, ale w jaki sposób można go wdrożyć we własnym języku programowania, aby faktycznie zwiększyć wydajność? Tego mi brakuje.
Jose Faeti

5

Oto konkretny przykład z mojej przeszłości.

Pracowałem na stronie, która miała około 50 MB kodu źródłowego Delphi, używając BDE do dostępu do danych. Chcieli przejść na korzystanie z Direct Oracle Access, aby umożliwić aktualizację Oracle do najnowszej wersji obsługiwanej przez BDE (8i, jeśli dobrze pamiętam).

Zamiast więc zmusić zespół programistów do pracy nad każdą formą i modułem danych zmieniającym ręcznie każdy komponent, napisałem skrypt PERL, który:

  1. Analizował DFM (plik formularza) i identyfikował wszystkie obiekty TQuery, TTable, TStoredProcedure i TDatabase - przechowując elementy na liście.

  2. Analizował PAS (kod) i identyfikował użycie obiektów - czy TQueries robiły aktualizacje, czy wybierały? Ponadto zidentyfikował wszelkie obiekty utworzone w kodzie zamiast upuszczenia na formularz w IDE.

  3. Przepisz DFM i PAS odpowiednio zmieniając typy obiektów (np. TTable -> TOracleDataSet z właściwością SQL ustawioną na „wybierz * z” itp.) I wywołaniami metod. W razie potrzeby dodano także dodatkowe wywołania metod w celu zamknięcia, otwarcia i ustawienia parametrów.

W skrócie, 3 tygodnie pracy nad ulepszeniem skryptu, aby działał na różnych aplikacjach napisanych przez różne zespoły o różnych stylach kodowania, zamiast pierwotnego szacunku ponad 5 programistów pracujących przez 6 miesięcy.

A powodem, dla którego nawet pomyślałem o zastosowaniu tego podejścia, było przeczytanie The Pragmatic Programmer


To świetnie, jestem teraz w Perlu od kilku dni i już stworzyłem narzędzia zwiększające produktywność do generowania podstawowych obszarów roboczych do tworzenia stron WWW, ze wszystkimi katalogami, plikami itp., Po prostu wpisując „stwórz obszar roboczy”! :)
Jose Faeti

1
@Jose To jest pomysł. Używaj języków skryptowych do automatyzacji powtarzających się czynności. Może to być jednorazowe zwiększenie wydajności 8-krotnie lub, jak w twoim przypadku, czasochłonne działanie, które zrobisz ponownie.
mcottle,

4

Pytasz o przykłady ....

Pracując z SQL, nie powinieneś bezpośrednio zmieniać bazy danych, ale zamiast tego powinieneś wykonywać skrypty, które wprowadzają dowolne zmiany, w tym zmiany strukturalne w bazie danych (dodawanie tabel, kolumn, kluczy podstawowych, ograniczeń itp.) . Dość często trzeba wykonać tę samą akcję przeciwko wielu tabelom lub kolumnom w tym samym czasie, a wykonywanie ich jedna po drugiej byłoby żmudne, krótki skrypt, który generuje większy skrypt, który robi to, co chcesz, może być prawdziwym oszczędzacz czasu.

Na przykład, zanim typ danych DATE został wprowadzony do MS SQl Server, jedynym wyborem dla kolumny daty był DATETIME, który ma część czasu - część czasu, która sprawia, że ​​radzenie sobie z danymi jest nieco trudniejsze. Po uaktualnieniu do wersji z typem danych Data możesz chcieć zaktualizować kolumny, w których zawsze jest godzina 00:00. W bazie danych zawierającej dziesiątki lub nawet setki kolumn DateTime byłoby to dość czasochłonne. Łatwo jest jednak napisać skrypt, który będzie sprawdzał wszystkie tabele, sprawdzając każdą kolumnę z typem danych DATETIME, aby sprawdzić, czy jest to kiedykolwiek czas inny niż 00:00, a jeśli nie, utwórz instrukcję ALTER, aby zmienić tabelę / kolumnę typ danych na DATE. Presto, kod, który pisze kod.


3

Spójrz na makra CL (Common Lips). Moim zdaniem właśnie tego chcesz. Usta są idealne w metaprogramowaniu.

Polecam również Nemerle, jeśli chcesz mieć uprawnienia .NET z doskonałą obsługą metaprogramowania (w tym makr)

Ale jeśli chcesz mieć prawdziwy silnik do generowania kodu, spójrz na oszczędności Apache


3

Właśnie pracuję nad takim narzędziem. W naszym szczególnym przypadku generujemy kod VB.NET dla warstwy danych na podstawie sygnatur funkcji w bazie danych.

Rozpoczęcie pracy z generowaniem kodu jest początkowo trudne, ponieważ nie masz pojęcia, jak wygenerować kod, ale po ustaleniu zestawu reguł można wygenerować kod na podstawie tych reguł. , praca z tym kodem nie jest taka trudna. Oczywiście w zależności od złożoności generowania kodu i liczby reguł zadanie może stać się trudniejsze. Ale w gruncie rzeczy automatyczne generowanie kodu służy do powtarzania zadań kodowania, a nie do zaawansowanego kodu, który jest bardzo zróżnicowany.

Testowanie wyników jest dwojakie. Najpierw musisz się upewnić, że kod się skompiluje, a to łatwe. Następnie musisz się upewnić, że dane wyjściowe działają tak, jak powinny, w oparciu o parametry, na których zostały wygenerowane ... a trudność tego zależy od złożoności generowanego kodu.

Szczerze zalecam, że jeśli czujesz, że piszesz kod w sposób powtarzalny i możesz sobie pozwolić na czas. Spróbuj pomyśleć, czy nie możesz zrobić tego za pomocą wygenerowanego kodu. A jeśli tak (jeśli jest to powtarzalny kod, który prawie zawsze ma miejsce), pomyśl, ile razy będziesz musiał rozszerzyć, nieznacznie zmodyfikuj ten kod, a także ile razy musisz napisać dokładnie ten rodzaj kodu. Jeśli odpowiedź na którekolwiek z nich brzmi „wiele” , powinieneś poważnie rozważyć stworzenie generatora dla tego kodu .

Mam nadzieję, że to pomoże,
IPP


Dziękuję za odpowiedź! Jak faktycznie wdrażane są reguły w twoim przykładzie?
Jose Faeti

1
Nie mogę ci powiedzieć wszystkich zasad, ale mogę podać kilka przykładów. Analizujemy interfejs udostępniony przez bazę danych Oracle i bierzemy pod uwagę sygnatury funkcji w interfejsie Oracle. Na podstawie podpisu generujemy nazwę funkcji warstwy danych. wiemy, że zawsze otrzymujemy z bazy danych tabelę wyroczni, którą analizujemy i zapisujemy w tablicy specjalnego typu obiektu, którego używamy do przechowywania naszych danych. Ponadto, na podstawie parametrów wejściowych / wyjściowych podpisu funkcji db dodajemy odpowiednie parametry wejściowe i wyjściowe do funkcji możemy generować i tak dalej ..
Ioan Paul Pirau

3

Mam moduł PHP, który wyświetla stronę internetową zawierającą kod JavaScript, który generuje HTML. Tam są trzy warstwy. Chłopiec był tak trudny do odczytania!

W klasie programistycznej musieliśmy napisać program, który pobierze od użytkownika ciąg formuły, przeanalizuje go i wyświetli wartość. Najbardziej imponujący solver po prostu pobrał dane wejściowe użytkownika, zawinął je w main () {printf ("% d", ...);} i uruchomił skrypt, aby go skompilować, połączyć i uruchomić. Nie napisał parsera! Dzisiaj możesz to zrobić w instrukcji SQL SELECT.

Jest to narzędzie, z którym powinieneś grać, a następnie przechowywać je na przyszły dzień, kiedy będzie przydatne.


To właściwie to samo, co próbowałem wdrożyć! :) Ale potem postanowiłem napisać kod w Perlu offline i działa świetnie. Mam mnóstwo funkcji, które zamierzam dodać!
Jose Faeti

Piszę kod zawierający do 20 warstw języka do transformacji języka, bez żadnych problemów. Nie jest to bardziej skomplikowane niż głębokość stosu wywołań wynosząca 20 warstw. Dlatego zdecydowanie nie zgadzam się, że jest to narzędzie do „ przechowywania go na jakiś przyszły dzień, kiedy będzie to przydatne ” - generowanie kodu jest zawsze przydatne.
SK-logic

3

Mam opracowane schludne meta-programowanie rozwiązań z Prologu . Tam, gdzie główna aplikacja (w C ++ powiedzą) tłumaczy abstrakcyjną definicję problemu na aplikację Prolog w czasie wykonywania, która jest następnie delegowana do. Często pisanie równoważnych funkcji w C ++ trwałoby wieczność.

Myślę, że ten scenariusz jest doskonałym argumentem za argumentem kod-pisanie-kod .


3

Co sądzisz na ten temat?

Metaprogramowanie jest najczęściej kojarzone z językami niedynamicznymi, ponieważ trudniej jest osiągnąć określone zachowania (takie jak implementacja ORM) bez wielu nieproduktywnych i nie inteligentnych linii kodu.

Ale nawet w bardziej dynamicznych językach, takich jak PHP, generowanie kodu może naprawdę uratować życie i znacznie zwiększyć produktywność. W nowoczesnych ramach często występuje rusztowanie, które generuje większość wspólnego modelu, formy, testu i akcji dla określonego obiektu biznesowego, który deklarujesz. Jest to jeden z powodów, dla których frameworki takie jak symfony lub RoR odnoszą tak duży sukces, te narzędzia do generowania kodu bardzo szybko tworzą spójny kod i zwiększają produktywność programistów.

Na stronach internetowych większość interakcji dotyczy czterech głównych działań:

  • Utwórz element
  • Pobierz zestaw elementów (z możliwym filtrowaniem)
  • Zaktualizuj element o nowe atrybuty
  • Usuń zestaw elementów

Przynajmniej wszystko, co kręci się wokół tych 4 głównych działań, i IMHO POWINNO zostać osiągnięte przy użyciu narzędzi do generowania kodu, aby osiągnąć maksymalną wydajność.

W mojej firmie używamy symfony, a jego generator-administrator jest wyjątkowym narzędziem, które nawet generuje kod w czasie wykonywania (i buforuje go), co oznacza, że ​​nie musimy nawet używać żadnego zadania ani zewnętrznego narzędzia do wygeneruj nowy kod, wystarczy wyczyścić naszą pamięć podręczną. MOCNO radzę używać tego rodzaju narzędzia do operacji CRUD.

Ale robienie tego, co zrobili wspaniali współpracownicy symfony, nie jest łatwym zadaniem. Sam zaimplementowałem niektóre zadania związane z generowaniem kodu i wykonanie czegoś, co jest naprawdę spójne, a szeroka implementacja obejmująca większość przypadków narożnych nie jest łatwa.

Czy to coś, co naprawdę zwiększy Twoją wydajność?

Uważam, że metaprogramowanie jest bardzo ważne w niższych poziomach pracy (frameworki, buforowanie, kompilatory itp.), Ale coś, do czego musimy podchodzić z najwyższą ostrożnością, jeśli robimy rzeczy na poziomie biznesowym.

Generowanie kodu jest bez wątpienia głównym czynnikiem zwiększającym produktywność. Wdrażanie własnych narzędzi do generowania kodu, nie tyle, chyba że sam tworzysz framework.

Jakie są dobre zasoby na ten temat, wśród książek, blogów, pokazów slajdów itp.?

Najlepszym zasobem do zrozumienia programowania jest zawsze dobry i dobrze skomentowany kod źródłowy. Powiedziałbym, że przyjrzenie się generatorom administracyjnym RubyOnRails i Symfony to dobry pomysł.


3

Podczas gdy wiele odpowiedzi tutaj odnosi się do tego, co jest powszechnie znane jako metaprogramowanie, w rzeczywistości istniało pole związane z AI znane jako programowanie automatyczne, które dotyczyło programów rozumiejących lub syntezujących programy [1].

Każdy kompilator (lub metaprogram, generator kodu, translator, system makr, ...) pracuje z transformacjami, generując dane wyjściowe z wejścia, wykonując ustalony algorytm transformacji. Ale tradycyjny kompilator lub metaprogram nie podaje, podając definicję, opis lub przykład tego, czym jest sortowanie listy (np. [5, 3, 9] => [3,5,9]), nie tworzy algorytmu sortowania. Takie problemy leżą w interesie tego pola „automatycznego programowania”.

[1] - Sprawozdanie z postępów w zakresie systemów rozumiejących programy ftp://db.stanford.edu/pub/cstr/reports/cs/.../CS-TR-74-444.pdf


2

Meta programowanie może być bardzo trudne w utrzymaniu. Na początku wygląda elegancko, ale kiedy zaczynasz spotykać się z przypadkami narożnymi, błędy są wychwytywane późno (na wygenerowanym kodzie), a wszystko staje się koszmarem do użycia / debugowania.

Pisałem głównie kod Pythona, a z mojego doświadczenia wynika, że ​​meta programowanie jest zawsze złym wyborem dla tego języka. Zawsze możesz zmienić sposób działania, aby uzyskać nudne funkcje w normalnym języku. Rezultat jest mniej funkowy, ale łatwiejszy do życia.


każdy rodzaj kodu może być bardzo trudny w utrzymaniu. I może być bardzo łatwe, jeśli zrobione we właściwy sposób. W rzeczywistości metaprogramowanie może zwiększyć łatwość konserwacji w rzędach wielkości. Twoje doświadczenie w Pythonie jest prawdopodobnie nieistotne dla prawdziwego metaprogramowania, ponieważ Python nie nadaje się do tego sposobu myślenia, z jego niezbyt głęboką AST. Ale nawet w Pythonie korzystałem z biblioteki Tempita z wysoką wydajnością i nigdy nie miałem żadnych problemów z utrzymaniem, nawet z zespołem bez prawie żadnego wcześniejszego doświadczenia w Pythonie.
SK-logic

Interesuje mnie twój punkt widzenia na temat pytona AST. Czy używałeś tempita do meta programowania?
Simon Bergot,

to ( docs.python.org/library/ast.html ) jest dość ad hoc AST, a parser daje niezoptymalizowane, przesadzone drzewo, co sprawia, że ​​analiza jest problematyczna (szczególnie przy braku odpowiedniego dopasowania wzorca w Pythonie). Generowanie takiego AST również nie jest zbyt wygodne. Użyłem tempita do wytworzenia zarówno kodu Python, jak i C (tj. Metaprogramowanie w oparciu o czysty tekst), działało dobrze dla tego konkretnego zadania (generowanie kodu na płycie głównej). Często używałem również Pythona do generowania kodu C z niektórych opisów wysokiego poziomu XML.
SK-logic

2

OP prosi o zasoby.

Może Cię zainteresować nasz pakiet DMS Software Reengineering Toolkit . Jest to czyste narzędzie do metaprogramowania, które pozwala budować niestandardowe narzędzia do analizy i transformacji programów.

[Aby podążać za komentarzem do pytania OP, gdy jest używany do budowy konkretnego narzędzia do transformacji, DMS to linia produktów, która pisze kod, który pisze kod:]

DMS osiąga to poprzez bycie agnostycznym (ale nie niezależnym) od docelowych programów programowania. DMS zapewnia standardowe usługi potrzebne dla szerokiej gamy zadań metaprogramowania, podobnie jak system operacyjny zapewnia szeroki zakres usług dla standardowych zadań programistycznych. Usługi te obejmują silne analizowanie składni, automatyczną budowę drzew składni abstact, dopasowywanie wzorców i przepisywanie na drzewach, biblioteki tablic symboli, które z łatwością zarządzają językami przy użyciu nieprzyjemnych zasad określania zakresu, takich jak wielokrotne dziedziczenie, przepływ kontrolny, przepływ danych, przekazywanie punktów i wywołanie analiza graficzna. Żadne z tych elementów nie ma znaczenia w przypadku braku określonych języków do przetworzenia, więc DMS akceptuje definicje języka powiązane z tymi ogólnymi maszynami, oferując parsowanie specyficzne dla języka, konstrukcję AST, dopasowanie / przepisywanie wzorca specyficznego dla języka docelowego przy użyciu parametru docelowego składnia języka,

I podobnie jak system operacyjny, DMS ma bardzo mało opinii lub ograniczeń co do (meta) programów, które chcesz napisać, co oznacza, że ​​może być używany do wielu różnych celów: wydobywania metryk, znajdowania martwego kodu, wdrażania tkaczy aspektów, tłumaczenia langauges, generowanie kodów z DSL, rearchitekcja dużych aplikacji. (DMS był już używany do wszystkich tych zadań).

Potrzebne są solidne definicje języka, jeśli nie chcesz poświęcać czasu na kodowanie wszystkiego w podręczniku langauge (pomyśl o tym, co to oznacza dla Java i C ++). DMS rozwiązuje ten problem, udostępniając bibliotekę pełnych definicji języków. Tutaj analog jest jak baza danych dostępna dla twojego systemu operacyjnego; nie musisz implementować żadnego z nich, aby rozpocząć pisanie aplikacji skoncentrowanej na bazie danych.


2

Zobacz zestaw problemów Philipa Greenspuna 4 z kursu MIT 6.916: Inżynieria oprogramowania innowacyjnych usług internetowych ( http://philip.greenspun.com/teaching/psets/ps4/ps4.adp ).

Jego cel mówi: „Naucz uczniów zalet metadanych. W szczególności uczą się, jak formalnie reprezentować wymagania usługi internetowej, a następnie budować program komputerowy do generowania programów komputerowych, które implementują tę usługę”.

Jest to jeden z problemów, które potencjalni rekruci ArsDigita ( http://en.wikipedia.org/wiki/ArsDigita ) musieli rozwiązać podczas pierwszej bańki.

Książka „SQL for Web Nerds” Odnośniki Philipa w zestawie zostały przeniesione do ( http://philip.greenspun.com/sql/ ).


2

Mniej więcej w 2001 r. Zacząłem pracować nad projektem, który szeroko wykorzystywał obiekty biznesowe i obiekty danych. Miałem budować front-endową stronę internetową, ale rozłączyłem się, kręcąc kciukami, ponieważ warstwa biznesowa i warstwa dostępu do danych nie były w pełni rozwinięte. Po kilku tygodniach zacząłem uważnie przyglądać się tym, co robią te warstwy. Zasadniczo ujawniali dane zwrócone z procedur przechowywanych jako kolekcje obiektów o właściwościach odpowiadających polom danych lub przyjmowali parametry wejściowe i wysyłali je do procedur przechowywanych w celu zapisania w tabelach bazy danych. Między dwiema warstwami miało miejsce wiele serializacji / deserializacji, zaangażowany był Microsoft Transaction Server, biblioteka typu IDL / ODL ... ale wszystko pasowało do wzorca.

2 tygodnie później uruchomiłem generator kodu, który zrzuciłby IDL / ODL, a także zrzucił obiekty biznesowe i danych. Facetowi zajmującemu się tworzeniem obiektów biznesowych i warstw danych zajęło 2 lata, aby przejść do debugowania i testowania tych obiektów. Po 2 tygodniach z generowaniem kodu mieliśmy takie same dane wyjściowe, ale ponieważ wszystko zostało wygenerowane, było całkiem dobrze wolne od błędów.

Ten generator kodu (narzędzie CASE niższego poziomu) śledził mnie przez wiele różnych iteracji, przez około 8 do 10 lat, ponieważ zasada była tak prosta: robisz coś, co należy zrobić, rozmawiając z bazami danych, jest całkiem ładna dużo powtarzalnego kodowania, a kiedy już dobrze to zrobisz, nie musisz się już o to martwić.

Tak, tak: użyj generatora kodu, szczególnie gdy kodowanie jest powtarzalne i pasuje do ściśle określonego wzorca.

Wiem, że ludzie używają makr RegX do robienia podobnych rzeczy lub do używania formuł Excela do robienia podobnych rzeczy (ja też to robię).


2

Przykład metaprogramowania

Mam bibliotekę autoryzacji Ruby o nazwie Authority . Pozwala programistom zadawać pytania w aplikacji za pomocą metod takich jak current_user.can_read?(@post)i @post.readable_by?(current_user). Odpowiedzi na te pytania udzielają scentralizowane klasy autoryzacyjne.

Jest to kluczowa część: organ nie wie, które metody zdefiniować, dopóki nie zobaczy konfiguracji użytkownika . Konfiguracja użytkownika może zawierać:

config.abilities =  {
  ...
  :read      => 'readable',
  :microwave => 'microwavable',  # user-defined
  ...
}

W takim przypadku musi istnieć taka metoda current_user.can_microwave?(@post).

Metaprogramowanie umożliwia: po przeczytaniu konfiguracji wiem, które metody zdefiniować :

Authority.verbs.each do |verb|
  class_eval <<-RUBY, __FILE__, __LINE__ + 1 # allows for a nice bracktrace
    def can_#{verb}?(resource)
      resource.#{Authority.abilities[verb]}_by?(self)
    end
  RUBY
end
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.