Przepisanie Java do Clojure

97

Moja firma właśnie poprosiła mnie o przepisanie dużej (50 000 pojedynczych linii kodu) aplikacji Java (aplikacji internetowej korzystającej z JSP i serwletów) w Clojure. Czy ktoś jeszcze ma wskazówki, na co powinienem uważać?

Pamiętaj, że dobrze znam zarówno Javę, jak i Clojure.

Aktualizacja

Zrobiłem przepisanie i weszło do produkcji. To dość dziwne, ponieważ przepisywanie skończyło się tak szybko, że zostało zrobione w około 6 tygodni. Ponieważ wiele funkcji nie było potrzebnych, skończyło się bardziej na 3000 linii Clojure.

Słyszałem, że są zadowoleni z systemu i robi dokładnie to, czego chcieli. Jedynym minusem jest to, że facet obsługujący system musiał nauczyć się Clojure od zera i został w to wciągnięty kopiąc i krzycząc. Niedawno zadzwonił do mnie, mówiąc, że teraz kocha Lispa ... zabawne :)

Powinienem też wspomnieć o Vaadinie. Używanie Vaadina prawdopodobnie przyczyniło się do zaoszczędzenia czasu i skrócenia kodu, tak jak Clojure. Vaadin jest nadal najlepszym frameworkiem internetowym, jakiego kiedykolwiek używałem, chociaż teraz uczę się ClojureScript w złości! (Zwróć uwagę, że zarówno Vaadin, jak i ClojureScript używają struktur GUI Google pod maską).

appshare.co
źródło
55
Chcę pracować dla Twojej firmy.
mtyaka
4
Cóż, niektóre firmy zbrojeniowe w Europie zaczęły używać Clojure (słyszałem). Ale nie pamiętam nazwisk :)
appshare.co
1
@Zubair: 50 000 Java LOC nie jest w pobliżu „largish”. To bardzo mały projekt. Mam tutaj projekt Java od 250KLOC do 300KLOC i jest on średniej wielkości ... W najlepszym razie.
SyntaxT3rr0r
5
Właściwie może popełniłem błąd, wspominając o rozmiarze bazy kodu, ponieważ aby być sprawiedliwym, zmniejszenie rozmiaru kodu nie jest celem przepisywania. Cel jest dwojaki: 1) aby baza kodu była bardziej zrozumiała, a tym samym tańsza w utrzymaniu kodu. zrobić w Javie)
appshare.co
1
Hej ... właśnie zobaczyłem to starsze pytanie i zastanawiałem się, jak idzie przepisywanie?
levand

Odpowiedzi:

82

Największym „problemem translacyjnym” będzie prawdopodobnie przejście od metodologii Java / OOP do paradygmatu Clojure / programowania funkcjonalnego.

W szczególności, zamiast mieć zmienny stan w obiektach, „sposób Clojure” polega na wyraźnym oddzieleniu zmiennego stanu i opracowaniu czystych (wolnych od skutków ubocznych) funkcji. Prawdopodobnie już to wszystko wiesz :-)

W każdym razie ta filozofia prowadzi do czegoś w rodzaju stylu rozwoju „oddolnego”, w którym początkowe wysiłki koncentrują się na budowaniu odpowiedniego zestawu narzędzi do rozwiązania problemu, a na końcu łączą je razem. To może wyglądać mniej więcej tak

  1. Zidentyfikuj kluczowe struktury danych i przekształć je w niezmienną mapę Clojure lub definicje rekordów. Nie bój się zagnieżdżać wielu niezmiennych map - są one bardzo wydajne dzięki trwałym strukturom danych Clojure. Warto obejrzeć ten film, aby dowiedzieć się więcej.

  2. Twórz małe biblioteki czystych funkcji zorientowanych na logikę biznesową, które działają na tych niezmiennych strukturach (np. „Dodaj pozycję do koszyka”). Nie musisz robić tego wszystkiego naraz, ponieważ później łatwo jest dodać więcej, ale warto zrobić kilka na początku, aby ułatwić testowanie i udowodnić, że struktury danych działają ..... tak czy inaczej w rzeczywistości możesz zacząć interaktywnie pisać przydatne rzeczy w REPL

  3. Oddzielnie opracuj procedury dostępu do danych, które w razie potrzeby mogą utrwalać te struktury do / z bazy danych lub sieci lub starszego kodu Java. Powodem, dla którego należy to bardzo oddzielić, jest to, że nie chcesz, aby logika trwałości była powiązana z funkcjami „logiki biznesowej”. W tym celu możesz spojrzeć na ClojureQL , chociaż dość łatwo jest opakować dowolny kod trwałości Java, który chcesz.

  4. Napisz testy jednostkowe (np. Za pomocą clojure.test ), które obejmują wszystkie powyższe. Jest to szczególnie ważne w dynamicznym języku, takim jak Clojure, ponieważ a) nie masz tak dużej siatki bezpieczeństwa przed statycznym sprawdzaniem typów i b) pomaga upewnić się, że konstrukcje niższego poziomu działają dobrze, zanim zaczniesz zbyt dużo budować górę z nich

  5. Zdecyduj, w jaki sposób chcesz używać typów referencyjnych Clojure (zmiennych, referencji, agentów i atomów) do zarządzania stanami poziomu aplikacji, które można modyfikować. Wszystkie działają w podobny sposób, ale mają inną semantykę transakcyjną / współbieżną w zależności od tego, co próbujesz zrobić. Domyślnym wyborem będą prawdopodobnie odwołania - pozwalają one na implementację „normalnego” zachowania transakcyjnego STM poprzez zawijanie dowolnego kodu w blok (dosync ...).

  6. Wybierz właściwą ogólne ramy internetowej - Clojure ma już całkiem sporo, ale bym zalecamy Ring - zobacz ten doskonały film „ Jeden, by związać ” plusa albo Fleet lub Enlive lub Czkawka zależności od filozofii szablonów. Następnie użyj tego do napisania swojej warstwy prezentacji (z funkcjami takimi jak „przetłumacz ten koszyk na odpowiedni fragment HTML”)

  7. Na koniec napisz swoją aplikację przy użyciu powyższych narzędzi. Jeśli poprawnie wykonałeś powyższe kroki, będzie to faktycznie łatwe, ponieważ będziesz w stanie zbudować całą aplikację poprzez odpowiedni skład różnych komponentów z bardzo małą ilością gotówki.

Jest to z grubsza kolejność, w której chciałbym zaatakować problem, ponieważ ogólnie reprezentuje on porządek zależności w Twoim kodzie, a zatem nadaje się do tworzenia „od podstaw”. Chociaż oczywiście w dobrym, zwinnym / iteracyjnym stylu, prawdopodobnie szybko przechodzisz do przodu do możliwego do udowodnienia produktu końcowego, a następnie często wracasz do wcześniejszych kroków, aby rozszerzyć funkcjonalność lub refaktoryzację w razie potrzeby.

ps Jeśli zastosujesz się do powyższego podejścia, byłbym zafascynowany tym, ile linii Clojure potrzeba, aby dopasować funkcjonalność 50000 linii Java

Aktualizacja : ponieważ ten post został pierwotnie napisany, pojawiło się kilka dodatkowych narzędzi / bibliotek, które należą do kategorii „trzeba sprawdzić”:

  • Noir - framework sieciowy, który jest oparty na Ring.
  • Korma - bardzo ładne DSL do uzyskiwania dostępu do baz danych SQL.
mikera
źródło
4
Nitpick re: „Zdecyduj, którego z typów referencji STM firmy Clojure chcesz użyć do zarządzania stanem poziomu aplikacji z możliwością zmiany każdej części”: Jest tylko jeden typ odniesienia STM. Inne IRef nie obejmują STM. W przeciwnym razie wygląda na solidną radę.
hmmm ... Myślę, że liczę referencje, agentów i atomy jako część systemu Clojure STM / współbieżności. Na przykład wszyscy obsługują walidatory, a agenci są koordynowani przy zatwierdzaniu transakcji. ale rozumiem twój punkt widzenia, referencje to „podstawowy” model transakcyjny. wprowadzi szybką poprawkę.
mikera
2
Gdybym tylko mógł dać temu więcej + 1-ek. Obejrzałem oba filmy, o których wspominałeś, i były świetne. Dzięki.
jdl
1
Teraz noir jest przestarzały. Przypuszczam, że trzeba wspomnieć o kompozycjach zamiast noir.
hsestupin
Link One Ring To Bind Them jest uszkodzony!
Adam Arold
5

Jakie aspekty języka Java obejmuje Twój obecny projekt? Rejestrowanie, transakcje w bazie danych, transakcje deklaratywne / EJB, warstwa WWW (wspomniałeś o JSP, serwletach) itp. Zauważyłem, że ekosystem Clojure ma różne mikro-frameworki i biblioteki, których celem jest wykonanie jednego zadania i robi to dobrze. Proponuję ocenić biblioteki w oparciu o Twoje potrzeby (i czy będzie to skalowalne w dużych projektach) i podjąć świadomą decyzję. (Zastrzeżenie: jestem autorem bitumenframework ) Inną rzeczą, na którą należy zwrócić uwagę, jest proces kompilacji - jeśli potrzebujesz złożonej konfiguracji (programowanie, testowanie, staging, prod) może być konieczne podzielenie projektu na moduły i skrypty procesu kompilacji łatwość.

Shantanu Kumar
źródło
Serwlety, JSP, struktura trwałości zbudowana w domu (10 lat) i pojos, ale bez EJB
appshare.co
4
Serwlety można łatwo zastąpić Ring + Compojure IMHO, a strony JSP można zastąpić być może StringTemplate (lub szablonami FreeMarker / Velocity). Trwałość w Clojure będzie inna niż w Javie. Jeśli potrzebujesz mapowania relacyjnego, możesz spojrzeć na Clj-Record i SQLRat (jeszcze niezbyt dojrzałe). ClojureQL obsługuje obecnie tylko MySQL i PostgreSQL AFAICT. Obecne ograniczenie w ccsql, aby nie zezwalać na podkreślenia w nazwach kolumn, może być zaskoczeniem. Myślę, że omówienie aspektów rozwoju na liście Clojure, gdy zajdzie taka potrzeba, będzie przydatne. Powodzenia w projekcie!
Shantanu Kumar
Od czasu tego projektu stworzyłem kolejną aplikację z Clojure i Clojurescript (nemcv.com) i używam teraz Ringa, wypróbowałem ClojureQL, ale przełączałem się na Korma w celu uzyskania dostępu do bazy danych. Najnowsze prace można zobaczyć na github.com/zubairq/coils
appshare.co. Sierpnia
4

Najtrudniejszą częścią było myślenie o bazie danych. Wykonaj kilka testów, aby znaleźć odpowiednie narzędzia, których chcesz tam użyć.

LenW
źródło
1
Cóż, próbowałem clojureql w celu uzyskania dostępu do danych, ale różni się on całkowicie od stylu Java dostępu do bazy danych, który jest oparty na obiektach. Tylko z ciekawości, z jakiego dostępu do bazy danych korzystałeś w Javie, a czego z Clojure?
appshare.co
1
Skończyło się na tym, że przemyśleliśmy wiele rzeczy i zdecydowaliśmy się na mongodb, ponieważ trwałość struktur danych clojure była bardzo naturalna
LenW