Tin tức mới

Thợ lành nghề #29: Giám sát liều lượng (6) – Di chuyển ngày tháng

Thợ lành nghề

6/8/2004

….Tiếp nối câu chuyện phần trước

21/2/2002, 1130

Giữa tháng 4 và tháng 7 năm 1939, tin tức chính trị và thiên văn học tiếp tục theo chiều hướng xấu hơn. Chiến tranh dường như là điều không thể tránh, và Trái Đất vẫn là trọng tâm trên hướng đi có thể xảy ra nhất của Clyde. Đội ngũ Stockholm thay đổi từ một nhóm nhỏ các nhà khoa học ở quán bar thành mạng lưới nhỏ bí mật của các nhà khoa học trên khắp thế giới. Mặc dù nhóm không có lãnh đạo chính thức, nhưng Lise Meitner lại là người cung cấp tầm nhìn và hướng đi. Bố trí ở Stockholm, bà duy trì khả năng kết nối với các đồng nghiệp trên khắp thế giới. Bà bắt đầu tuyển dụng họ với cách chậm và chắc.

Vào tháng 9, khi những sự chống đối từng đợt nhỏ lẻ cuối cùng cũng bùng nổ thành cuộc chiến toàn diện ở châu Âu, đội ngũ Stockholm có những thành viên đến từ các quốc gia trung lập và thù địch như nhau. Nhóm này không biết chính xác sẽ làm gì sắp tới, nhưng bọn họ tin rằng thế giớ sẽ giành nhiều sự chú ý cho Clyde hơn là cuộc chiến. Họ cũng bị thuyết phục rằng các phản ứng phân hạch Uranium mới được khám phá sẽ là chìa khóa để đánh bại lại Clyde, và sẽ thật khủng khiếp nếu được dùng như một vũ khí chiến tranh. Họ cũng biết rằng các nước tham chiến sẽ coi quan điểm của họ là sự phản nghịch.

Jerry và Jasmine đi phía trước khi chúng tôi trở về phòng làm việc. Suốt đoạn đường, họ cười nói và hành động như những người bạn thân thiết. Avery và tôi lại nhìn như rất chán ghét nhau, nhưng vẫn giữ im lặng.

Trở về phòng làm việc, chúng tôi ngồi xuống và lại bắt đầu làm việc với kiểm thử fixture.

“Vậy, chúng ta sẽ làm gì với ngày tháng?” Jerry hỏi.

“Chúng ta cần lưu nó lại để ứng dụng có thể truy cập khi nó cần biết ngày tháng của hôm nay.” Tôi đáp lời.

Avery vẫn không thích như vậy, tỏ thái độ bằng cách liếc mắt và giữ im lặng.

“Đúng thế.” Jerry nói. “Giờ thì để tao chỉ cho mày biết cách chúng ta làm điều đó.”

Hắn ta gõ những dòng code sau.

public class UtilitiesTest extends TestCase {
public void testDateGetsTodayWhenNoTestDateIsSpecified() throws Exception {
Date now = new Date();
Utilities.testDate = null;
assertEquals(now, Utilities.getDate());
}
}

Jerry nhìn sang Avery và hỏi: “Mày có thể làm nó thành công được không Avery?”

Avery thở dài một cách khinh khỉnh khi hắn ta nhìn bàn phím. Hắn nói: “Tôi đoán là anh muốn tôi dùng một biến công khai.” Và hắn gõ những dòng sau mà không đợi câu trả lời:

public class Utilities {
public static Date testDate = null;
public static Date getDate() {
return new Date();
}
}

Hắn nhấn vào nút kiểm tra và thấy được một thanh màu xanh lá cây.

“Tuyệt.” Jerry nói.

Nhưng Avery sốt ruột nhìn Jerry và nói:

“Ừ, nhưng nhìn đây.”

Avery bắt đầu nhấn nút kiểm tra liên tục. Hắn có được ba hoặc bốn thanh màu xanh và sau đó kiểm thử thất bại với dòng nhắn:

junit.framework.AssertionFailedError:
expected:<Tue Feb 21 11:33:16 2000 (subjective)>
but was: <Tue Feb 21 11:33:16 2000 (subjective)>

Trước khi Jerry kịp phản ứng, Avery nói: “Anh đã viết kiểm thử sai. Đôi khi hai ngày không thể giống nhau hoàn toàn. Sự khác biệt dù có thể nhỏ như một phần nghìn giây nhưng cũng đủ để làm kiểm thử thất bại. Tôi sẽ sửa nó bằng cách viết đoạn kiểm thử thông minh hơn một chút.” Và hắn thay đổi kiểm thử như sau:

public void testDateGetsTodayWhenNoTestDateIsSpecified() throws Exception {
GregorianCalendar now = new GregorianCalendar();
GregorianCalendar systemDate = new GregorianCalendar();
Utilities.testDate = null;
now.setGregorianChange(new Date());
systemDate.setGregorianChange(Utilities.getDate());
long difference = now.getTimeInMillis() - systemDate.getTimeInMillis();
assertTrue(Math.abs(difference) <= 1);
}

Và rồi Avery quay về phía Jerry và nhấn phím kiểm tra liên tục. Hắn không nhìn màn hình lấy một lần, nhưng kiểm thử lần nào cũng thành công.

Jerry lạnh lùng nhìn Avery và nói: “Tao thừa nhận điểm này, Avery. Cảm ơn. Nhưng, hàm này vẫn có chút lộn xộn.” Và Jerry lấy bàn phím lại và thực hiện các thay đổi sau:

public void testDateGetsTodayWhenNoTestDateIsSpecified() throws Exception {
Utilities.testDate = null;
assertTrue(DatesAreVeryClose(new Date(), Utilities.getDate()));
}
private boolean DatesAreVeryClose(Date date1, Date date2) {
GregorianCalendar c1 = new GregorianCalendar();
GregorianCalendar c2 = new GregorianCalendar();
c1.setGregorianChange(date1);
c2.setGregorianChange(date2);
long differenceInMS = c1.getTimeInMillis() - c2.getTimeInMillis();
return Math.abs(differenceInMS) <= 1;
}

“Được rồi, tao nghĩ nó thể hiện ý đồ của chúng ta tốt hơn một chút.” Jerry nói khi anh ta quan sát kiểm thử liên tục thành công.

Avery chỉ phát ra tiếng khụt khịt.

Tôi có chút cảm giác như tôi đang ở khu vực chiến sự vậy. Tôi không biết tại sao Avery và Jerry lại tỏ ra thù địch nhau như vậy, nhưng tôi lo rằng nó làm họ sao nhãng công việc hiện tại. Nên tôi giật lấy bàn phím và nói:
“Được rồi, tôi nghĩ tôi biết lần kiểm thử tiếp theo là gì rồi.” Và tôi viết:

public void testThatTestDateOverridesNormalDate() throws Exception {
Date t0 = new GregorianCalendar(1959, 11, 5).getTime();
Utilities.testDate = t0;
assertEquals(t0, Utilities.getDate());
}

Jerry nhìn kiểm thử thất bại và nói: “Phải rồi, Alphonse. Giờ thì làm nó thành công đi.”

Nhưng Avery giật lấy bàn phím và nói: “Tôi sẽ làm.” Và viết đoạn mã mạch lạc sau:

public static Date getDate() {
return testDate != null ? testDate : new Date();
}

Và khi bài kiểm thử vượt qua, hắn càu nhàu: “Và lại thêm một lần chết tiệt lãng phí thời gian để có một dòng mã đơn giản và hiển nhiên hoạt động.”

“Nó không bị lãng phí…” Jerry nói. Nhưng sau đó anh ta dừng lại và lắc đầu. Anh ấy hít môt hơi thật sâu và nói: “Được rồi, giờ thì chúng ta phải lấy được DtrackContext fixture để thiết lập testDate.” Vậy nên anh ta viết đoạn kiểm thử sau:

public class DTrackContextTest extends TestCase {
public void testExecuteSetsTestDate() throws Exception {
Date t0 = new GregorianCalendar(1959, 11, 5).getTime();
DTrackContext c = new DTrackContext();
c.todaysDate = t0;
Utilities.testDate = null;
c.execute();
assertEquals(t0, Utilities.testDate);
}
}

Khi tôi nhìn thấy kiểm thử thất bại, tôi nói: “Hay lắm, Jerry, tôi hiểu điều anh vừa làm. Anh đã tạo một instance của fixture và đã chèn ngày t0 vào todayDate giống như cách của FitNesse1. Sau đó anh chờ đợi t0 bằng cách nào đó được đặt vào trong trường Utilties.testDate. Tôi đoán rằng phương thức thực thi của fixture làm điều này, phải không?”

“Đúng thế. Hãy nhớ rằng bảng FitNesse mà chúng ta đang làm việc sẽ trông như thế này:” và anh ta đẩy bảng lên màn hình.

“Khi FitNesse xử lý bảng này, nó sẽ đặt ngày 2/21/2002 vào trong trường todaysDate của DTrackContext fixture, và sau đó nó sẽ gọi excute() trên fixture đó.”

“Được rồi, sau đó tôi có thể làm bài kiểm thử này vượt qua bằng cách làm như thế này:” và tôi chộp lấy bàn phím rồi gõ:

public class DTrackContext extends ColumnFixture {
public Date todaysDate;
public void execute() throws Exception {
Utilities.testDate = todaysDate;
}
}

Bài kiểm thử đã qua được, và tôi cũng hiểu đươc một chút về cách FitNesse hoạt động. Rồi Jerry hỏi: “Mày cũng nên chạy cả kiểm thử chấp nhận nữa.” Nên tôi đi đến trang RegisterNormalSuit trên máy chủ FitNesse và nhấn nút kiểm tra. Không có gì thay đổi cả.

“Tốt.” Jery nói. “Chúng ta không phá hỏng thứ gì cả.”

“Chúng ta cũng chẳng đạt được cái gì cả.” Avery nói.

Jerry lườm Avery, buồn bã nhìn tôi, sau đó thở dài và rời khỏi ghế đi tới chỗ Jean. Hai bọn họ nhanh chóng bắt đầu nói chuyện. Tôi nhìn Avery và nói: “Avery, có chuyện gì vậy, sao mày kêu ca nhiều vậy chứ?”

“Lão ta là một thằng ngốc!” Avery nói. “Anh ta chẳng biết tí gì về thiết kế hướng đối tượng cả, và những kiểm thử vô nghĩa này chỉ là những thứ vặt vãnh giết thời gian dành cho những kẻ ngốc. Chúng ta đã làm việc về yêu cầu kiểm soát đồ bảo hộ trong gần 4 tiếng đồng hồ, và mã tạo thành mà chúng ta có được để cho thấy điều đó là như thế này đây:” và hắn đẩy lớp Utilities lên màn hình.

public class Utilities {
public static Date testDate = null;
public static Date getDate() {
return testDate != null ? testDate : new Date();
}
}

“Và ngay cả cái lớp này cũng chẳng là gì ngoại trừ là một mẹo để cho phép kiểm thử. 4 tiếng đồng hồ, 3 con người, đó là 12 tiếng cuộc đời, và chúng ta đã làm được phô mai Jack cheese (tên 1 loại phô mai)! Tao nghĩ cả nhóm này thật thảm hại. Tao nghĩ ngài C chắc chắn là một thằng đần. Sao ông ta có thể nghĩ rằng ông ta sẽ hoàn thành dự án DTrack trong 2 tháng khi mà chúng ta lãng phí hàng giờ liền mà chẳng làm gì ngoại trừ những lần kiểm thử ngu ngốc kia? Nếu tao mà là thuyền trưởng, tao sẽ tống khứ ngài C. ra ngoài khu airlock.”

Khi Avery huênh hoang, giọng hắn to hơn và mắt hắn bắt đầu lồi ra. Hắn không nhận ra rằng Jerry và Jean đang đi ngay đằng sau hắn.

“Thế là quá đủ rồi đấy, chàng trai trẻ!” Jean nghiêm nghị nói.

Avery vô thức nhìn quanh, và mặt hắn ta từ giận dữ đổi thành hoảng hốt. Jean không còn là một người bà ân cần mà chúng tôi từng biết tới. Bà ấy hoàn hoàn trông rất khác. Nó thể hiện rất rõ qua tông giọng và biểu cảm trên khuôn mặt của bà đến mức chúng tôi không dám ho he hay nhúc nhích.

“Nói về thuyền trưởng và những chuyên viên phần mềm chủ chốt của ông ấy theo cách đó là hành vi không thể chấp nhận được trong bộ phận này. Tôi sẽ không tha thứ. Avery, hôm qua cậu xúc phạm Jason tệ đến mức anh ta từ chối làm việc với cậu lần nữa. Vậy nên tôi để cậu làm việc với Alphonse để xem liệu rằng nhân cách tốt của cậu ấy có thể thay đổi được cậu không. Hai người có vẻ hòa thuận, và tôi thực sự hy vọng rằng cậu đã học được bài học đắt giá. Nhưng giờ cậu lại tỏ ra chống đối Jerry, và với cả đội, cả bộ phận và ngay cả con tàu. Chúng tôi nên làm gì với cậu đây?”

…Vẫn còn tiếp

Tác giả: Robert C. Martin

Đăng ký nhận bộ tài liệu kỹ năng dành cho lập trình viên (video hướng dẫn + slide) tại đây

Xem thêm về Tạp Chí Lập Trình Vol 4 tại đây


Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.

Leave a Reply

Your email address will not be published. Required fields are marked *