Viết lại Java thành Clojure


97

Tôi vừa được công ty yêu cầu viết lại một ứng dụng Java lớn (50.000 dòng mã đơn) (một ứng dụng web sử dụng JSP và các servlet) trong Clojure. Có ai khác có lời khuyên về những gì tôi nên đề phòng không?

Xin lưu ý rằng tôi biết cả Java VÀ Clojure khá tốt.

Cập nhật

Tôi đã viết lại và nó đã đi vào sản xuất. Nó khá kỳ lạ vì việc viết lại kết thúc quá nhanh đến mức nó được thực hiện trong khoảng 6 tuần. Bởi vì nhiều chức năng không cần thiết nhưng nó đã tạo ra hơn 3000 dòng Clojure.

Tôi nghe nói rằng họ hài lòng với hệ thống và nó đang làm chính xác những gì họ muốn. Nhược điểm duy nhất là anh chàng duy trì hệ thống phải học Clojure từ đầu, và anh ta bị lôi vào đó đá và la hét. Tôi đã nhận được một cuộc gọi từ anh ấy ngày hôm trước nói rằng anh ấy yêu Lisp bây giờ mặc dù vậy .. buồn cười :)

Ngoài ra, tôi nên đề cập tốt đến Vaadin. Sử dụng Vaadin có lẽ chiếm nhiều thời gian tiết kiệm và ngắn gọn mã như Clojure đã làm .. Vaadin vẫn là web framework hàng đầu mà tôi từng sử dụng, mặc dù bây giờ tôi đang học ClojureScript trong cơn tức giận! (Lưu ý rằng cả Vaadin và ClojureScript đều sử dụng khung GUI của Google bên dưới mui xe.)


55
Tôi muốn làm việc cho công ty của bạn.
mtyaka

4
Vâng, một số công ty quốc phòng ở châu Âu đã bắt đầu sử dụng Clojure (tôi nghe nói). Nhưng không thể nhớ bất kỳ tên nào :)
appshare.co Ngày

1
@Zubair: 50 000 Java LOC không ở đâu gần "lớn". Đây là một dự án rất nhỏ. Tôi có một dự án Java 250KLOC đến 300KLOC ở đây và nó có kích thước trung bình ... Tốt nhất.
Cú phápT3rr0r Ngày

5
Trên thực tế, tôi có thể đã nhầm lẫn khi đề cập đến kích thước của codebase vì công bằng mà nói, việc giảm kích thước mã không phải là mục đích của việc viết lại. Mục đích là gấp đôi: 1) để có cơ sở mã dễ hiểu hơn và do đó rẻ hơn để duy trì mã 2) Cho phép người dùng công cụ mở rộng sản phẩm bằng trình chỉnh sửa Clojure trong trình duyệt web (sử dụng eval và các tính năng Clojure động khác, tốn kém hơn để làm bằng Java)
appshare.co

1
Này ... vừa mới nhìn thấy câu hỏi cũ hơn này và tự hỏi việc viết lại diễn ra như thế nào?
levand

Câu trả lời:


82

"Vấn đề dịch thuật" lớn nhất có lẽ sẽ chuyển từ phương pháp luận Java / OOP sang mô hình lập trình chức năng / Clojure.

Đặc biệt, thay vì có trạng thái có thể thay đổi bên trong các đối tượng, "cách Clojure" là tách biệt rõ ràng trạng thái có thể biến đổi và phát triển các chức năng thuần túy (không có tác dụng phụ). Bạn có thể biết tất cả những điều này rồi :-)

Dù sao, triết lý này có xu hướng hướng tới một thứ gì đó theo phong cách phát triển "từ dưới lên", nơi bạn tập trung nỗ lực ban đầu vào việc xây dựng bộ công cụ phù hợp để giải quyết vấn đề của mình, sau đó kết hợp chúng lại với nhau ở phần cuối. Cái này có thể trông giống như thế này

  1. Xác định các cấu trúc dữ liệu chính và chuyển chúng thành bản đồ Clojure bất biến hoặc các định nghĩa bản ghi. Đừng ngại lồng nhiều bản đồ bất biến - chúng rất hiệu quả nhờ cấu trúc dữ liệu bền bỉ của Clojure. Đáng xem video này để tìm hiểu thêm.

  2. Phát triển các thư viện nhỏ gồm các chức năng thuần túy, theo hướng logic nghiệp vụ hoạt động trên các cấu trúc bất biến này (ví dụ: "thêm một mặt hàng vào giỏ hàng"). Bạn không cần phải thực hiện tất cả những điều này cùng một lúc vì việc bổ sung thêm sau này rất dễ dàng, nhưng thực hiện một số việc sớm để tạo điều kiện thuận lợi cho việc kiểm tra và chứng minh rằng cấu trúc dữ liệu của bạn đang hoạt động ..... theo cách này điểm bạn thực sự có thể bắt đầu viết nội dung hữu ích một cách tương tác tại REPL

  3. Phát triển riêng biệt các quy trình truy cập dữ liệu có thể duy trì các cấu trúc này đến / từ cơ sở dữ liệu hoặc mạng hoặc mã Java kế thừa nếu cần. Lý do để giữ điều này rất riêng biệt là bạn không muốn logic liên tục bị ràng buộc với các chức năng "logic nghiệp vụ" của bạn. Bạn có thể muốn xem xét ClojureQL cho điều này, mặc dù nó cũng khá dễ dàng để bọc bất kỳ mã bền vững Java nào mà bạn thích.

  4. Viết các bài kiểm tra đơn vị (ví dụ: với clojure.test ) bao gồm tất cả những điều trên. Điều này đặc biệt quan trọng đối với một ngôn ngữ động như Clojure vì a) bạn không có nhiều lưới an toàn từ việc kiểm tra kiểu tĩnh và b) điều đó giúp đảm bảo rằng các cấu trúc cấp thấp hơn của bạn đang hoạt động tốt trước khi bạn xây dựng quá nhiều hàng đầu của họ

  5. Quyết định cách bạn muốn sử dụng các loại tham chiếu của Clojure (vars, refs, agent và nguyên tử) để quản lý từng trạng thái cấp ứng dụng có thể thay đổi của từng phần. Tất cả chúng đều hoạt động theo cách tương tự nhưng có ngữ nghĩa giao dịch / đồng thời khác nhau tùy thuộc vào những gì bạn đang cố gắng thực hiện. Refs có thể sẽ là lựa chọn mặc định của bạn - chúng cho phép bạn thực hiện hành vi giao dịch STM "bình thường" bằng cách gói bất kỳ mã nào trong một khối (dosync ...).

  6. Chọn khung web tổng thể phù hợp - Clojure đã có khá nhiều nhưng tôi thực sự khuyên bạn nên sử dụng Ring - hãy xem video xuất sắc này " One Ring To Bind Them " cùng với Fleet hoặc Enlive hoặc Hiccup tùy thuộc vào triết lý tạo mẫu của bạn. Sau đó, sử dụng nó để viết lớp trình bày của bạn (với các chức năng như "dịch giỏ hàng này thành một đoạn HTML thích hợp")

  7. Cuối cùng, viết ứng dụng của bạn bằng các công cụ trên. Nếu bạn đã thực hiện các bước trên đúng cách, thì đây thực sự sẽ là một việc dễ dàng bởi vì bạn sẽ có thể xây dựng toàn bộ ứng dụng bằng thành phần thích hợp của các thành phần khác nhau với rất ít bảng tạo sẵn.

Đây đại khái là trình tự mà tôi sẽ tấn công vấn đề vì nó đại diện cho thứ tự của các phần phụ thuộc trong mã của bạn và do đó phù hợp với nỗ lực phát triển "từ dưới lên". Tất nhiên, mặc dù theo phong cách nhanh nhẹn / lặp đi lặp lại tốt, bạn có thể thấy mình đang thúc đẩy sớm đến một sản phẩm cuối cùng có thể trình diễn và sau đó quay lại các bước trước đó khá thường xuyên để mở rộng chức năng hoặc cấu trúc lại nếu cần.

ps Nếu bạn làm theo cách trên, tôi sẽ rất thích thú khi nghe cần bao nhiêu dòng Clojure để phù hợp với chức năng của 50.000 dòng Java

Cập nhật : Vì bài đăng này ban đầu được viết, một số công cụ / thư viện bổ sung đã xuất hiện nằm trong danh mục "phải kiểm tra":

  • Noir - khuôn khổ web được xây dựng dựa trên Ring.
  • Korma - một DSL rất tốt để truy cập cơ sở dữ liệu SQL.

4
Nitpick re: "Quyết định loại tham chiếu STM của Clojure mà bạn muốn sử dụng để quản lý trạng thái cấp ứng dụng có thể thay đổi từng phần": Chỉ có một loại tham chiếu STM. Các IRef khác không liên quan đến STM. Nếu không có vẻ như lời khuyên vững chắc.

hmmm ... Tôi đoán tôi tính số tham chiếu, tác nhân và nguyên tử như tất cả đều là một phần của hệ thống Clojure STM / đồng thời. Ví dụ: tất cả họ đều hỗ trợ trình xác thực và các đại lý được điều phối với các cam kết giao dịch. nhưng tôi hiểu ý bạn, ref là mô hình giao dịch "chính". sẽ sửa đổi nhanh chóng.
mikera

2
Giá mà tôi có thể cho thêm +1 này. Tôi đã xem cả hai video mà bạn đã tham khảo, và chúng rất tuyệt. Cảm ơn.
jdl

1
Hiện noir không được dùng nữa. Tôi cho rằng bạn phải đề cập đến compojure thay vì noir.
hsestupin

Liên kết One Ring To Bind Them bị hỏng!
Adam Arold

5

Dự án hiện tại của bạn bao gồm những khía cạnh nào của Java? Ghi nhật ký, Giao dịch cơ sở dữ liệu, Giao dịch khai báo / EJB, lớp web (bạn đã đề cập đến JSP, servlet), v.v. Tôi nhận thấy hệ sinh thái Clojure có nhiều khung vi mô và thư viện khác nhau với mục tiêu làm một nhiệm vụ và làm tốt nhiệm vụ đó. Tôi khuyên bạn nên đánh giá các thư viện dựa trên nhu cầu của bạn (và liệu nó có mở rộng quy mô trong các dự án lớn hay không) và đưa ra quyết định sáng suốt. (Tuyên bố từ chối trách nhiệm: Tôi là tác giả của bitumenframework ) Một điều khác cần lưu ý là quá trình xây dựng - nếu bạn cần một thiết lập phức tạp (dev, testing, staging, prod), bạn có thể phải chia dự án thành các mô-đun và quy trình xây dựng được viết kịch bản cho giảm bớt.


Servlets, JSP, khung homebuilt bền bỉ (10 tuổi) và POJO, nhưng không có EJB
appshare.co

4
Servlet có thể dễ dàng được thay thế bằng Ring + Compojure IMHO và JSP có thể được thay thế bằng các mẫu StringTemplate (hoặc FreeMarker / Velocity.) Tính bền trong Clojure sẽ khác với Java. Nếu bạn cần ánh xạ quan hệ, bạn có thể xem Clj-Record và SQLRat (chưa thuần thục lắm). ClojureQL hiện chỉ hỗ trợ MySQL và PostgreSQL AFAICT. Giới hạn hiện tại trong ccsql để không cho phép dấu gạch dưới trong tên cột có thể gây ngạc nhiên. Tôi nghĩ rằng thảo luận về các khía cạnh phát triển trong danh sách Clojure khi được yêu cầu sẽ hữu ích. Chúc may mắn trên dự án!
Shantanu Kumar

Vì dự án đó, tôi đã tạo một ứng dụng khác với Clojure và Clojurescript (nemcv.com) và tôi đang sử dụng Ring bây giờ, đã thử ClojureQL, nhưng chuyển sang Korma để truy cập cơ sở dữ liệu. Bạn có thể xem tác phẩm mới nhất tại github.com/zubairq/coils
appshare.co

4

Tôi thấy phần khó khăn nhất là suy nghĩ về cơ sở dữ liệu. Thực hiện một số thử nghiệm để tìm đúng công cụ bạn muốn sử dụng ở đó.


1
Tôi đã thử dùng clojureql để truy cập dữ liệu, nhưng nó hoàn toàn khác với phong cách truy cập cơ sở dữ liệu của Java vốn là tất cả dựa trên đối tượng. Chỉ vì quan tâm bạn đã sử dụng quyền truy cập cơ sở dữ liệu nào cho Java và bạn đã sử dụng gì với Clojure?
appshare.co

1
Cuối
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.