Tag Archives: Code

Thợ lành nghề #19: Kiên nhẫn (SMCRemote Phần 9)

Gã học việc đã quen với sự chậm rãi của người hướng dẫn mới, hắn đã học được trong sự tôn trọng kiến thức và bộ đồ đan len.

Tác giả: Robert C. Martin

Người dịch: Hoàng Ngọc Diêu | Biên tập: Phạm Anh Đới

Jean đưa tôi đến thang máy để xuống tầng ngầm 36 thuộc cánh gamma, phòng khách của các tay du mục. Bà nói tầng ngầm này -1- làm các khớp xương của bà hết sức dễ chịu. Khi chúng tôi đến nơi, tôi thấy có Jerry, Jasmine và một vài tay du mục đang tụ lại một bàn. Jean cũng thấy họ và rảo bước đến nơi họ ngồi. Tôi miễn cưỡng đi theo.

“Chào các cô, các cậu thân mến!” Bà thốt lên mừng rỡ như thể không gặp họ sau nhiều tuần lễ. Bọn họ đều chào lại cũng với vẻ thân mật (như bà dành cho họ). Thế rồi bà cáo lỗi và rảo bước về chiếc ghế đấm bóp bỏ trống, để lại một mình tôi đối diện với hai cựu huấn luyện viên.

“Chào Jerry; chào cô J. Đằng ấy có khoẻ không?”

Jerry trông có vẻ sửng sốt. “Cái của khỉ ‘cô J’. gì đây nhỉ?”

Jasmine vội vàng lảng đi thật nhanh cho xong chuyện: “Quên cái chuyện ‘Ms. J’ đi cao thủ. Chuyện này đã quá đủ.” Đôi mắt nàng chưa bao giờ dịu như vậy, và tôi nhận ra chính mình cũng không thể trả lời nàng một cách khéo léo và gọn gàng.

Chiếc xe phục vụ cà-phê đi ngang. Tôi mừng rỡ vớ ngay một cốc vì có dịp may để đánh trống lảng và rồi tôi lại tiếp tục đối diện với các tay cựu huấn luyện viên này.

“Jean đối xử với cậu thế nào hở cao thủ?” Jasmine hỏi.

Jerry chêm vào: ” Ừa, làm sao mày “gỡ” được một “món” của bà ta vậy?”

Sau khi ở trong hoàn cảnh không thể nói hơn ba chữ một lần suốt cả buổi sáng với Jean, nỗi bực dọc trong lòng tôi vỡ tung ra.

“Tôi không “gỡ” gì hết, bà ấy bất thình lình xuất hiện sáng nay. Thật tình mà nói, làm việc với bà tôi thấy hơi khó chịu. Bà ta lúc nào cũng gọi tôi là ‘cậu bé thân mến’; và bà nói quá nhiều, nghỉ giải lao cũng quá nhiều. Chúng tôi không hoàn tất được bao nhiêu việc cả. Tôi không chắc tôi có muốn tiếp tục làm việc với bà ta hay không.”

Jasmine và Jerry nhìn tôi, họ nhìn nhau, rồi đột nhiên phá ra cười. Jerry trở lại bình thường một cách nhanh chóng nhưng Jasmine không thể tự chủ được. Mỗi khi nhìn tôi, nàng lại cười phá lên; tiếng cười hao hao như giọng con hải sư gọi bạn -2-.

“Gì vậy?” tôi hỏi.

Jerry dẫn tôi qua một bên trong khi Jasmine tiếp tục tuôn ra hàng tràng cười lảnh lót. “Alphonse, mày không biết mày may mắn như thế nào. Bọn tao ở đây đứa nào cũng sẵn sàng đánh đổi bất cứ điều gì -3- để được làm việc với Jean. Tao biết bà ấy hơi khác thường nhưng đừng nên lầm với cái vẻ “bà ngoại” bên ngoài của bà ta. Bà ấy là một trong những tay thiện nghệ nhất và mày sẽ học được rất nhiều từ bà.”

Tôi ngớ ra nhưng không thể đối đáp thêm được tí gì vì ngay khi ấy Jean khập khiễng từ chiếc ghế đấm bóp đi đến.

“Ơn trời, tôi cảm thấy khoẻ hơn rất nhiều.”

Trao đổi với Jerry tôi tìm được những thông tin nhiều hơn cần thiết cho nên tôi đổi chủ đề bằng cách đề nghị gọi người phục vụ cà phê.

“Ồ thôi cậu bé. Tôi nghĩ chúng ta nên về lại tầng 6 thiếu tiện nghi của chúng ta và tiếp tục làm việc với SMCRemote, cậu có nghĩ thế không? Chúng mình còn quá nhiều thứ phải lo trong ngày hôm nay và hẳn nhiên chúng ta sẽ chẳng thực hiện được nếu chúng ta ở đây, phải không nào? …. Không hiểu sao Jasmine lại phát ra những âm thanh khủng khiếp vậy nhỉ? Âm thanh giống như con thú nào đó đang giẫy chết vậy. Jasmine, uống chút nước đi cô bé thân mến…”

Chúng tôi dùng thang máy đi về phòng làm việc. Tầng lầu cao này làm Jean chậm chạp hẳn. Ở dưới phòng khách bà ta nhanh nhẹn hơn rất nhiều.

Sau khi yên ổn ngồi vào bàn máy, bà nói: “Nào, Alphonse thân mến, tôi nghĩ chúng ta nên xem thử có thể chạy được đoạn lệnh mình đã tạo ra không. Cậu nghĩ sao?”

Tôi đã ngẫm nghĩ cách thực hiện nên tôi đồng ý ngay. “È… vâng.”

“Tốt lắm cậu bé thân mến. Bây giờ thế này, đoạn lệnh mình sắp chạy sẽ gọi chương trình biên dịch SMC, tôi nghĩ việc đầu tiên mình cần làm là tạo ra một đoạn mã đơn giản để trình dịch đó đọc. Thế, hãy viết một cái kiểm thử dùng để tạo tệp tin này đi, rồi gọi trình dịch và kiểm tra xem trình dịch có tạo ra tệp tin xuất đúng hay không.”

Bà lại lôi ra bộ đồ đan len và không hề tỏ ý muốn động đến bàn đánh, bởi vậy tôi vớ lấy nó và bắt đầu gõ:

public void testExecuteCommand() throws Exception {
    File sourceFile = new File("simpleSourceFile.sm");
    PrintWriter pw = new PrintWriter(new FileWriter(sourceFile));
    pw.println("
}
Không biết phải tiếp tục thế nào nên tôi nhìn bà với ý chờ đợi.

“Tốt lắm cậu bé thân mến. Đây, để tôi gõ vào cú pháp SMC cho cậu.”

public void testExecuteCommand() throws Exception {
    File sourceFile = new File("simpleSourceFile.sm");
    PrintWriter pw = new PrintWriter(new FileWriter(sourceFile));
    pw.println("Context C");
    pw.println("FSMName F");
    pw.println("Initial I");
    pw.println("{I{E I A}}");
    pw.close();
}

“Nó có nghĩa thế nào vậy Jean?”

“À, cậu bé thân mến, với mục đích riêng của chúng ta thì nó có nghĩa là trình dịch sẽ tạo ra tệp tin tên là F.java. Lúc này cậu chỉ cần biết ngần ấy thôi. Tuy nhiên, khi cậu trở về phòng riêng của mình, cậu nên tìm kiếm tài liệu SMC và tham khảo thêm; việc này là việc cần thiết. Tôi viết tài liệu này nhiều năm về trước đó cậu bé thân mến và tôi vẫn nghĩ nó là một trong những tài liệu hay của tôi. Nó gọi là “Care and Feeding of the State Map Compiler” -4. Bây giờ mình xem thử có chạy được lệnh biên dịch ấy không.”

Tôi không chắc phải làm gì để chạy lệnh này; nhưng tôi học được từ Jerry và Jasmine thông thường cách hay nhất là chỉ viết các cú gọi diễn tả ý định của mình. Bởi thế tôi tiếp tục gõ:

public void testExecuteCommand() throws Exception {
    File sourceFile = new File("simpleSourceFile.sm");
    PrintWriter pw = new PrintWriter(new FileWriter(sourceFile));
    pw.println("Context C");
    pw.println("FSMName F");
    pw.println("Initial I");
    pw.println("{I{E I A}}");
    pw.close();
    
    String command = SMCRemoteServer.buildCommandLine("simpleSourceFile.sm");
    assertEquals(true, SMCRemoteServer.executeCommand(command));

    File outputFile = new File("F.java");
    assertTrue(outputFile.exists());
    assertTrue(outputFile.delete());
    assertTrue(sourceFile.delete());
}

“Mỹ mãn! Alphonse. Tôi nghĩ rằng đoạn trên nắm bắt phần kiểm thử một cách rất đáng khen. Chúng ta chưa viết executeCommand nhưng chắc chắn mình có thể diễn đạt cách mình muốn nó được gọi ra sao, phải không nào. Bây giờ chúng ta hãy tạo stub -5- cho bước này và xem đoạn test bị hỏng. Lúc nào tôi cũng thấy thú vị khi thấy chúng hỏng, cậu có nghĩ thế không?”

Thế rồi tôi bấm vào executeCommand và chọn “Create Method”, và IDE của tôi -6- tạo stub method tôi muốn. Và rồi, y như thật, phần test bị hỏng.

public class SMCRemoteServer {
    ...
    
    public static boolean executeCommand(String command) {
        return false;
    }
}

“Được rồi cậu bé thân mến, hãy làm cho cái kiểm thử ấy đạt nhé.”

Jean lại có vẻ mệt mỏi. Tôi biết bà sắp muốn nghỉ tay thêm lần nữa. Đã gần đến giờ ăn trưa, nên tôi hy vọng bà có thể nán lại cho đến lúc ấy. Tôi nhanh chóng rảo xuyên qua javadocs để tìm cách thực thi một lệnh. Jean thấy vậy bèn nói:

“Trong Runtime class đó, cậu bé. Thế rồi tôi gõ đoạn mã tôi nghĩ nó chạy.

public static boolean executeCommand(String command) {
    Runtime rt = Runtime.getRuntime();
    try {
        rt.exec(command);
        return true;
    }catch (IOException e) {
        return false;
    }
}

Nhưng khi tôi chạy phần kiểm thử, nó không tìm được tệp tin xuất. Tôi tìm trong thư mục và quả thật, F.java không có ở đó.

“Sao nó hỏng vậy, Jean?”

Bà nhìn lên và bảo: “Cậu không đợi cho process chấm dứt đó cậu bé thân mến. Khi cậu thực hiện một lệnh, nó tạo ra một process mới chạy đồng thời với process của cậu. Cậu phải đợi cho nó hoàn tất trước khi thoát ra khỏi executeCommand.”

Tôi tham khảo phần Runtime.exe trong JavaDoc và thấy nó trả lại một object Process. Tôi cũng thấy rằng mình có thể đợi object Process hoàn tất và có thể truy khảo tình trạng thoát -7- của nó. Bởi thế tôi tạo những thay đổi như sau:

public static boolean executeCommand(String command) {
    Runtime rt = Runtime.getRuntime();
    try {
        Process p = rt.exec(command);
        p.waitFor();
        return p.exitValue() == 0;
    }catch (Exception e) {
        return false;
    }
}

Lần này phần kiểm thử đạt.

“Cũng không khó lắm.” Tôi phát biểu.

“Tất nhiên là không rồi cậu bé thân mến. Chúng ta chỉ chạy một cái lệnh thôi mà. Tất nhiên nó sẽ trở nên phức tạp hơn một chút khi chúng ta phải nắm bắt thông điệp mà trình dịch thường in ra trên console -8-. Chúng ta sẽ phải gắn vào standard output và standard error 9- của Process. Nhưng hãy làm chuyện ấy sau giờ ăn trưa cậu bé thân mến, tôi bắt đầu cảm thấy đói, cậu có thấy vậy không?”

Tôi thở dài và đứng dậy. Tôi cảm thấy dường như chúng tôi vẫn tiến triển chậm chạp. Tuy vậy, xét lại thì tôi thấy chúng tôi đã hoàn tất phần client và làm cho server chạy được trong nửa ngày đầu làm việc với Jean. Chúng tôi không dành tí thời gian nào cho việc tìm lỗi. Có lẽ chúng tôi tiến triển nhanh hơn tôi nghĩ.

Jean bỏ bộ đồ đan vào giỏ và giăng ra chiếc áo len. “Đây, cậu bé thân mến, thử cái này vào xem.”

Nếu không còn gì đáng để nói thì chiếc “đồ” này của Jean dạy cho tôi thêm tính kiên nhẫn.

-1-    Nguyên văn “low-g”, một dạng tiếng tiếng lóng chỉ cho “lower ground”. Đây là lối nói rất Mỹ.

-2-    “sounded like a sea lion calling to its mate” tạm dịch là “tiếng cười hao hao như giọng con hải sư gọi bạn”. Có lẽ tác giả muốn phần nào bộc tả tình cảm của Alphonse lúc ấy bằng lối so sánh đầy hình tượng này. Theo tôi, giọng con hải sư gọi bạn quả thật khó có thể “cảm” nổi (nhưng có lẽ lại hấp dẫn đối với giống hải sư chăng).

-3-    “Give our eyeteeth”, một thành ngữ chỉ cho sự đánh đổi rất đắt giá.

-4-    “Care and Feeding of the State Map Compiler”, tạm dịch là “Chăm sóc và bồi dưỡng trình dịch State Map”.

Trong nguyên bản, tác giả cho đường dẫn đến: http://www.objectmentor.com/resources/downloads/bin/smcJava.zip để tải smcJava.zip.

-5-    stub theo nguyên bản, tạm dịch là nội đệm và có lẽ skeleton sẽ là ngoại đệm (dịch theo ngữ cảnh). Đối với những ai tiếp xúc với RMI (Remote Method Invocation – đọc thêm ở http://java.sun.com/products/jdk/rmi/) và J2EE chắc không lạ với khái niệm “stub” và “skeleton”.

Tổng quát mà nói, “stub” là một class nội bộ (local class) có cùng interface với một class tầm xa (remote class). Với RMI, class tầm xa là class được gọi để thực hiện một công tác nào đó. Để thực hiện một công tác này, bạn chỉ cần gọi “stub” nội bộ mà không cần phải quan tâm đến chuyện công tác này được thực hiện bởi một class nào đó từ xa.

Trong khi đó, “skeleton” là một class tầm xa dùng để tiếp nhận thông điệp và lo liệu cú gọi đến một class nào đó trên một máy tầm xa và class này chính là class thực hiện công tác. Chỉ cần ghi nhận tổng quát: stub dành cho local và skeleton dành cho tầm xa trong cơ chế RMI.

-6-    IDE, viết tắt từ Integrated Development Environment (không phải là Intergrated Drive Electronics dành để chỉ cho ổ cứng), tạm dịch là bộ tích hợp môi trường phát triển. IDE là một bộ công cụ dùng để phát triển chương trình. Ví dụ, Java Netbeans, Eclipse, VC++ là các IDE. Chỉ cần nhớ IDE là đủ 🙂

-7-    exit status, tạm dịch là “tình trạng thoát”. Exit status là thuật ngữ quen thuộc với những ai đã từng lập trình, nó dựa trên các mã số đã được quy định trước để xác định một chương trình sau khi thoát ra thuộc tình trạng nào.

-8-    console, một thuật thông dụng trong ngành điện toán. Trước đây “console” là một màn hình gắn liền với bàn đánh trong môi trường mainframe hoặc các hệ thống UNIX (không dùng giao diện đồ hình). Mỗi màn hình là một “console”. Cho đến ngày nay, các hệ điều hành hiện đại kèm theo giao diện đồ hình nhưng vẫn còn phương tiện để mở lên một “console” (như DOS prompt trên Windows hoặc term trên *nix nói chung). Nói theo phương diện kỹ thuật, console là một giao diện, hay một cơ chế đứng giữa chương trình làm việc và hệ điều hành.

-9-    “standard output”, “standard error” và “standard in”, đôi khi còn viết tắt là “stdin”, “stdout”, “stderr”. Các thuật ngữ này được dùng để chỉ cho cơ chế xử dụng các thiết bị xuất, nhập dữ liệu hoặc hiển thị lỗi trên console (ở trên). Với stdin, stdout và stderr trong môi trường Java, nên tham khảo tài liệu “The ins and outs of standard input/output” của Jeff Friesen ở http://www.javaworld.com/javaworld/jw-03-2001/jw-0302-java101.html

Nguồn

Tác giả: Robert C. Martin

Người dịch: Hoàng Ngọc Diêu | Biên tập: Phạm Anh Đới