Phiên bản ngữ nghĩa khi sửa một lỗi quan trọng


18

Tôi hiện đang quản lý một thư viện có rất nhiều sử dụng công cộng và tôi đã có một câu hỏi về phiên bản ngữ nghĩa . Tôi muốn cấu trúc lại một phần khá quan trọng của thư viện được triển khai không chính xác - và luôn luôn được thực hiện không chính xác. Nhưng làm điều này có nghĩa là thay đổi API công khai, đây là một quyết định chính.

Thay đổi tôi muốn thực hiện xoay quanh cách sử dụng các trình vòng lặp. Hiện tại, người dùng phải làm điều này:

while ($element = $iterator->next()) {
   // ...
}

Điều này là không chính xác, ít nhất là trong giao diện Iterator gốc của PHP . Tôi muốn thay thế bằng cái này:

while ($iterator->valid()) {
   $element = $iterator->current();
   // ...
   $iterator->next();
}

tương tự như:

foreach ($iterator as $element) {
    // ...
}

Nếu bạn xem hướng dẫn của Tom về phiên bản ngữ nghĩa, anh ta nói rõ rằng mọi thay đổi đối với API công khai (tức là những thay đổi không tương thích ngược), sẽ chứng minh một bản phát hành chính. Vì vậy, thư viện sẽ nhảy từ 1.7.3 lên 2.0.0, mà đối với tôi, là một bước đi quá xa. Chúng tôi chỉ nói về một tính năng được sửa chữa.

Tôi có kế hoạch cuối cùng sẽ phát hành 2.0.0, nhưng tôi nghĩ rằng đây là khi bạn viết lại hoàn toàn thư viện và thực hiện nhiều thay đổi API công khai. Việc giới thiệu tái cấu trúc này có đảm bảo phát hành phiên bản chính không? Tôi thực sự không thể thấy nó hoạt động như thế nào - tôi cảm thấy thoải mái hơn khi phát hành nó dưới dạng 1.8.0 hoặc 1.7.4. Có ai có lời khuyên nào không?


Điều gì ngăn cản bạn giữ khả năng tương thích ngược?
mouviciel

Hiện tại, next()phương thức được sử dụng để truy xuất phần tử hiện tại VÀ di chuyển con trỏ bên trong về phía trước. Sai chỗ nào. next()nên di chuyển con trỏ và current()được sử dụng để truy xuất ...
hohner

6
Vì vậy, trong phiên bản mới, mọi người không nên quan tâm đến giá trị trả về next()chỉ di chuyển con trỏ, điều này thực sự không phá vỡ tính tương thích
ratchet freak

Câu trả lời:


29

Bạn do dự vì bạn không muốn tạo phiên bản ngữ nghĩa, bạn muốn tạo "phiên bản hỗ trợ quảng cáo". Bạn mong đợi một số phiên bản "2.0" để nói với cả thế giới rằng bạn có một loạt các tính năng thú vị mới trong thư viện của bạn, không phải là bạn đã thay đổi API. Điều đó ổn (nhiều công ty phần mềm và / hoặc nhà phát triển làm điều đó). IMHO bạn có các tùy chọn sau:

  • bám sát phiên bản ngữ nghĩa và sống với thực tế là bạn phải thay đổi số phiên bản thành 2.0.0
  • thay đổi sơ đồ phiên bản của bạn thành 4 số. "1.1.7.3" là phiên bản của bạn bây giờ, "1.2.0.0" là phiên bản tiếp theo sau khi thay đổi API và "2.0.0.0" là phiên bản đầu tiên của "họ sản phẩm 2.x hoàn toàn mới"
  • làm cho bản sửa lỗi của bạn tương thích ngược (vì vậy đừng thay đổi chức năng của next, chỉ cần thêm validvà các currentchức năng). Sau đó, bạn có thể sử dụng "1.8.0" làm số phiên bản tiếp theo. Nếu bạn nghĩ việc thay đổi hành vi nextlà thực sự quan trọng, hãy thực hiện trong 2.0.0.

Nhiều như lựa chọn cuối cùng sẽ là giải pháp hoàn hảo: bạn không thể yêu cầu next()tiếp tục làm những gì nó đang làm. Để thực hiện các chức năng chính xác, nó phải làm một cái gì đó khác nhau. Vì vậy, nếu tôi làm cho nó tương thích ngược - chức năng / sửa lỗi mới cũng sẽ sai và làm suy yếu toàn bộ điểm thay đổi.
hohner

2
Đề xuất rộng hơn mà bạn thực hiện trong viên đạn thứ ba của mình (làm cho bản sửa lỗi tương thích ngược) là một gợi ý tốt để xem xét. Nó có thể không hoạt động trong trường hợp cụ thể này, nhưng kỹ thuật tổng thể là đáng xem xét. Chức năng kết thúc phức tạp hơn nhưng đây có thể là một tuyến khả thi.

Cảm ơn tất cả mọi người: nếu tôi có thể chấp nhận hai tôi sẽ. Cuối cùng tôi đã hack next()phương thức mới để thực hiện tất cả các chức năng mới, cộng với những gì cần thiết để làm cho tương thích ngược. Cảm giác thật kinh khủng khi phải làm mờ chức năng mới như thế này, nhưng hey ho.
hohner

10
@hohner: Bây giờ cũng là lúc ghi lại hành vi cũ là không dùng nữa, vì vậy bạn có thể xóa nó trong 2.0.0.
Jan Fabry

7

Gắn bó với hướng dẫn của Tom để tạo phiên bản ngữ nghĩa.

Bất kỳ thay đổi đáng kể nào đối với API công khai phải được thực hiện tại một trong hai điểm sau:

  1. Không bao giờ
  2. Tại một bản cập nhật phát hành lớn

Nhân tiện, phiếu bầu của tôi là dành cho người đầu tiên. Nhưng tôi thừa nhận nó chỉ thích hợp cho những thứ vặt vãnh.

Vấn đề là duy trì khả năng tương thích ngược và đảm bảo bạn không phá vỡ mọi thứ cho những người dùng API trước đó.

Về bản chất, bạn đang tạo ra một lỗi lập chỉ mục cho những người dùng của bạn không biết về sự thay đổi. Buộc thay đổi như thế này buộc tất cả người dùng của bạn phải làm như sau:

  1. Mã sửa lỗi để sử dụng phương pháp mới
  2. Xác thực bản sửa lỗi và đảm bảo rằng nó không phá vỡ bất cứ thứ gì
  3. Gửi bản phát hành mới của sản phẩm cho người dùng cuối của họ

Điều đó có khả năng có thể là rất nhiều nỗ lực, đặc biệt là khi bạn xem xét có bao nhiêu dự án có các trường hợp thử nghiệm để xác nhận các thay đổi như thế này. Lượng hợp chất nỗ lực khi bạn xem xét số lượng người dùng xuôi dòng từ người dùng của bạn, những người cũng sẽ cần cập nhật cài đặt của họ.

Đối với một cái gì đó nhỏ này, tôi sẽ để nó đi và không bận tâm với nó.
Nếu nó thực sự làm phiền bạn (có vẻ như nó làm hoặc bạn sẽ không hỏi) thì tôi sẽ làm như sau.

  1. Tạo nhánh v2.0.0 trong cây mã của bạn
  2. Đóng góp đầu tiên cho nhánh v2.0.0, đây là thay đổi
  3. Gửi bản xem trước Release Notestrước khi phát sóng rằng sự thay đổi đang đến

Và sau đó hãy kiên nhẫn vì sẽ mất một thời gian để tích lũy những thứ khác mà biện minh cho việc nâng cấp số phiên bản lên một bản phát hành chính mới. Thông báo nâng cao (phần 3) cho bạn thời gian để nhận phản hồi từ người dùng cuối để tìm hiểu mức độ ảnh hưởng của sự thay đổi sẽ xảy ra.


Một giải pháp thay thế là thêm một chức năng mới hoạt động theo cách bạn muốn.

Nếu bạn có foo()thì bạn sẽ tạo fooCorrect()để cung cấp bản sửa lỗi nhưng cũng bảo toàn hoàn toàn khả năng tương thích ngược. Và đến một lúc nào đó bạn có thể phản đối foo()để cho người khác biết không sử dụng nó.

Thách thức ở đây là bạn sẽ tìm thấy một cái gì đó khác trong fooCorrect()đó bắt buộc phải cập nhật và bạn kết thúc với fooCorrectedCorrect()hoặc một số điều vô nghĩa ngớ ngẩn khác.

Nếu bạn thực sự muốn sửa lỗi này ngay bây giờ, phương pháp thay thế này có lẽ là con đường tốt nhất. Hãy chú ý và cảnh giác với việc tạo ra nhiều chức năng bổ sung theo cách này vì nó làm cho API khó hoạt động hơn. Và nhận thức đó có thể đủ để ngăn chặn những vấn đề tồi tệ nhất.

Nhưng đây có thể là cách tiếp cận "ít tệ nhất" để xem xét cho một cái gì đó nhỏ.


Tôi đồng ý với bạn. Vấn đề tôi gặp phải là tôi muốn viết lại hoàn toàn thư viện cho v2.0.0 (vì có rất nhiều vấn đề cần được khắc phục); Vì vậy, tôi không muốn một thay đổi nhỏ như các trình vòng lặp tạo thành nền tảng của thay đổi lớn này. Vì vậy, các lựa chọn của tôi là: bỏ qua lỗi này, hoặc sửa lỗi và đưa nó vào một phiên bản chính mới?
hohner

@hohner - câu trả lời được cập nhật để cung cấp một cách tiếp cận khác với việc tạo các chức năng mới. Hãy lưu ý rằng rất nhiều mới, chức năng tương tự đặt tên là gần như là xấu như thay đổi API riêng của mình.

3
@hohner: Sai một cách nhất quán> không nhất quán đúng trong trường hợp này. Hành vi vẫn hoạt động, nó không phải là thành ngữ. Hãy xem xét rằng nếu bạn thực hiện thay đổi này, bạn đang phá vỡ mã khách hàng. Để làm điều này mà không có cảnh báo sẽ không được đánh giá cao.
Phoshi

@ GlenH7 Trong trường hợp này, sử dụng phương pháp được đặt tên thay thế sẽ không hoạt động. Trình lặp riêng của PHP dựa vào các phương thức này (tức là next()không nextCorrect()). Tôi sẽ xem liệu tôi có thể sửa đổi next () để nó tương thích ngược VÀ hoạt động khi triển khai Iteratorgiao diện không.
hohner

1
@Phoshi Bạn đang ở trên - Tôi hoàn toàn đồng ý ngay bây giờ. Bây giờ là lúc để thử và mã hóa điều không thể: D
hohner
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.