I Don’t Write Unit Tests Because…. : The Excuses


As someone who’s seen the benefits of the approach, I’m a huge believer in test driven development. It adds a level of quality and maturity to the field of software development, yet it’s still not a widespread practice across development projects. When it comes to a choice between the features, time and quality, it’s always the quality that suffers. We don’t want to add extra time for testing and we don’t want to compromise on the feature set of the delivery. If you haven’t set out to do test driven development at the start of the phase, then it’s difficult to fit in.

We’ve all heard excuses for not taking the test driven approach, but nowhere compiles them better than “Pragmatic Unit Testing in Java With JUnit“, from the Pragmatic Bookshelf.  I read the book a few years ago, and afterward I thought there was no way that any responsible developer could read the book without truly believing that unit tests were one of the most important aspects of the development activity.

The most worrying excuse I’ve heard is that it’s too difficult to test my code. This can be for one of two reasons. One is that your code is mainly UI related, and automating the UI tests is too difficult. I’ll concede that UI automation is a tricky area (but not impossible, as we’ll see in a later article), but every effort should be made to automate it if possible: think about regression tests. If you have a fully automated test suite, including the UI behaviour, you can make a change to your code, and have full confidence that you haven’t broken anything if you have tests to re-run.

The second reason that your code is too difficult to test is that you’ve messed up your design. Maybe your logic and UI code are too tightly coupled, and without that automated UI layer existing, the dependency between the logic and the UI will cause a problem. This is where test driven development helps to ensure a clean design, following best practices. Using JUnit is simple, so if I can just point my test at a clean logic layer, I can test all logic that the UI will ever touch.  What’s that? You’re missing your data model? Well then just use mock objects – there are many frameworks for that!

For those who haven’t read the book yet, I’ll give a quick summary of the excuses for not testing as outlined in the introduction chapter:

I don’t have time to unit test.
Really? But you have to time to fix your mistakes later?  The simple fact is that nobody, not even you, can write bug free code.  Unit tests greatly speed up the time it takes to identify a bug because they narrow the suspect code down to a very specific unit.  Other types of testing, such as Quality Assurance or User Acceptance Testing, identify problems at a much higher level, forcing the developer to spend extra time plodding through the various units looking for the root cause. Unit tests can also serve as verification that the bug is corrected without having to go through the hassle of creating a new application build and deploying it for further testing.  Simply put, unit tests speed up overall development.  It might take slightly longer to create each new feature, but the development time for the entire application, from inception to delivery, is considerable shorter.
The client pays me to develop code, not write unit test.
News Flash – Unit tests are code.  They are as integral to the application as any other piece of code you are writing, and should be included in the original estimate and statement of work.  It might also help to mention to the client that unit tests lower both development cost (see previous excuse) as well as maintenance cost.  If you are not writing unit tests, then you are doing your client an injustice by forcing them to incur extra expense.
I am supporting a legacy application without unit tests.
That still doesn’t preclude you from writing your own.  Granted, you are not going to be able to go in and write tests to bring the entire code base up to an acceptable level of coverage.  You most likely don’t have the time or resources to do that.  But as support issues are raised, write the unit tests for any code that you modify.  When I am working on a support task, one of the very first things I do is write a unit test to recreate the bug.  When the unit test starts passing, I know that I have fixed the problem.  Now, not only have I resolved a bug, but I have added some unit test coverage to the code base.  Over time, this coverage will become more and more robust, and actually reduce future maintenance costs by preventing the introduction of regression bugs.
QA and User Acceptance Testing is far more effective in finding bugs.
No arguments there.  But Unit Testing is far more effective at preventing bugs.  Just because my smoke alarm is better at detecting potential fires doesn’t mean that it is safe to leave the stove on all the time.  QA and UAT are smoke alarms – they alert you to potential existing trouble.  Unit testing is turning off the stove when you are done – it helps you prevent trouble.  Unit testing, QA, and UAT are all important parts of the testing process, and they each play very different roles.  Trying to replace one with another doesn’t work.  I wouldn’t release a project that was well unit tested without QA, and I wouldn’t release a project that was thoroughly QA’ed without unit testing.
I don’t know how to unit test, or I don’t know how to write good unit tests.
Well, this is probably the most valid excuse that is out there.  The sad truth is that a great many number of developers and engineers do not know how to unit test.  I didn’t when I started.  And nothing discourages a developer more than struggling to write bad unit tests.  Luckily there are resources out there.  There are so many books, webinars, conference presentations, blogs, etc on writing good unit tests that the inability to write them simply isn’t going to cut it as an excuse any more.  When someone offers me this excuse, I don’t look at it as a roadblock, but rather as a teachable moment.  It usually only takes a time or two of seeing how well written unit tests can help one develop code to turn them from the dark side…

Are there other excuses out there?  Absolutely.  But they are just that – excuses.  I have yet to encounter a valid reason to skip unit testing.  If you think you have one, post it here.  I look forward to the challenge of changing your mind! :)


Lập trình theo kiểu Aspect Oriented Programming (AOP) sử dụng Spring Framework

Aspect Oriented Programming

Trong khoảng 5 năm trở lại đây, một khuynh huớng lập trình mới xuất hiện. Nó được gọi là AOP để phân biệt với kiểu lập trình OOP đã có sẵn. Nguời viết muốn cung cấp cho bạn đọc một kiến thức cơ bản về kiểu lập trình mới mẻ này, và sử dụng springframework, một open-source phổ biến, để minh hoạ. Nếu bạn muốn tìm hiểu chi tiết về cách sử dụng springframework, thì bài viết này không nhằm mục đích đó, mà chỉ trình bày khái quát về những thuật ngữ và nguyên tắc trong việc sử dụng 1 chức năng phổ biết của spring: declarative transaction .

Aspect Oriented Programming (AOP) và Object Oriented Programming (OOP)

Một điểm quan trọng nữa cần đuợc nêu ra, AOP đuợc xem là cái bổ sung cho OOP, chỗ mà OOP còn thiếu sót trong việc tạo những ứng dụng thuộc loại phức tạp. AOP khônng phải là cái thay thế OOP. Nguời lập trình bắt buộc phải quen thuộc với OOP để bắt đầu với AOP. Cũng vì lí do này mà AOP thuờng đuợc xem là dành cho các bạn đã có kinh nghiệm, chứ không dành cho các bạn mới bắt đầu làm quen với Java. Bạn có thể làm quen với OOP qua lí thuyết và sách vở từ truờng học. Và nếu bạn thấy vẫn còn lạc lối trong việc tìm kiếm những danh từ, tính từ, hay trả lời những câu hỏi ai, cái gì, làm gì… đại loại như vậy, trong việc tìm kiếm class, thì bạn có thể đọc lại những bài viết về OOP mà nguời viết đã trình bày truớc đây xem có giúp ích hơn không. Dù học OOP theo kiểu nào thì kết quả cuối cùng của OOP là chia ứng dụng thành nhiều phần nhỏ với những chức năng riêng biệt, theo kiểu các hộp đen (black box). Các hộp đen này làm cho việc tái sử dụng và bao quản chúng đuợc dễ dàng hơn….và còn thêm nhiều ưu điểm khác nữa không kể ra ở đây.

Hạn chế của Object Oriented Programming

Lấy ví dụ về transaction trong việc truy cập database. Trong Java, truy cập database đòi hỏi nhiều buớc: tạo ra Connection, bắt đầu transation, commit, clean up connection… Để đơn giản hoá, ta hãy tạo ra 1 class hay black box chuyên làm việc này.

public class DBTransaction {
     public DBTransaction () {
          //mã nguồn tạo ra Connection và bắt đầu 1 transaction

     public Connection getConnection () {
          //mã nguồn return Connection đã tạo ra

     public void commit () {
          //mã nguồn commit transaction và clean up resources

Giả sử trong 1 ứng dụng, có 1 class (hay blackbox) XuatNhapHang làm chức năng xuất nhập hàng và nó chứa 1 method làm chức năng nhập hang.

public void nhapHang ( int monHang, int soLuong )
     //sử dụng blackbox để bắt đầu 1 transaction
     DBTransation tx = new DBTransactiơn ();

     // ...mã nguồn truy cập database để nhập hàng...

     tx.commit ();

Bạn dễ dàng hình dung đuợc mục đích sử dụng của blackbox này.
Mỗi khi cần truy cập database, nguời sử dụng chỉ việc gọi các public methods của nó mà không cần biết tới bên trong nó hoạt động ra sao. Việc thay đổi bên trong của blackbox cũng không làm ảnh huởng tới nguời sử dụng nó. Đó là cái đẹp của việc tạo ra blackbox. Mọi nguời hình như đều vui vẻ và độc lập với công việc của mình. Thực tế không hoàn toàn như vậy. Giả sử ứng dụng sau này đòi hỏi phải theo dõi tất cả mọi hoạt động liên quan đến việc truy cập database. Mỗi khi database đuợc truy cập, tên nguời sử dụng và thời gian sẽ đuợc lưu trữ lại. Ta có thể tạo ra 1 blackbox đơn giản chuyên làm việc này.

public class DBTruyCapTheoDoi {
     public DBTruyCapTheoDoi (Connection con, String tenNguoi) {
          //mã nguồn lưu lại trong database nguời sử dụng và thời gian

Method nhapHang hay những nơi trong ứng dụng đã truy cập database đều phải sửa đổi như sau

public void nhapHang ( int monHang, int soLuong )
     //sử dụng blackbox để bắt đầu 1 transaction
     DBTransation tx = new DBTransactiơn ();
     //theo doi truy cap
     DBTruyCapTheoDoi (tx.getConnection (), tenNguoi);

     // ...mã nguồn truy cập database để nhập hàng...

     tx.commit ();

Sửa đổi không nhiều nhưng nó rộng khắp trong toàn ứng dụng. Đây chính là điểm làm cho nhiều nguời không hài lòng. Những nguời lập trình kì cựu đều đồng ý với nhau rằng, trong thực tế, đòi hỏi của ứng dụng luôn thay đổi theo thời gian. Cứ mỗi 1 yêu cầu mới của ứng dụng thì một (hay nhiều) blackbox đuợc tạo thành, và mã nguồn sẽ bị thay đổi rộng khắp trong ứnng dụng để sử dụng blackbox mới này. Thay đổi mã nguồn rộng khắp ứng dụng là điều tối kị vì nó đòi hỏi phải testing lại toàn bộ . Những bug xuất hiện lúc này thuờng rất khó tìm vì nguời lập trình thuờng cho rằng “mình sửa có 1 chút thì không sao…” .

Câu hỏi đặt ra là làm sao tạo đuợc một kiểu lập trình uyển chuyển với sự phức tạp của ứng dụng . Mô hình này phải cho phép tạo dựng nhanh chóng ứng dụng khi nó ở trong giai đọan đầu đơn giản, và thay đổi nhanh chóng để thích ứng kịp thời với đòi hỏi mới . OOP cho phép tạo ra những blackbox và điều này vẫn đuợc xem là không thể thiếu trong việc lập trình . Bản thân những blackbox không phải là vấn đề, mà chính việc sử dụng chúng mới là vấn đề . Việc gọi trực tiếp những public method của 1 blackbox khi phải sử dụnng nó trong mã nguồn, tạm gọi là nối cứng (hard wired) blackbox vào mã nguồn. Có cách nào để sử dụng 1 blackbox mà khônng cần gọi trực tiếp nó trong mã nguồn hay không? Cần có 1 cách nào đó để gọi gián tiếp những public method, hay tạm gọi là nối mềm (soft wired) khi sử dụng những blackbox. Đây là chỗ OOP bỏ sót, và AOP ra đời để đáp ứng nhu cầu này .

Đến đây bạn có thể thấy rằng, OOP là buớc đầu tiên cần phải có để tạo thành các blackbox. AOP là buớc kế tiếp để nối mềm những blackbox tạo thành 1 ứng dụng hoàn chỉnh . Việc nối mềm đòi hỏi nguời thiết kế phải có kinh nghiệm trong việc chia ứng dụng thành nhiều lớp (layer) để ứng dụng đuợc tạo ra và chạy 1 cách hữu hiệu . Điều này sẽ đuợc nói kĩ hơn sau đây. Một rắc rối nữa của việc nối mềm là nó thuờng đòi hỏi tạo nhiều cấu hình (configuration) phụ trợ .

Làm thế nào để nối mềm 1 ứng dụng?

Đây cũng chính là câu hỏi mà AOP cần phải trả lời . Java cho phép là đuợc việc này .

Nối mềm là cho phép sử dụng 1 class (hay blackbox) mà không cần gọi trực tiếp public methods của nó trong mã nguồn, và bạn có thể ngạc nhiên nếu biết rằng điều này thực sự đã đuợc làm từ lâu . Nó đuợc làm bởi các container chẳng hạn như của EJB, portlet, servlet. Lấy EJB container làm ví dụ, vì nó rất gần với khái niệm AOP . Muốn sử dụng 1 EJB, bạn phải gọi create… chứ không bao giờ sửng dụng new . EJB trong thực tế chạy bên trong 1 container. Container trực tiếp tạo ra instance của EJB và chuyển cho nguời sử dụng khi method create… được gọi . Mỗi lần nguời sử dụng gọi method của EJB, container sẽ đón đầu (intercept) cú gọi này, rồi mới chuyển giao cho instance của EJB . Truớc khi chuyển giao cho EJB, thuờng container có thể sẽ làm nhiều việc khác nữa …. Container có thể bắt đầu 1 transaction, hay kiểm tra xem nguời gọi có đuợc phép gọi hay không, tùy theo cách cấu hình của EJB đó bên trong file ejb-jar.xml . Nếu xem EJB là 1 blackbox thì việc nối giữa EJB và nguời sử dụng nó mặc dù là gián tiếp nhưng chưa đuợc xem là nối mềm . Bản thân EJB container có thể chứa sẵn bên trong nó 1 blackbox làm công việc bắt đầu 1 transaction, hay 1 blackbox khác làm công việc kiểm tra mức độ cho phép nguời gọi . Việc nối kết giữa EJB và những blackbox bên trong của container mới chính xác là mềm … Bản thân EJB hay nguời viết nó hoàn toàn không biết đến có tồn tại 1 blackbox có sẵn bên trong container làm công việc transaction . Nguời viết EJB chỉ việc thông tin với container qua file cấu hình ejb-jar.xml rằng phải bắt đầu 1 transaction hay làm thêm những chuyện khác mỗi khi method của nó đuợc gọi . Cũng dựa trên ý tuởng này, spring framework chính là 1 container thuộc loại nhẹ và nó có thể chứa đựng những Java object thông thuờng chứ không phức tạp như EJB .

Trở lại ví dụ xuất nhập hàng ở trên, nếu class XuatNhapHang chạy bên trong spring framework thì method nhapHang ở trên có thể viết lại như sau

public void nhapHang ( int monHang, int soLuong )
     // ...mã nguồn truy cập database để nhập hàng...

Không hề có 1 đọan mã nguồn nào bên trong method nhapHang nói đến việc tạo ra transaction hay theo doi truy cap . Bản thân các blackbox transaction và theo dõi try cập cũng đuợc chạy trong spring. Nguời viết class XuatNhapHang chỉ việc truyền đạt cho spring, qua 1 file cấu hình, rằng mỗi khi method nhapHang đuợc gọi , hãy gọi blackbox transaction và theo dõi truy cập truớc khi chuyển nó đến nhapHang . Bằng cách nối mềm này, việc bao gồm hay loại bỏ những blackbox đuợc thực hiện qua việc thay đổi file cấu hình, chứ không cần phải thay đổi mã nguồn của class XuatNhapHang . Đây chính là lập luận mạnh nhứt trong việc cho ra đời AOP . Những nguời ủng hộ AOP trong ví dụ này lí luận rằng class XuatNhap hay method nhapHang chỉ nên lo lắng việc xuất nhập hàng . Việc bắt đầu 1 transaction hay theo dõi truy cập dữ liệu , đành rằng phải có do yêu cầu của ứng dụng, cũng không nên chen lấn 1 cách thô bạo vào trong mã nguồn của class XuatNhap, hay bất kì vào trong những blackbox nào khác khi chúng cũng cần truy cập dữ liệu . Có như vậy thì 1 blackbox mới giữ đuợc tính độc lập của nó với những thay đổi của yêu cầu của ứng dụng, dẫn đến việc tái sử dụng blackbox đuợc triệt để hơn .

Những khía cạnh như transaction hay theo dõi truy cập, nếu cần phải ‘chen lấn ‘ thì mã nguồn không phải là chỗ tốt để làm . Có những chỗ tốt hơn chẳng hạn như dùng file cấu hình, và spring framework làm đúng như vậy . Công việc của spring framework là đón đầu các cú gọi và thực hiện các chức năng thể hiện qua file cấu hình . Đây cũng chính là nguyên tắc cơ bản của AOP: thay các cú gọi trực tiếp, bằn các cú gọi qua file cấu hình ..

Khó khăn khi áp dụng Aspect Oriented Programming

Đọc đến đây, có thể bạn không mấy hào hứng với AOP . Thực tế các file cấu hình cho spring hay các AOP framework khác như AspectJ không đơn giản chút nào . Gọi trực tiếp method chỉ mất 1 dòng và cũng dễ theo dỏi logic của ứng dụng . Thay đổi file cấu hình liệu có an toàn hơn thay đổi mã nguồn hay không ? Những nguời ủng hộ AOP thì cho rằng nó rất nên làm . Những nguời còn hoài nghi thì luỡng lự . Các AOP framework khác nhau đều có cách tạo file cấu hình khác nhau. Không giống như EJB có thể chạy trong mọi EJB container, ứng dụng viết cho AOP framework này không chạy đuợc trong AOP framework khác . Những cố gắng để thống nhứt các AOP framework cho đến bây giờ vẫn chưa kết thúc . Việc container đón đầu các cú gọi có thể ảnh huởng đến tốc độ chạy của ứng dụng . Thêm nữa, không phải mọi class trong ứng dụng đều cần đuợc quản lí bởi AOP framework cũng như không phải mọi class đều trở thành EJB. Nếu ứng dụng thiết kết kém cỏi có thể dẫn đến số luợng class mà AOP container phải quản lí cùng với các file cấu hình tăng lên nhanh chóng . Có lẽ cũng chính vì những lí do này mà AOP vẫn chưa cất cánh nhanh chóng như OOP . Điểm khó khăn cuối cùng nữa của AOP là lí thuyết hoá nó để truyền đạt . AOP đưa ra những khái niệm lạ hoắc khó nắm bắt, dễ làm nản lòng những nguời mới bắt đầu . Phần kế tiếp nguời viết sẽ trình bày những khái niệm cơ bản của AOP, và nguyên tắc Inversion of Control hay còn gọi là Dependency Injection của springframework trong việc triển khai AOP .

Những khái niệm trong Aspect Oriented Programming

Khái niệm đầu tiên thuờng gặp trong AOP là concern (1 mối lo âu) hay aspect ( 1 khía cạnh của vấn đề). Concern hay aspect trong AOP chỉ là 1, và nó tuơng đuơng với chức năng của 1 blackbox trong OOP. Lấy ví dụ trong ứng dụng cho 1 cửa hàng mua bán . Những yêu cầu của ứng dụng bao gồm : chi thu tài chính, xuất nhập hàng, kết toán cuối tháng, cuối năm, quản lí nhân viên … Và có thể thay đổi trong tuơng lai theo yêu cầu của thực tế . Việc chia nhỏ 1 yêu cầu cùng với OOP sẽ đưa đến các blackbox như xuất nhập hàng, transaction, hay theo dõi truy cập như ở trên . Chức năng của mỗi blackbox có thể đuợc xem là 1 khía cạnh của ứng dụng mà nguời thiết kế phải lo lắng . Tới đây bạn có thể thấy vì sao 2 chữ concern và aspect mang nghĩa không mấy ăn nhập với nhau lại đuợc dùng để chỉ chung 1 khái niệm . Có những khía cạnh, như transaction, cần phải ‘chen lấn ‘ vào các khía cạnh khác . Những khía cạnh đó đuợc gọi là crosscutting aspect, tạm gọi là những khía cạnh cắt ngang . Trong thực tế, điểm chen lấn của những crosscutting aspect không tùy tiện mà nó thuờng là các điểm đặc biệt . Ví dụ như khía cạnh trasaction chỉ chen vào khi bắt đầu method nhapHang để khởi tạo 1 transaction và lại chen vào 1 lần nữa khi method nhapHang return để commit transaction. Những điểm đặc biệt có thể kể ra là bắt đầu hay kết thúc 1 method, khi xảy ra exception. Spring chỉ cho phép chen vào các điểm đặc biệt, còn AspectJ thì cho phép hầu như vào bất cứ điểm nào trong mã nguồn . Việc chen lấn tuỳ tiện cần được cân nhắc kĩ lưỡng và thuờng đuợc khuyên nên tránh . Điểm chen lấn đuợc gọi là joinpoint (điểm nối ) . Tập họp các điểm nối đuợc gọi là pointcut (cắt điểm). Bản thân blackbox XuatNhapHang bị chen lấn nên nó đuợc gọi là target object. Bản thân blackbox transaction, triển khai transaction aspect, làm công việc chen lấn, đuợc gọi là advice. Vì có nhiều điểm chen lấn đặc biệt kể trên, nên có nhiều loại advice.
_ Around advice: là loại chen vào truớc khi cú gọi đuợc chuyển tới method và sau khi method thực hiện xong. Transaction advice chính là loại này
_ Before advice: chen vào truớc khi cú gọi đuợc chuyển tới method
_ Throws advice: chen vào khi bản thân method thows excpetion
_ After returning advice: chen vào sau khi method thực hiện và không có exception .

Ta có thể hình dung như sau: mỗi khi ứng dụng gặp điểm ‘chen lấn ‘, container sẽ đón đầu cú gọi và chạy mã nguồn của advice cho điểm ‘chen lấn ‘ đó rồi mới chuyển giao cho method.
Tới đây có lẽ khá đủ cho nguời mới làm quen với AOP. Để thực sự có thể lập trình theo kiểu AOP, bạn cần phải thông thạo với 1 AOP framework như spring hay aspectJ, đặc biệt là cách tạo file cấu hình cho mỗi framework.

Trở lại spring framework, nó đuợc đề cập ở đây vì 1 chức năng phổ biến : declarative transaction, giống như trong EJB, nhưng đơn giản và dễ sử dụng hơn nhiều. Để sử dụng chức năng này, chỉ cần khái niệm của AOP ở trên là đủ . Khi sử dụng spring, 1 khái niệm luôn gặp phải là Inversion of Control (IoC) hay còn gọi là Dependency Injection, nó sẽ đuợc nói rõ duới đây .

Inversion of Control (IoC) và Dependency Injection (DI)

IoC (tạm dịch là đảo nguợc kiểm soát) thuờng được thực hiện bởi các loại container như servlet, portlet, hay EJB.

Lấy ví dụ EJB container, nguời sử dụng không trực tiếp tạo ra instance của EJB, mà container tạo ra nó và chuyển giao nguời sử dụng khi cần tới . Khi nào instance đuợc tạo ra nằm ngoài sự kiểm soát của nguời sử dụng . Container có thể tạo instance ra truớc và chờ đến khi nguời sử dụng, hoặc tạo ra ngay vào lúc đuợc cần tới . Tên gọi IoC cũng nhằm chỉ lí do này: container giành sự kiểm soát từ nguời sử dụng (trong lập trình thông thuờng nguời sử dụng giành kiểm soát bằng cách gọi new để tạo ra instance). Khi instance của EJB đuợc tạo ra và trong truờng hợp session bean, container luôn gọi method setSessionContext(SessionContext sc) để cho EJB sử dụng SessionContext của nó .

Tuơng tự trong servlet container, khi instance của servlet đuợc tạo ra, container luôn gọi method init(ServletConfig sc) để servlet sử dụng . Trong cả 2 truờng hợp, container đuợc xem là nạp (injection) cho instance cái mà nó cần . Cái đuợc cần như SessionContext hay ServletConfig gọi là dependency .

Tên gọi Dependency Injection cũng từ đây mà ra. Có 1 điểm bất đồng giữa cách gọi tên Dependency Injection và định nghĩa về mối quan hệ giữa class trong UML . Dựa trên tài liệu “Mastering UML with Rational Rose” thì instance của EJB sử dụng SessionContext nên instance mới chính là dependency phụ thuộc vào SessionContext . Nếu bạn giải thích đuợc tại sao có sự bất đồng này thì làm ơn cho mọi nguời cùng biết . Dù sao thì chúng ta không nên mất quá nhiều thời giờ cho vấn đề định nghĩa và tên gọi ở đây .

Aspect Oriented Programming trong Spring Framework

Muốn sử dụng Spring, ít nhiều bạn phải làm quen với Spring container . Class tiêu biểu cho spring container là ApplicationContext . Nguời sử dụng phải trực tiếp tạo ra instance của spring container truớc khi có thể sử dụng những object mà nó chứa . Có nhiều cách tạo ra spring container. Cách thông thuờng nhứt là (những ví dụ theo sau đuợc dựa trên tài liệu spring-reference.pdf vversion 1.2.8)

ApplicationContext ac = new ClassPathXmlApplicationContext( new String[] {"applicationContext.xml", "applicationContext-part2.xml"});

Spring container tạo ra theo cách này sẽ đọc những file config duới dạng xml để load tất cả các Java ojbect mà nó cần quản lí .
Như ví dụ sau

<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

ExampleBean và ExampleBeanTwo có thể là những java object thông thuờng chứ không có gì đặc biệt . Muốn truy cập chúng qua container rất dễ dàng

ExampleBean eb = (ExampleBean)ac.getBean("exampleBean");
ExampleBeanTwo eb2 = (ExampleBeanTwo)ac.getBean("anotherExample");

Theo mặc định thì container sẽ tạo ra singleton instance cho mỗi bean, có nghĩa là chỉ 1 instance của 1 bean đuợc tái sử dụng cho những lần gọi sau . Ta có thể sử dụng Dependency Injection của container như sau

<bean id="exampleBean" class="examples.ExampleBean">
<property name="beanOne"><ref bean="anotherExampleBean"/></property>
<property name="beanTwo"><ref bean="yetAnotherBean"/></property>
<property name="integerProperty"><value>1</value></property>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
     private AnotherBean beanOne;
     private YetAnotherBean beanTwo;
     private int i;

     public void setBeanOne(AnotherBean beanOne) {
          this.beanOne = beanOne;
     public void setBeanTwo(YetAnotherBean beanTwo) {
          this.beanTwo = beanTwo;
     public void setIntegerProperty(int i) {
          this.i = i;

Bản thân ExampleBean phải chứa những setter method để container gọi ngay sau khi tạo ra chúng và truớc khi chuyển cho nguời sử dụng .

Nguyên tắc sử dụng spring container chỉ đơn giản như vậy thôi . Nó cho phép định nghĩa qua file cấu hình những logic phức tạp hơn mà bài viết không trình bày hết ra đây . Tới đây bạn có thể thắc mắc như vậy thì sức mạnh của spring nằm ở đâu ? Tiện lợi chỉ đơn giản như vậy thì có đáng đuợc sử dụng không ?

Cần nhắc lại 1 nguyên tắc làm việc của mọi dạng container là đón đầu những cú gọi . Spring làm việc này bằng cách dựa trên file cấu hình để tạo ra những object phụ trợ khác vào lúc runtime . Cái return từ method getBean đuợc xem là 1 proxy đuợc tạo ra vào lúc runtime của java object mà spring quản lí . Đằng sau proxy này là 1 tập họp các phụ trợ object thực hiện các chức năng theo yêu cầu của file cấu hình truớc khi chuyển cú gọi tới cho java object . Chẳng hạn như các phụ trợ object có thể chạy mã nguồn của advice, hoặc bắt đầu 1 transaction, một chức năng đã được làm sẵn trong Spring, sẽ đuợc nói tới duới đây .

Trong việc truy cập database, ứng dụng có thể sử dụng các phuơng pháp khác nhau như: trực tiếp sử dụng SQL, Hybernate, EJB Entity … Để đơn giản hoá vấn đề, ta lấy truờng sử dụng SQL để cập nhật database .

Trong Java, connection thường tạo ra duới dạng connection pool hay DataSource, là 1 tập họp những connection để xử dụng chung cho toàn bộ ứng dụng . Giả sử apache datasource đuợc xử dụng ở đây . Để container có thể tạo ra datasource cho oracle, ta xử dụng cấu hình duới đây

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@//localhost:1521"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>

Nếu datasource đã đuợc tạo ra xử dụng JNDI, ta có thể dùng cấu hình

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryB ean">
<property name="jndiName" value="jdbc/jpetstore"/>>

Bản thân datasource sẽ đuợc xử dụng bởi 1 transaction manager, 1 object quản lí transaction có sẵn trong spring như sau:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSou rceTransactionManager">
<property name="dataSource" ref="dataSource"/>

Trở lại class XuatNhapHang ở trên, muốn spring tự động bắt đầu và kết thúc 1 transaction mỗi khi 1 method của class này đuợc gọi , cần có những cấu hình cho pointcut hay advice khá phức tạp theo kiểu AOP . Rất may là spring đã gói gọn trong 1 class TransactionProxyFactoryBean đơn giản sau

<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="transactionAttributes">
<prop key="*">PROPAGATION_REQUIRED, -MyException</prop>

Chúng ta sẽ kiểm tra kĩ lưỡng cấu hình này .
_ abstract=”true” có nghĩa là ứng dụng không đuợc phép gọi method getBean(“txProxyTemplate”) . Cấu hình này chỉ đuợc dùng để các cấu hình khác extends . Giống như tính chất inheritance trong OOP
_ property name=”transactionManager” ref=”txManager” cho biết class TransactionProxyFactoryBean sẽ đuợc nạp bean txManager bởi container.
_ prop key=”*” : áp dụng cho mọi method của những class extends cấu hình này
_ PROPAGATION_REQUIRED: bắt đầu 1 transaction nếu chưa có hoặc tiếp tục 1 transaction có sẵn .
_ MyException: nếu method throw MyException, thì dấu – đằng truớc sẽ làm transaction bị rollback, và dấu + sẽ commit transaction truớc khi throw MyException.

Cấu hình của class XuatNhapHang sẽ extends cấu hình này như sau:

<bean id="xuatNhapBean" parent="txProxyTemplate">
<property name="target">
<bean class="XuatNhapHang"></bean>

Ứng dụng có thể xử dụng class XuatNhapHang như sau:

XuatNhapHang xnh = (XuatNhapHang)ac.getBean("xuatNhapBean");

Bằng cách extends cấu hình của txProxyTemplate qua việc sử dụng attribute parent, mỗi khi 1 method của class XuatNhapHang đuợc gọi, 1 transaction sẽ tự động bắt đầu và kết thúc . Transaction sẽ bị rollback trong truờng hợp exception MyException xảy ra . Spring còn giúp mô hình JDBC operations như những java object qua việc xử dụng class MappingSqlQuery, SqlUpdate, StoredProcedure .

Bài viết đuợc kết thúc ở đây chỉ với mục đích giúp bạn làm quen với những khái niệm của AOP . Vì AOP là cái bổ sung cho những thiếu sót của OOP, AOP không dành cho những bạn mới bắt đầu lập trình . Spring framework mặc dù triển khai AOP đơn giản hơn so với AspectJ, cũng khác phức tạp với rất nhiều chức năng có thể dùng đuợc, và nguời viết chỉ tóm tắt 1 chức năng phổ biến nhất của nó là declarative transaction. Dù sao thì bạn vẫn cần tham khảo những tài liệu huớng dẫn về Spring truớc khi có thể dùng nó 1 cách hữu hiệu . Chúc bạn may mắn.

Sưu tầm

Refactoring to Patterns – Joshua Kerievsky [PDF, ePub]

Giới thiệu

Đây là cuốn sách cực hay của tác giả Joshua Kerievsky. Nó giúp chúng ta hiểu và apply các principle, design pattern vào trong chương trình thông qua việc phân tích những đoạn code hiện tại để tìm ra các code smell, sau đó sẽ từng bước tiến hành refactor chúng theo đúng pattern.



Nội dung tham khảo

What Is Refactoring To Patterns?

Refactoring to Patterns is the marriage of refactoring — the process of improving the design of existing code — with patterns, the classic solutions to recurring design problems. Refactoring to Patterns suggests that using patterns to improve an existing design is better than using patterns early in a new design. This is true whether code is years old or minutes old. We improve designs with patterns by applying sequences of low-level design transformations, known as refactorings.

What Are The Goals Of This Book?

This book was written to help you

  • Understand how to combine refactoring and patterns
  • Improve the design of existing code with pattern-directed refactorings
  • Identify areas of code in need of pattern-directed refactoring
  • Learn why using patterns to improve existing code is better than using patterns early in a new design

To achieve these goals, this book features

  • A catalog of 27 refactorings
  • Examples based on real-world code, not the toy stuff
  • Pattern descriptions, including real-world pattern examples
  • A collection of smells (i.e. problems) that indicate the need for pattern-directed refactorings
  • Examples of different ways to implement the same pattern
  • Advice for when to refactor to, towards or away from patterns
  • A suggested study sequence for the refactorings

Who Is This Book For?

This book is for object-oriented programmers engaged in or interested in improving the design of existing code. Such programmers either

  • Use patterns and/or practice refactoring, but have never implemented patterns by refactoring
  • Know little about refactoring and patterns and would like to learn more

The types of projects for which this book is useful are:

  • Greenfield development, in which a new system or feature is being written from scratch
  • Legacy development, in which you are mostly maintaining a legacy system.

Whether you are doing greenfield or legacy development, the refactorings and design ideas in this book will help you with your work.

What Background Do You Need?

This book assumes you are familiar with design concepts like tight- or loose-coupling and object-oriented concepts like inheritance, polymorphism, encapsulation, composition, interfaces, abstract and concrete classes, abstract and static methods and so forth.

I use Java examples in this book. I find that Java tends to be easy for most object-oriented programmers to read. I’ve gone out of my way to not use fancy Java features, so whether you code in C++, C#, VB.NET, Python, Ruby, Smalltalk or some other object-oriented language, you ought be able to understand the Java code in this book.

This book is closely tied to Martin Fowler’s classic book, Refactoring [F]. It contains references to low-level refactorings, such as

  • Extract Method [F]
  • Extract Interface [F]
  • Extract Superclass [F]
  • Extract Subclass [F]
  • Pull Up Method [F]
  • Move Method [F]
  • Rename Method [F]

It also contains references to more sophisticated refactorings, such as

  • Replace Inheritance with Delegation [F]
  • Replace Conditional with Polymorphism [F]
  • Replace Type Code with Subclasses [F]

To understand the pattern-directed refactorings in this book, you don’t need to know every refactoring listed above. Instead, you can follow the example code that illustrates how the above refactorings are implemented. However, if you want to get the most out of this book, I do recommend that you have Refactoring [F] close by your side. It’s an invaluable refactoring resource, as well as a useful aid for understanding this book.

The patterns I write about come from the classic book, Design Patterns [DP], as well as from authors such as Kent Beck, Bobby Woolf and myself. These are patterns that my colleagues and I have refactored to, towards or away from on real-world projects. By learning the art of pattern-directed refactorings, you’ll understand how to refactor or towards patterns not mentioned in this book.

You don’t need expert knowledge of these patterns to read this book, though some knowledge of patterns is useful. To help you understand the patterns I’ve written about, this book includes brief pattern summaries, UML sketches of patterns and many example implementations of patterns. To get a more detailed understanding of the patterns, I’d recommend that you study this book in conjunction with the patterns literature I reference.

This book uses UML 2.0 diagrams. If you don’t know UML very well, you’re in good company. I know the basics. Whie writing this book, I kept the third edition of Fowler’s UML Distilled close by my side and referred to it often.


PDF (chất lượng hơi kém do converted từ ePub): https://drive.google.com/file/d/0BxrbqNV1YSlmUmpHRVhGYTk3Z1E/edit?usp=sharing

ePub (chất lượng gốc): https://drive.google.com/file/d/0BxrbqNV1YSlmQU55UU91SW1PcDQ/edit?usp=sharing

Xem thêm tại:


Email: edwardthienhoang@gmail.com


Java 8 Tutorial: Trọn bộ Java 8 new features từ Pluralsight

Giới thiệu


Hôm nay mình sẽ share một bộ video Trọn bộ Java 8 new features từ Pluralsight . Với hơn 4 giờ học, các bạn sẽ nắm được tất cả những đặc điểm nổi bật nhất trong Java 8 như Lambda Expression, Stream, Date and Time API, …

This course covers the most useful parts of Java 8. This update of the Java platform is the biggest of all. It’s even bigger than Java 5 that saw the introduction of generics. We’ll begin with lambda expressions and the Stream API, which bring new fundamental patterns to the Java platform. Many problems solved with the Iterator pattern are now solved much more efficiently with the patterns brought by the Stream API. But Java 8 is not only about lambdas, streams and collectors, there is also a new Java Date and Time API which are covered in this course. This API fixes all the flaws of the previous Date/Calendar API and brings new, very useful, concepts and tools. Many new features that bring a functional programming approach have been added to the Collection API. This is also covered in detail. Many more things are covered; little things, scattered here and there in the JDK, like this new StringJoiner class, useful to join strings with a prefix, a postfix, and a separator. JavaFX and Nashorn are also quickly covered, to show the FXML way to describe Graphical User Interfaces, and the new ways to describe JavaFX in Javascript using Nashorn.



Link GoogleDrivehttps://drive.google.com/folderview?id=0B5U6Rykwg1bVd3BvMFZoWGViZnM&usp=sharing

Nội dung chi tiết

Introduction to Lambda Expressions in Java 8

  • Introduction, Targeted Audience
  • Module Outline
  • The FileFilter Example
  • A First Lambda Expression
  • Live Coding: A First Lambda Expression
  • Live Coding: Runnable and Comparator Examples
  • Several Ways of Writing Lambda Expressions
  • Three Questions About Lambda Expressions
  • Functional Interfaces
  • Is a Lambda Expression an Object?
  • The Functional Interfaces Toolbox
  • Method References
  • Processing Collections With Lambdas
  • Changing the Way Interfaces Work?
  • Default and Static Methods in Java 8 Interfaces
  • New Patterns: The Predicate Interface Example
  • Live Coding: New Patterns Examples
  • Module Wrap Up

Java 8 Stream API and Collectors

  • Introduction, Module Outline
  • The Map / Filter / Reduce Algorithm
  • What Is a Stream?
  • Definition of a Stream in Java 8
  • Building and Consuming a Stream
  • Filtering a Stream
  • Live Coding: Consuming and Filtering a Stream
  • Lazy Operations on a Stream
  • Lice Coding: Intermediary and Terminal Operations
  • Wrapping up Intermediary and Terminal Operations
  • The Map Operation
  • The Flatmap Operation
  • Lice Coding: Map and Flatmap Examples
  • Wrapping Up Map and Filter on a Stream
  • Reduction, Functions, and Bifunctions
  • Reduction of the Empty Set: Identity Element
  • Optionals
  • Pattern for the Optionals
  • Wrapping Up Reduction Operations
  • Terminal Operations
  • Live Coding: Reductions, Optionals
  • Wrapping Up Operations and Optionals
  • Collectors, Collecting in a String, in a List
  • Collecting in a Map
  • Live Coding: Processing Streams
  • Wrapping Module

Java 8 Date and Time API

  • Introduction and Outline
  • The Old java.util.Date API
  • Why Does Immutability Matter?
  • The Instant Class and the Duration Class
  • The LocalDate Class and the Period Class
  • Live Coding: Local Dates and Periods Examples and Corner Cases
  • Computing Dates From Other Dates
  • The LocalTime Class
  • Dealing With Time Zones: The ZonedTime Class
  • Printing Dates and Times: The DateTimeFormatter
  • From Legacy Code to the New Date and Time API
  • Conclusion and Wrap-Up

Strings, IO, and Other Bits and Pieces

  • Introduction and Outline
  • Strings and StringJoiner
  • Java I/O: Reading Text Files
  • Java I/O: Exploring Directories
  • New Methods on Iterable, Collection, and List
  • Comparator: Patterns and Utilities
  • Numbers, Method References, and Hashcodes
  • Map: Enhancements of Existing Methods
  • Map: The Compute and Merge Methods
  • Live Coding: General Map Enhancements
  • Live Coding: Map Merging
  • Live Coding: Building Bimaps
  • Annotations
  • Conclusion and Wrap Up

Introduction to Java FX 8

  • Introduction and Outline
  • First Key Concepts on a Simple Example
  • Live Coding a Hello World Example
  • Setting Up an Interface Using the JavaFX API
  • Setting Up an Interface Using the FXML File
  • Controller and Dependency Injection
  • Live Coding: Setting Up a UI With FXML and Java Controllers
  • Conclusion and Wrap Up

Nashorn: A JavaScript Engine on the JVM

  • Introduction and Outline
  • jjs: The Nashorn REPL
  • Livecoding: The REPL in Action
  • Running Javascript in Java Classes
  • Writing and Launching JavaFX UI in Javascript
  • Live Coding: JavaFX With Nashorn
  • Conclusion and Wrap Up

Email: edwardthienhoang@gmail.com


Java 8 Tutorial: Lambda expression and Streams in Java 8


Giới thiệu

Hôm nay mình sẽ share một bộ video học Java 8 từ LiveLessions. Với hơn 3 giờ học, các bạn sẽ nắm được những đặc điểm nổi bật nhất trong Java 8 là Lambda Expression và Stream.

Tóm tắt nội dung

  • Cách sử dụng những đặc điểm quan trọng nhất trong Java 8: Lambda Expressions và Streams.
  • Những kỹ thuật sử dụng lambda expression: method references, lambda building blocks in the java.util.function package, effectively-final local variables, the @FunctionalInterface annotation, and higher-order functions.
  • Các method mới liên quan đến Stream: forEach, map, filter, reduce, etc.
  • Infinite (unbounded) streams
  • Parallel streams.
  • Lazy evaluation and short-circuit stream operations.
  • Những đặc điểm khác trong Java 8: Functional Interface và Optional class.


Bộ video này được upload trên Youtube bởi bạn Tiep Phan, mình xin mạn phép chia sẻ lại.

Nội dung chi tiết


  • Introduction to Java 8: Lambda Expressions and Streams LiveLessons

Lesson 1: Java 8: Installation, Setup, and Review of Supporting Topics

  • Learning objectives
  • 1.1 Getting Started with Java 8
  • 1.2 Java 8 References
  • 1.3 Quick Review of Pre-Lambda Handlers
  • 1.4 Quick Review of Building Generic Methods and Classes
  • 1.5 Wrap-Up

Lesson 2: Lambda Expressions Part 1 – Basics

  • Learning objectives
  • 2.1 Motivation and Overview
  • 2.2 Lambdas: Most Basic Form
  • 2.3 Type Inferencing
  • 2.4 Expression for Body: Implied Return Values
  • 2.5 Comparing Java and JavaScript Sorting
  • 2.6 Omitting Parens for One-Arg Lambdas
  • 2.7 Using Effectively Final Local Variables
  • 2.8 The @FunctionalInterface Annotation
  • 2.9 Method References
  • 2.10 The java.util.function Package
  • 2.11 Final Example
  • 2.12 Wrap-Up

Lesson 3: Lambda Expressions Part 2 – Lambda Building Blocks in java.util.function

  • Learning objectives
  • 3.1 Lambda Building Blocks in java.util.function: Overview
  • 3.2 Predicate
  • 3.3 Function and BiFunction
  • 3.4 Consumer
  • 3.5 Supplier
  • 3.6 BinaryOperator
  • 3.7 Wrap-Up

Lesson 4: Lambda Expressions Part 3

  • Learning objectives
  • 4.1 Variable Scoping
  • 4.2 Method References: Details
  • 4.3 Java 8 Interfaces: Default Methods and Static Methods
  • 4.4 Methods that Return Lambdas
  • 4.5 Wrap-Up

Lesson 5: Streams Part 1

  • Learning objectives
  • 5.1 Overview of Streams
  • 5.2 Getting Standard Data Structures Into and Out of Streams
  • 5.3 Core Stream Methods: Overview
  • 5.4 forEach – Calling a Lambda on Each Element of a Stream
  • 5.5 map – Transforming a Stream by Passing Each Element through a Function
  • 5.6 filter – Keeping Only the Elements that Pass a Predicate
  • 5.7 findFirst – Returning the First Element of a Stream while Short-Circuiting Earlier Operations
  • 5.8 Lazy Evaluation
  • 5.9 Wrap-Up

Lesson 6: Streams Part 2

  • Learning objectives
  • 6.1 reduce: Combining Stream Elements
  • 6.2 collect: Fancier Stream Output
  • 6.3 Operations that Limit the Stream Size: limit, substream
  • 6.4 Operations that Use Comparisons: sorted, min, max, distinct
  • 6.5 Operations that Check Matches: allMatch, anyMatch, noneMatch, count
  • 6.6 Parallel Streams
  • 6.7 Infinite (Unbounded On-the-Fly) Streams
  • 6.8 Wrap-Up


  • Summary of Java 8: Lambda Expressions and Streams LiveLessons


Email: edwardthienhoang@gmail.com


Eclipse tutorial: Hướng dẫn cài đặt và sử dụng CheckStyle plugin

Eclipse tutorial: Hướng dẫn cài đặt và sử dụng CheckStyle plugin

Bài viết này sẽ hướng dẫn các bạn cài đặt và sử dụng CheckStyle plugin trong Eclipse. CheckStyle là một trong những plugin phổ biến nhất trong Eclipse, giúp chúng ta kiểm tra coding convention (quy ước viết mã) dựa trên những quy tắc đã được định nghĩa trước đó. Các bạn có thể tham khảo thêm bộ quy tắc đồ sộ của CheckStyle tại đây: http://checkstyle.sourceforge.net/availablechecks.html

Cài đặt

Chọn Menu Help –> Install New Software… và nhập vào địa chỉ sau:

1. Download

Sau đó tiến hành cài đặt với vài cú click, sau đó khởi động lại Eclipse

Để kiểm tra việc cài đặt có thành công hay không, các bạn vào Menu Window –> Preferences sẽ thấy mục CheckStyle

2. InstallSuccess

Định nghĩa những quy ước

Mặc định CheckStyle dùng bộ quy ước đã được định nghĩa sẵn từ Sun, tuy nhiên bạn cũng có thể tạo ra những quy ước riêng cho mình, tùy theo đặc thù của dự án.
Đầu tiên chúng ta sẽ tạo 1 configuration file có tên là CheckStyleTemplate.xml với nội dung như sau:

<?xml version="1.0" encoding="UTF-8"?>
Checkstyle configuration (v5.x)
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.2//EN" "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
<module name="Checker">
    <property name="severity" value="warning"/>

Root tag của file là module, bên trong hiện chỉ có 1 child tag là

<property name="severity" value="warning"/>

với ý nghĩa sẽ hiện những thông báo dưới dạng warning trong Eclipse khi phát hiện những đoạn code vi phạm quy tắc.

Tiếp theo là thêm những quy tắc vào trong file config này, các bạn có thể tham khảo danh sách các quy tắc mà CheckStyle hỗ trợ tại: http://checkstyle.sourceforge.net/availablechecks.html

Trong ví dụ này, mình sẽ sử dụng 3 quy tắc: StrictDuplicateCode (không cho phép có những đoạn code trùng lặp), EqualsHashCode (khi override phương thức equals thì bắt buộc phải override phương thức hashCode) và MethodLength (giới hạn số dòng tối đa trong 1 method)

<?xml version="1.0" encoding="UTF-8"?>
Checkstyle configuration (v5.x)
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.2//EN" "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
<module name="Checker">
    <property name="severity" value="warning"/>
	<module name="StrictDuplicateCode">
		<property name="min" value="15"/>
	<module name="TreeWalker">
		<module name="EqualsHashCode"/>
		<module name="MethodLength">
		<property name="tokens" value="METHOD_DEF, CTOR_DEF"/>
		<property name="max" value="30"/>
		<property name="countEmpty" value="false"/>

Áp dụng những quy tắc vào dự án

Import những quy tắc trên vào Eclipse bằng cách chọn New trong cửa sổ CheckStyle, sau đó chọn External Configuration Filebrowse đến file config CheckStyleTemplate.xml

3. CreateNew

Sau đó chọn Set as Default để áp dụng bộ quy tắc này cho các project trong Eclipse workspace hiện tại

4. SetDefault

Kiểm tra source code với CheckStyle

Với file config như trên, ta sẽ áp dụng kiểm tra cho đoạn code dưới đây

public class TestCheckStyle {

	public static void main(String[] args) {

	private static void foo() {
		System.out.println("Bla bla bla...");
		int a = 10;
		int b = 20;
		int c = 30;
		int d = 40;
		int e = a + b + c + d;
		System.out.println("Bla bla bla... again");
		System.out.println("Bla bla bla... again");
		System.out.println("Bla bla bla... again");
		System.out.println("Bla bla bla... again");
		System.out.println("Bla bla bla... again");
		System.out.println("Bla bla bla... again");

	public boolean equals(Object o) {
		if(o instanceof TestCheckStyle) {
			return true;
		return false;

Click chuột phải vào file Java, package hoặc Project cần kiểm tra và chọn CheckStyle –> Check code with CheckStyle

5. Check

Nếu đoạn code nào vi phạm các quy tắc trên sẽ được hightlight như hình bên dưới:

6. FoundError

CheckStyle chỉ hỗ trợ phát hiện ra những đoạn code vi phạm quy tắc chứ không hỗ trợ gợi ý sửa chúng ra sao. Vì vậy việc còn lại của các bạn là sửa những vi phạm đó để tránh những lỗi về coding convention.

Kết thúc bài giới thiệu về CheckStyle plugin ở đây. Hi vọng có thể giúp ích cho các bạn trong việc kiểm tra và tránh những lỗi về coding convention trong dự án

Nguồn: https://edwardthienhoang.wordpress.com
Email: edwardthienhoang@gmail.com

Hướng dẫn sử dụng plugin Vanaraha để kiểm tra code trùng lặp

Hướng dẫn sử dụng plugin Vanaraha để kiểm tra code trùng lặp

Trong bài viết này mình sẽ giới thiệu về plugin Vanaraha, một công cụ để kiểm tra những đoạn code trùng lặp có trong chương trình, từ đó chúng ta có thể đặt những đoạn code giống nhau đó trong 1 phương thức và tái sử dụng lại.


Việc sử dụng Vanaraha rất đơn giản, các bạn vào trang chủ tại: https://code.google.com/p/vanaraha/ sau đó download gói jar ở mục Download về và bỏ vào trong thư mục eclipse\plugins. Quá trình cài đặt đã hoàn tất, khởi động lại Eclipse nếu các bạn đã mở trước đó.

Tạo 1 class để test

public class TestDuplicateCode {

	public static void main(String[] args) {


	private static void foo1() {
		int a = 10;
		int b = 20;
		int c = 30;
		int d = 40;
		int e = a + b + c + d;

	private static void foo2() {
		System.out.println("Bla bla bla...");
		int a = 10;
		int b = 20;
		int c = 30;
		int d = 40;
		int e = a + b + c + d;
		System.out.println("Bla bla bla... again");

Click chuột phải vào class TestDuplicateCode hoặc 1 package hoặc nguyên cả Project, sau đó chọn Vanahara (Find Duplicates) –> Find duplicated in this file(s) để tìm ra những đoạn code trùng lặp.

1. HuongDan

Ngoài ra Vanaraha cũng có 1 số setting tùy chỉnh như:
File Extension: để filter ra những loại file cần kiểm tra

2. File Extension
Minimum number of duplicate line(threshold): chỉ tính những đoạn code trùng lặp từ n dòng trở lên.
Và một số tùy chỉnh khác

3. Threshold

Kết thúc phần giới thiệu về plugin Vanahara tại đây, hi vọng bài viết sẽ giúp ích cho các bạn trong quá trình refactor để loại bỏ những đoạn code trùng lặp không cần thiết.

Nguồn: https://edwardthienhoang.wordpress.com

Email: edwardthienhoang@gmail.com