Làm thế nào để viết mã Clojure có thể đọc được?


13

Tôi mới đến Clojure. Tôi có thể hiểu mã tôi viết nhưng nó trở nên quá khó để hiểu nó sau này.
Nó trở nên khó khăn để phù hợp với dấu ngoặc đơn.

Các quy ước chung để tuân theo về các quy ước đặt tên và thụt lề trong các tình huống khác nhau là gì?

Ví dụ tôi đã viết một ví dụ khử cấu trúc mẫu để hiểu nhưng nó trông hoàn toàn không thể đọc được lần thứ hai.

(defn f [{x :x y :y z :z [a b c] :coll}] (print x " " y  " " z " " a " " b " " c)) 

Trong trường hợp hủy cấu trúc, tốt hơn là thực hiện trực tiếp ở cấp tham số hoặc bắt đầu một biểu mẫu cho phép và sau đó tiếp tục ở đó?


3
Có một câu trả lời tốt về khả năng đọc tại Stack Overflow. Bạn có thể kiểm tra nó stackoverflow.com/a/1894891/1969106
yfklon

2
Viết mã Lisp có thể đọc được nói chung là khó khăn. Họ đã phát minh ra từ viết tắt "Lost In Superfluity Parent ngoặc" vì một lý do.
Mason Wheeler

Câu trả lời:


23

Quy ước đặt tên

  • viết thường cho các chức năng
  • sử dụng -cho dấu gạch nối (những gì sẽ là dấu gạch dưới hoặc trường hợp lạc đà trong các ngôn ngữ khác).

    (defn add-one [i] (inc i))

  • Vị ngữ (nghĩa là các hàm trả về đúng hoặc sai) kết thúc bằng ? Ví dụ:odd? even? nil? empty?

  • Thủ tục thay đổi nhà nước kết thúc vào !. Bạn nhớ set!đúng không? hoặc làswap!

  • Chọn độ dài tên biến ngắn tùy thuộc vào phạm vi của họ. Điều đó có nghĩa là nếu bạn có một biến phụ thực sự nhỏ, bạn thường chỉ có thể sử dụng tên một chữ cái. (map (fn [[k v]] (inc v)) {:test 4 :blub 5})chọn tên biến dài hơn nếu cần, đặc biệt nếu chúng được sử dụng cho nhiều dòng mã và bạn không thể đoán ngay mục đích của chúng. (quan điểm của tôi).

    Tôi cảm thấy rằng rất nhiều lập trình viên clojure có xu hướng sử dụng tên chung và ngắn. Nhưng điều này tất nhiên không thực sự là một quan sát khách quan. Vấn đề là rất nhiều chức năng clojure thực sự khá chung chung.

    • Sử dụng tên có ý nghĩa. Các ứng dụng đang làm một cái gì đó, do đó bạn có thể mô tả chúng tốt nhất bằng cách sử dụng các động từ. Clojure built-in chức năng nên đưa bạn đi đúng hướng: drop, take, assoc, vv Sau đó, có một bài viết tốt đẹp mô tả cách để chọn một tên có ý nghĩa: http://ecmendenhall.github.io/blog/blog/2013/09/ 02 / sạch-clojure-ý nghĩa tên /

Hàm Lambda

  • Bạn thực sự có thể đặt tên hàm lambda. Điều này thuận tiện cho việc gỡ lỗi và định hình (kinh nghiệm của tôi ở đây là với ClojureScript).

    (fn square-em [[k v]] {k (* v v)})

  • Sử dụng chức năng lambda nội tuyến #()là thuận tiện

Khoảng trắng

  • Không nên có các dòng chỉ parens. Tức là đóng dấu ngoặc ngay lập tức. Hãy nhớ parens có sẵn cho trình soạn thảo và trình biên dịch, thụt lề là dành cho bạn.

  • Danh sách tham số chức năng đi trên một dòng mới

   (khuyết điểm
     [ab]
     (danh sách ab))

Điều này có ý nghĩa nếu bạn nghĩ về các chuỗi doc. Chúng nằm giữa tên hàm và tham số. Chuỗi doc sau có lẽ không phải là khôn ngoan nhất;)

   (khuyết điểm
     "Ghép đôi mọi thứ"
     [ab]
     (danh sách ab))
  • Dữ liệu được ghép có thể được phân tách bằng một dòng mới miễn là bạn giữ lại việc ghép nối
  (không biết 
    [{x: x 
      y: y 
      z: z  
      [abc]: coll}] 
    (in x "" y "" z "" a "" b "" c)) 

(Bạn cũng có thể nhập ,theo ý muốn nhưng điều này cảm thấy không hợp lý).

  • Đối với thụt lề sử dụng một trình soạn thảo đủ tốt. Nhiều năm trước đây là emacs để chỉnh sửa lisp, vim cũng rất tuyệt ngày hôm nay. IDE clojure điển hình cũng nên cung cấp chức năng này. Chỉ không sử dụng một trình soạn thảo văn bản ngẫu nhiên.

    Trong vim trong chế độ lệnh, bạn có thể sử dụng =lệnh để thụt lề đúng cách.

  • Nếu lệnh quá dài (lồng nhau, v.v.), bạn có thể chèn một dòng mới sau đối số đầu tiên. Bây giờ đoạn mã sau khá vô nghĩa nhưng nó minh họa cách bạn có thể nhóm và biểu thức thụt lề:

(+ (if-let [age (: coll-age coll)]
     (nếu (> 18 tuổi)
       tuổi tác
       0)
   (đếm (phạm vi (- 3 b)
                 (giảm + 
                         (phạm vi b 10)))))

Lõm tốt có nghĩa là bạn không phải đếm dấu ngoặc. Dấu ngoặc dành cho máy tính (để giải thích mã nguồn và thụt lề). Sự thụt lề là để bạn dễ hiểu.

Hàm bậc cao hơn so với fordoseqbiểu mẫu

Xuất thân từ nền tảng Scheme tôi khá tự hào vì đã hiểu mapvà các hàm lambda, v.v ... Vì vậy, khá thường xuyên, tôi sẽ viết một cái gì đó như thế này

(map (fn [[k x]] (+ x (k data))) {:a 10 :b 20 :c 30})

Điều này khá khó đọc. Hình forthức là cách đẹp hơn:

(for [[k x] {:a 10 :b 20 :c30}]
  (+ x (k data)))

`map có rất nhiều công dụng và thực sự rất hay nếu bạn đang sử dụng các hàm được đặt tên. I E

(map inc [12 30 10]

(map count [[10 20 23] [1 2 3 4 5] (range 5)])

Sử dụng macro phân luồng

Sử dụng các macro luồng ->->>cũng như dotokhi áp dụng.

Vấn đề là các macro luồng làm cho mã nguồn xuất hiện tuyến tính hơn thành phần chức năng. Đoạn mã sau đây khá khó đọc nếu không có macro luồng:

   (f (g (h 3) 10) [10 3 2 3])

so sánh với

   (-> 
     (h 3)
     (g 10)
     (f [10 3 2 3]))

Bằng cách sử dụng macro luồng, người ta thường có thể tránh đưa ra các biến tạm thời chỉ được sử dụng một lần.

Những thứ khác

  • Sử dụng tài liệu
  • giữ chức năng ngắn
  • đọc mã clojure khác

Chức năng đó với cấu trúc khử trông rất đẹp với vết lõm!
Amogh Talpallikar

+1 để giữ chức năng ngắn. Rất nhiều chức năng nhỏ được ghi lại nhiều hơn
Daniel Gratzer

1
Tôi mạnh mẽ không đồng ý rằng đó là một ý tưởng tốt để sử dụng tên biến ngắn, ngay cả trong chức năng "ngắn đạt". Tên biến tốt là rất quan trọng cho khả năng đọc và chúng không tốn kém gì ngoại trừ các nét chính. Đây là một trong những điều khiến tôi bận tâm nhất về cộng đồng Clojure. Có nhiều người có sức đề kháng gần như thù địch với các tên biến mô tả. Lõi Clojure chứa đầy các tên biến 1 ký tự cho các đối số hàm và điều đó khiến việc học ngôn ngữ trở nên khó khăn hơn nhiều (ví dụ: chạy dochoặc sourcetrong REPL). Kết thúc câu chuyện, vì một câu trả lời xuất sắc khác
Nathan Wallace

@NathanWallace Theo cách tôi đồng ý với bạn, nhưng ở một số khía cạnh thì tôi không. Tên dài đôi khi có xu hướng làm cho chức năng quá mức. Vì vậy, bạn có thể thấy rằng một số hoạt động của bộ lọc chung trên thực tế là chung, trong khi khi đối số applesthay vì xs, bạn nghĩ rằng nó là cụ thể cho táo. Sau đó, tôi cũng sẽ xem xét các tên đối số của hàm để tiếp cận hơn là giả sử một biến vòng lặp for. Vì vậy, nếu cần, bạn có thể có chúng lâu hơn. Như một ý nghĩ cuối cùng: Tôi sẽ để lại cho bạn với "Tên mã không đánh giá cao" concatenative.org/wiki/view/Concatenative%20language/...
wirrbel

Tôi có thể thêm một đoạn trên một cái gì đó như giao diện riêng tư và giao diện công cộng. Đặc biệt là liên quan đến thư viện. Đó là một khía cạnh của chất lượng mã không được nói đến đủ và tôi đã học được rất nhiều về điều này kể từ khi viết câu trả lời đó.
wirrbel
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.