2012-12-18 19 views
7

Tôi đã tìm kiếm một công cụ chất lượng mã Ruby vào ngày khác, và tôi đã đi qua đá quý pelusa, trông thú vị. Một trong những điều mà nó kiểm tra là số lượng các câu lệnh khác được sử dụng trong một tệp Ruby đã cho.Tại sao các phát biểu khác không được khuyến khích trong Ruby?

Câu hỏi của tôi là, tại sao những điều này xấu? Tôi hiểu rằng các tuyên bố if/else thường thêm nhiều phức tạp (và tôi nhận thấy rằng mục tiêu là để giảm độ phức tạp của mã) nhưng làm thế nào để một phương pháp kiểm tra hai trường hợp được viết mà không cần else?

Để tóm tắt, tôi có hai câu hỏi:

1) Có một lý do nào khác hơn giảm phức tạp của mã mà else có thể tránh được?

2) Dưới đây là phương pháp mẫu từ ứng dụng tôi đang xử lý sử dụng câu lệnh else. Làm thế nào bạn sẽ viết này mà không có một? Lựa chọn duy nhất tôi có thể nghĩ ra sẽ là một tuyên bố ba năm, nhưng có đủ logic ở đây mà tôi nghĩ rằng một tuyên bố ba năm thực sự sẽ phức tạp hơn và khó đọc hơn.

def deliver_email_verification_instructions 
    if Rails.env.test? || Rails.env.development? 
    deliver_email_verification_instructions! 
    else 
    delay.deliver_email_verification_instructions! 
    end 
end 

Nếu bạn là người viết với một nhà điều hành ternary, nó sẽ là:

def deliver_email_verification_instructions 
    (Rails.env.test? || Rails.env.development?) ? deliver_email_verification_instructions! : delay.deliver_email_verification_instructions! 
end 

là đúng? Nếu vậy, không phải là cách khó đọc hơn sao? Câu hỏi else có giúp giải quyết vấn đề này không? Có cách nào khác, tốt hơn, else không có cách nào để viết điều này mà tôi không nghĩ đến?

Tôi đoán tôi đang tìm kiếm các cân nhắc về phong cách tại đây.

+1

Viết tốt trên 'else' dưới dạng mã nguồn tại đây: http://solnic.eu/2012/04/11/get-rid-of-that-code-smell-control-couple.html – michaelmichael

+0

Đó là khá tốt, và một số trong những gì tôi đang tìm kiếm (mặc dù một chút trên đầu của tôi tại các bộ phận). Hãy cẩn thận để đăng câu trả lời, xây dựng, và cho các điểm nghiệp bổ sung, tái cấu trúc ví dụ của tôi hoặc sử dụng một của riêng bạn để minh họa? Hay bạn có cảm thấy bài đăng đó nên hoạt động như một câu trả lời? – nickcoxdotme

+0

Sử dụng quá mức là xấu, như là một sự khăng khăng cứng nhắc mà nó tránh được. Có một thời gian và một nơi, và, với mã viết đúng cách, đôi khi nó là giải pháp đúng. Nó có thể gây nhầm lẫn với mã spaghetti, do đó, tránh viết mã suy nghĩ kém và phần còn lại nên tự lo cho chính nó. –

Trả lời

6

Hãy để tôi bắt đầu bằng cách nói rằng không có bất cứ điều gì thực sự sai với mã của bạn, và nói chung bạn nên biết rằng bất cứ một công cụ chất lượng mã cho bạn thể được hoàn thành vô nghĩa, vì nó thiếu bối cảnh để đánh giá những gì bạn đang thực sự làm.

Nhưng quay lại mã. Nếu có một lớp học mà có đúng một phương pháp mà đoạn

if Rails.env.test? || Rails.env.development? 
    # Do stuff 
else 
    # Do other stuff 
end 

xảy ra, đó sẽ là hoàn toàn tốt (có luôn cách tiếp cận khác nhau để một điều nào đó, nhưng bạn không cần phải lo lắng về điều đó, ngay cả khi các lập trình viên sẽ ghét bạn vì không tranh luận với họ về nó: D).

Bây giờ đến phần khó khăn. Mọi người lười biếng như địa ngục, và do đó đoạn mã giống như trên là mục tiêu dễ dàng để sao chép/dán mã (đây là lý do mọi người sẽ cho rằng người ta nên tránh chúng ngay từ đầu, bởi vì nếu bạn mở rộng một lớp thì bạn có nhiều khả năng chỉ cần sao chép và dán nội dung hơn là thực sự tái cấu trúc nó).

Hãy xem đoạn mã của bạn làm ví dụ. Tôi về cơ bản đề xuất cùng một điều như @Mik_Die, tuy nhiên ví dụ của anh ta cũng dễ bị sao chép/dán như của bạn. Do đó, sẽ phải được thực hiện (IMO) là thế này:

class Foo 
    def initialize 
    @target = (Rails.env.test? || Rails.env.development?) ? self : delay 
    end 

    def deliver_email_verification_instructions 
    @target.deliver_email_verification_instructions! 
    end 
end 

này có thể không áp dụng đối với ứng dụng của bạn như là, nhưng tôi hy vọng bạn sẽ có được ý tưởng, đó là: Đừng lặp lại chính mình. Không bao giờ.Mỗi khi bạn lặp lại chính mình, bạn không chỉ làm cho mã của mình ít bảo trì hơn mà còn dễ bị lỗi hơn trong tương lai, bởi vì một hoặc thậm chí 99/100 lần xuất hiện của bất kỳ thứ gì bạn đã sao chép và dán có thể thay đổi, nhưng một trong những lần xuất hiện còn lại là những gì làm cho @disasterOfEpicProportions vào cuối :)


một điểm mà tôi đã quên được nuôi dưỡng bởi @RayToal (nhờ :), mà là nếu/else cấu trúc thường được sử dụng trong kết hợp với tham số đầu vào boolean, dẫn đến các cấu trúc như thông số này (mã thực tế từ dự án tôi phải duy trì):

class String 
    def uc(only_first=false) 
    if only_first 
     capitalize 
    else 
     upcase 
    end 
    end 
end 

Hãy để chúng tôi bỏ qua các phương pháp đặt tên và vá lỗi rõ ràng ở đây và tập trung vào cấu trúc if/else, được sử dụng để cung cấp phương thức uc hai hành vi khác nhau tùy thuộc vào thông số only_first. Mã như vậy là vi phạm Nguyên tắc về trách nhiệm duy nhất, bởi vì phương pháp của bạn là làm nhiều việc, đó là lý do tại sao bạn nên viết hai phương pháp ngay từ đầu.

+2

Đây là IMHO tái cấu trúc tốt nhất có thể của mã OP. Các câu lệnh 'if' với các phần' else' khác thường bị cau mày bởi vì khi bạn nhìn thấy chúng, các phương thức kèm theo của bạn là ** làm nhiều hơn một điều **, vi phạm SRP (mặc dù tôi sẽ không bao giờ tranh luận cho việc theo dõi 100% số này thời gian). Việc khởi tạo mục tiêu của bạn dựa trên môi trường không làm nhiều thứ; nó đang tính toán mục tiêu chính xác. Sau đó, phương pháp phân phối là rất tốt. +1 –

+0

@RayToal Cảm ơn bạn đã thêm :) Cập nhật câu trả lời của tôi. – fresskoma

2
def deliver_email_verification_instructions 
    subj = (Rails.env.test? || Rails.env.development?) ? self : delay 
    subj.deliver_email_verification_instructions! 
end 
+1

Một sự tái cấu trúc vững chắc của phương pháp tôi đã viết, mà tôi đánh giá cao. Bất kỳ ngữ cảnh nào bạn có thể thêm vào để giải quyết câu hỏi đầu tiên của tôi, tại sao bạn chọn kiểu này và phương thức này cung cấp một cách khách quan một câu lệnh nào với câu lệnh 'else'? Điều đó, tôi có thể đánh dấu chính xác. – nickcoxdotme

Các vấn đề liên quan