[Training Java Spring Nội Bộ] Lab 1: Developing an Application from Plain Java Objects.

Bây giờ ta sẽ tìm hiểu bài LAB đầu tiên trong khóa học Spring Java, như thường lệ trước khi bắt đầu học cái gì hay làm cái gì tôi thường có thói quen phân tích xem mình cần phải làm gì, cần cái gì để đạt hiệu quả cao nhất, tương tự trong bài làm này tôi đi tìm hiểu xem mình cần làm gì, và được gì trong bài LAB này.

Đầu tiên để có thể hiểu được rõ ràng bài LAB yêu cầu, cũng như lợi ích đặt được sau bài LAB bạn bắt buộc phải đọc tài liệu "core-spring-4.2.a.RELEASE-labdocs.pdf", và trong bài LAB hãy đọc bắt đầu đọc từ mục "Chapter 1: spring-intro: Introduction to Core Spring" trang 15.

Ok để hiểu rõ về bài LAB bạn phải đọc tài liệu ở đây tôi chỉ tập trung vào một số điểm chính và giải bài tập thôi không dịch ra hết nổi  :)), phần đầu tiên chúng ta tìm hiểu là chúng ta sẽ được gì sau bài LAB.

Chúng ta sẽ học được:
  • Cơ bản các chức năng trong Spring Tool Suite.
  • Cốt lỗi các chức năng xử lý RewardNetwork và API.
  • Tương tác cơ bản giữa các thành phần chủ chốt trong ứng dụng Reward Dining.

Cơ bản các chức năng trong Spring Tool Suite.

Phần này được mô tả khá chi tiết công hình ảnh minh họa trong tài liệu về bài LAB, trong cái nhìn phân tích tổng quan lần đầu tiên tôi hầu như đã đoán ra toàn bộ nội dung này và đã mô tả trong bài viết [Training Java Spring Nội Bộ] Tìm hiểu Spring Tool Suite của Core-Spring-4.2.a và tìm hiểu tổng quát về các LAB.

Ha ha ha... công nhận mình giỏi quá ta (tự sướng chút), trong phần này chủ yếu mô tả về cách dùng Spring cơ bản, cấu trúc workspace, working set, project của dự án, nói sơ qua một số lỗi có thể gặp khi sử dụng Spring Tool chủ yếu nói về lỗi kết nối mạn internet không được khiến nó tải về các LIB ko được dẫn tới lỗi hoặc bạn xử lý code trong khi các LIB chưa tải về xong, sử dụng todo list, cái phần này tôi đã giới thiệu qua trong bài trước bạn hãy xem bài trước nhé.

Chỉ có một phần về todo list tôi còn thiếu sót nên sẽ miêu tả tại đây, trong bài trước tôi có nói qua cách sử dụng tuy có hơi bất tiện là khi bạn nhấn sang class khác bạn chỉ thấy được todo list trong class đó thôi, trong phần mô tả tài liệu này thì có hướn dẫn cách để xem toàn bộ todo list mà không cần quan tâm bạn đang ở class nào, chọn mũi tên cấu hình sổ xuống ở góc phải màn hình Tasks và chọn Configure Contents..


Trong cửa phổ Configure Contents bạn chọn option "On any element in same project", tự là xem Todos của toàn bộ project ở bất kỳ thành phần nào trong project và nhấn "OK".

Nói thêm một chút ở đây bạn sẽ có thể câu hình được rất nhiền Contens khác để phục vụ cho dự án, đặc biệt rất hữu dụng trong việc làm việc nhóm, bạn có thể ghi các task cho thành viên trong nhóm xử lý, thiết Contents ghi chú các lưu ý cần thiết,... hoặc các thành viên trong nhóm có thê note lại nhưng điều cần khi xử lý cái gì đó, mà thông qua Task List bạn có thể dễ dàng nhìn thấy chúng.


Ok vậy là xong phần 1 chúng ta sẽ đi tìm hiểu lợi ích tiếp theo trong phần thần thứ 2.

Cốt lỗi các chức năng xử lý RewardNetwork và API và Tương tác cơ bản giữa các thành phần chủ chốt trong ứng dụng Reward Dining.

Tôi xin gọm chung hai phần trên lên để dễ trình này vì chúng liên quan tới nhau nhiều mà phần cột lỗi (core) thì tôi không trình bày lý do như bên dưới :))...

Trong tài liệu sẽ mô tả cho chúng ta về lớp "RewardNetwork" trong dự án, tuy  nhiên nó yêu cầu bạn phải hiểu được cốt lỗi của dự án trước khi tìm hiểu liếp "RewardNetwork" này, dài lắm, thôi các bạn tự tìm hiểu đi, mình chỉ tâp trung cốt lỗi của "RewardNetwork".

Trong miêu tả nó nói RewardNetwork sẽ chịu trách nhiệm thực hiện các chuyển giao rewardAccountFor(Dining), tôi xin trình bài lại cho dễ hiểu hơn là lớp RewardNetwork sẽ chịu tránh nhiệm thực thi việc chuyển khoản tiền thường ăn uống tới các tài khoảng thông qua phương thức rewardAccountFor(Dining). Trong bài LAB này bạn sẽ thực hiện các kế thừa interface từ lớp này, hãy xem biểu đồ mô tả kế thừa từ lớp này. (lưu ý hãy nhớ các biểu đồ vì nó là cần thiết để hiểu được bài LAB).


Kế tiếp nó chỉ cho ta biết được "RewardNetwork" nằm ở đâu trong dự án, bạn xem hình bên dưới để biết nó nằm ở đâu.


Biểu đồ kế tiếp nó mô tả lại việc "RewardNetworkImpl" kế thừa và về tần luận lý hay tần thị, hoặc các phương thức chứng năng của nó. (bên tiếng anh gọi là logi đó :)), còn Impl là "Implement" đó)


Thông qua biểu đổ ta có thể thấy được các logic của của "RewardNetworkImpl" tuy nhiên ta không thể hiển được chúng dùng để làm gì nếu không có mô tả :)):

Đầu tiên là AccountRepository được dùng để load Account Object (tải các đối đượng tài khoàng về) để xử lý hoặc trong bài này thì để thực hiện các lợi ích được thưởng từ việc ăn uống (đi ăn mà còn có tiền :)) sướng vãi). Đễ dễ hiểu bạn xem lại biểu đồ tuần tự đã được nhắc tới trong bài training từ trang 1 → 40.


Kế tiếp RestaurantRepository dùng để load Restaurant objects (tạo ra các đối tượng nhà hàng) để tính toán lợi ích để thưởng cho Account ăn uống tại nhà hàng, cái này đúng chuẩn hướng đối tượng luôn. Để dễ hiểu bạn có thể tưởng tượng việc dùng thẻ thành viên tại siêu thị mỗi lần mua hàng tại hệ thống của siêu thị thì ta sẽ được một điểm thưởng nhất định, tuy nhiên ở mỗi siệu thị khác nhau trong hệ thống thì có thể có cơ cấu điểm thưởng khác nhau, tại seo làm như vậy ư? bạn nào biết hoặc từng làm marketing thì sẽ hiểu :)).

Ok chức năng cuối cùng RewardRepository đây không phải là một đối tượng nó đơn thuần chuẩn là chức năng có nhiệm vụ xác nhận lại các giao dịch (transactions) để phục vụ cho mục đích báo cáo (report) hoặc có thể xem nó hoạt động như một chức năng ghi log.

Thông qua 3 mô tả trên bạn có thể thấy được cách lập trình hướng hướng đối tượng trong dự án Spring này, cách mà đối tượng được tạo ra, và cách mà đối tượng được sử dụng, tuy có chút khác biệt so với các cách tạo và xử đối tượng (object) phổ biến mà tôi từng biết, dù sao Spring thì quá mới mẻ với tôi :)).

Hướng dẫn giả bài LAB 001:

Bây giờ tôi sẽ hướng dẫn cách giải bài LAB 001 theo hướng dẫn của tài liệu :)) đầu tiên hãy xem kỹ biểu đồ dưới đây các task bạn làm sẽ nằm ở trong đây, theo cảnh báo trong tài liệu biểu đồ này còn các các giao thức trả về tuy nhiên nó không được miêu tả trong đây.


Ok bây giờ ta lấy ra danh sách các tasks todo list cần phải thực hiện, để xem no yêu cầu cái gì?
  • TODO-01: Reward an account per the sequence diagram.
  • TODO-02: Return the corresponding reward confirmation.
  • TODO-03: Remove the @Ignore annotation below. Run this JUnit test, It should pass.

Đầu tiên ta đi qua TODO-01 và TODO-02 trước bởi vì chúng đi cùng nhau và nằm trên tập tin RewardNetworkImpl.java.

    public RewardConfirmation rewardAccountFor(Dining dining) {
        // TODO-01: Reward an account per the sequence diagram
        // TODO-02: Return the corresponding reward confirmation
        return null;
    }

và theo biểu đồ tuần tự thì ta sẽ thực hiện các task 1 và task 2 như sau:
    public RewardConfirmation rewardAccountFor(Dining dining) {
        // TODO-01: Reward an account per the sequence diagram.
        Account account = accountRepository.findByCreditCard(dining.getCreditCardNumber());
        Restaurant restaurant = restaurantRepository.findByMerchantNumber(dining.getMerchantNumber());
        MonetaryAmount amount = restaurant.calculateBenefitFor(account, dining);
        AccountContribution contribution = account.makeContribution(amount);
        accountRepository.updateBeneficiaries(account);
        // TODO-02: Return the corresponding reward confirmation.
        return rewardRepository.confirmReward(contribution, dining);
        //return null;
    }

Nếu bạn là tay ngang giống tôi thì hay copy lời giải trong phần Solution sang tuy nhiên cần phải từ lời giải quay ngược trở lại đẻ có thể hiêu được cách mà nó thực hiện, đầu tiên khi tôi copy vào sẽ các lỗi Compiler Error như sau:


Đây là một sắp đặt trước giúp chúng ta hiểu được các lớp chúng ta đang sử dụng nó ở đâu, trông như thế nào, và giúp ta năm thêm cách sử dụng cơ bản về Spring Tool, ok để giải quyết mấy cái dòng đỏ thì dễ rùi chi cần import các lớp vào thôi nên cho qua.

Như đã trình bày trong phần trên ta đã biết Account và Restaurant là hai đối tượng (object) và thông thường khi ta tạo ra một object ta thường làm theo kiểu trực tiếp như thế này:
Point originOne = new Point(23, 94);
Rectangle rectOne = new Rectangle(originOne, 100, 200);
Rectangle rectTwo = new Rectangle(50, 100);

Nhưng với bài lab này 2 object được tạo ra từ một lớp khác, đây có lẽ sẽ hơi khó khi phải thay đổi tư duy lập trình như vậy.
    private AccountRepository accountRepository;
    private RestaurantRepository restaurantRepository;

Tôi có khá nhiều thắc mắc trong phần này nên có đào sâu một chút thì rút ra được được một điều rằng cách mà lập trình là sử dụng interface để thao tác trên đối tượng, một điều mà tôi không nghĩ tới trước đây, thông thường tôi chỉ dùng lớp interface để giải quyết về vấn đề đa kế thừa và giảm nhẹ mã code, cũng như hiệu suất xuất của ứng nhưng trong một số vài viết về tính kế thừa trước đây của tôi.

public class Entity {}

public class Restaurant extends Entity {}
public class Account extends Entity {}

public interface AccountRepository {
    public Account findByCreditCard(String creditCardNumber);
    public void updateBeneficiaries(Account account);
}
public interface RestaurantRepository {
    public Restaurant findByMerchantNumber(String merchantNumber);
}

public class RewardNetworkImpl implements RewardNetwork {
    Account account = accountRepository.findByCreditCard(dining.getCreditCardNumber());
    Restaurant restaurant = restaurantRepository.findByMerchantNumber(dining.getMerchantNumber());   
}

Ok về phát hiện trên tôi đã tóm gom lại các mã code trong bài để giải thích, tạm thời đây chỉ mới là cách nhìn nhận vấn đề này của tôi nên chưa đủ chứng minh là đúng và tôi hơi chưa rõ ràng lắm về lợi ích cũng như cách nó thực hiện nên bạn nào có thể thông qua code để hiểu thì hiểu, không hiểu thì cho qua vì tôi hơi lang mang rùi :)) có thể trong bài giảng tiếp theo tôi sẽ có được câu trả lời và mô tả cho các bạn sau.

Tiếp theo chúng ta sẽ thảo luận về :
MonetaryAmount amount = restaurant.calculateBenefitFor(account, dining);

Thông qua đối tượng "restaurant" một tính toán lợi ích (hay phần tưởng) sẽ được thực hiện dự trên đối tượng "account" và đối tượng "dining", từ đây số điểm hay tiền thưởng gì đó sẽ được tạo ra. Hiểu đơn giản trong thực thế là lúc ta tính tiền sau khi ăn xong vậy đó, cô nhân nhiên tính tiền xin đẹp ngồi bấm máy tính cho ra số tiền đó.

Kế tiếp đó số tiền này sẽ được chuyển tới account bằng:
 AccountContribution contribution = account.makeContribution(amount);

Đồng thời một bản tóm tắt về tiền được thưởng sẽ được lưu lại trong contribution để thực hiện các report báo cáo hay confirm gì đó. Hiểu đơn giản thì đây là việc nhập tiền vào tài khoản đồng thời in ra hóa đơn.

Sau khi tài khoản đã có đây đủ thông tin tiền thưởng thì accountRepository lại tiếp tục xử lý tài khoảng bằng cách câp nhập tiền thưởng vào account. Hơi lằng nhằn chỗ này tuy nhiên suy diễn chút sẽ ra tôi cũng chả biết giải thích sao cho dễ hiểu.
accountRepository.updateBeneficiaries(account);

Ok tới đây là ta đã hoàn thành xong yêu cầu thứ nhất, bạn hãy so sánh lại với biểu đổ tuần tự trên để xem ta làm có đúng không, và cũng để hiểu rõ hơn các class này tương tác với nhau thế nào sau khi đã tìm hiểu code.

Bây giờ ta sẽ làm tiế task todo thứ là "// TODO-02: Return the corresponding reward confirmation." ý nó là trả về "RewardConfirmation", có thể hiểu là giao dịch bao gồm thông tin hóa đơn, khách hàng sẽ được lưu giữ lại để làm chứng chiếc gì đó, sau này ta có thể lấy lại thông tin giao dịch này để kiểm kê, xác nhận, report.... gì đó.
return rewardRepository.confirmReward(contribution, dining);

Vạy là ta đã làm xong TODO 1 và TOD 2 y hệt như trong biểu đồ tuần tự mô tả, qua đó ta đã nắm được cơ bản cách sử dụng Spring Tool, kiến trúc và một số thành phần về dự án trong bài LAB y như tài liệu đã đề cập.

Phần tiếp theo cũng liên quan tới cơ bản sử dụng Spring Tool là sử dụng JUnit để kiển tra ứng dụng, cũng là yêu cầu cuối cùng của bài LAB này "// TODO-03: Remove the @Ignore annotation below. Run this JUnit test, It should pass." khi di chuyển tới phần code ở nhiệm vụ này bạn sẽ thấy được code như hình bên dưới.


Ok cứ làm như yêu cầu bỏ @Ignore đi và chạy JUnit test thôi, với bạn nào đã biết JUnit thì không có vấn đề gì, với tôi thì chưa biết gì về JUnit test thì liên ngáo đá liền, đặt câu hỏi liền làm vậy để làm gì? Cái này cũng là một cái hay cũng bài giảng nó giúp người không biết thắc mặc và phải đi tìm hiểu về annotations @Test và @Ignore trong JUnit Test và thông qua đó cũng có thể nắm cơ bản về nó.
  • @Ignore: được sử dụng khi bạn muốn bỏ qua một method hoặc class trong việc chạy JUNIT.
  • @Test: đây là một annotations dùng để thông báo với JUnit phương thức (method) đang được chạy thử nghiệp để test, nó cung cấp cho ta 2 option, test để quăng ra ngoại lệ (expected) nếu phương thức không quăn ra ngoại lệ như mong muốn hoặc cho ra một ngoại lệ khác thì việc kiểm thử là thất bại, option thứ hai là timeout nếu việc thực thi của method vượt quá mong đợi thì việc kiểm thử này cũng là thất bại.

À quên mất trong TODO 3 chúng ta thực hiện việc JUnit tại thư test theo đúng kiến trúc của Maven cung cấp việc Test sẽ được thực thi tại đây "/spring-intro/src/test/java/rewards/internal" nếu bạn chịu khó tìm hiểu một chút sẽ có thêm kiến thức về việc thiết lập môi trường test trong Maven và JUnit, theo tôi thì rất hay đấy.

Tuy nhiên bài này chúng ta không tìm hiểu về Maven JUnite nên tôi không nói sâu vào nữa, tiếp đây tôi sẽ hướng dẫn cách chạy JUnit Test để thực hiện TODO final, hãy nhìn hình hướng dẫn bên dưới nếu hình nhỏ thì bạn click vào để xem hình to nhé chuẩn 1080 HD đó :)).


Đầu tiên tôi di chuyển tới phần code của TODO 3 bằng cách click vào dòng TODO 3 trong Tasks List, nó chuyển tới tập tin "RewardNetworkImplTests.java" trong thư mục Test "/spring-intro/src/test/java/rewards/internal", tại đây bỏ dòng Ignore bằng cách chuyển nó thành note, tiếp theo tôi click chuột phải vào thư mục test và chọn RUN AS → JUnit Test và nhận được kết quả màu xanh thành công như hình bên dưới.


Táy náy nghịch một chút tôi dùng annotation @Ignore chạy thử xem nó như thế nào và tôi nhận được thông báo là "No tests found with test runner 'JUnit 4' "


Tôi mới sực nhớ ra một điều quan trong khi chạy bất kỳ một ứng dụng Java nào đó là phương thước VOID MAIN, nó đâu rùi, tôi đã đi tìm hết trong project của lab này, nhưng tìm hoài không thấy TT_TT, que a you? mi ở đâu? Thê là tôi lại thắc mắc tại seo nó chạy được.

Lại tiếp tục search and read về JUnit Test, khổ vãi học cái này phải học đủ thứ mệt quá, khi dùng phương thức test thì có thể bỏ qua việc tạo phương thức VOID MAIN tuy nhiên có thể bỏ qua là do JUnit Framework hỗ trợ tạo ngầm bên dưới rùi chứ không đố mà chạy được, và phương thức "public void testRewardForDining() {}" kết hợp với @Test thì sẽ tương đương với VOID MAIN (tương đương thôi nhé), vì thế khi tôi bỏ qua nó thì nó báo lỗi.

Tôi lại tiếp tục thực nghiệm để giải đáp thắc mắc tôi chơi tới hai các @Test thì sẽ như thế nào, kết quả tôi nhận được là nó chạy cả 2, điều này rất có lợi cho việc xây dựng môi trường Test, rất hay và tôi rất hài lòng về phần Training này, nó cho tôi rất nhiều kiến thức mới, mặc dù phải tự mình đào sâu vào vấn đề mới có thể hiểu dược.


Phù mệt vật vã mất gần cả tuần tuần, 5 ngày 2 tiếng, 1 ngày thứ 7 tám tiếng, tổng cộng 18 tiếng mới có thể nắm được hết phần 1 và LAB của bài giảng, thế mờ ông thầy đi một phát 8 tiếng tới trang hai trăm mấy, mấy cái bài LAB, thảo nào tôi muốn không ngáo đá cũng không được. Khổ thân tôi quá các bạn cho mấy cái comment với like để cổ vũ tinh thần cho em nó nhé :))...



Writer: +Bui Ngoc Son










1 comment:

  1. anh gì ơi, tài liệu mật có share được không anh ^^

    ReplyDelete