Create the Perfect Application

In this series of blog entries, I build an entire ASP.NET MVC Forums application from start to finish. The goal is to discover and promote best-practices for building applications with the ASP.NET MVC framework.

In this first entry, I discuss the overall goals for the forums application. I discuss the importance of avoiding code smells and how software design principles and patterns can help you write code that is resilient to future change. I also justify my choice to use test-driven development while building the Forums application.

What is Good Software?

I don’t want to build just any forums application. The goal is to build the best forums application possible. My modest goal is to build the perfect forums application.

This goal immediately leads to the question: What is good software? What makes one software application better or worse than another software application? At the end of the day, I can’t claim that I have built the perfect forums application without a definition of good software.

Therefore, here’s my definition of good software:

Good software is software that is designed to easily survive change.

There are multiple reasons that you might need to change software (see Feathers page 3):

1) You might need to add a new feature to existing software

2) You might need to fix a bug in existing software

3) You might need to optimize existing software

4) You might need to improve the design of existing software

Badly designed software is difficult to change. Software can be so poorly designed that everyone is afraid to touch it. We’ve all experienced bad software. When software is badly written, you just wish that it would go away. Or worse, given the first opportunity, you just want to rewrite it from scratch.

Avoid Code Smells

Robert and Micah Martin describe the markers of bad software as code smells. The following code smells indicate that software is badly written:

(1) Rigidity – Rigid software is software that requires a cascade of changes when you make a change in one place.

(2) Fragility – Fragile software is software that breaks in multiple places when you make a change.

(3) Needless Complexity – Needlessly complex software is software that is overdesigned to handle any possible change.

(4) Needless Repetition – Needlessly repetitious software contains duplicate code.

(5) Opacity – Opaque software is difficult to understand.

(These code smells are described by Micah and Robert Martin in their book Agile Principles, Patterns, and Practices in C# on page 104. This book is strongly recommended!)

Notice that these code smells are all related to change. Each of these code smells are a barrier to change.

Software Design Principles

By following software design principles, you can write software that is resilient to change. There are several different lists of software design principles. However, there tends to be a lot of overlap between the principles on the different lists.

For example, the Cunningham and Cunningham Wiki describes 11 principles of Object Oriented Design at:

The first 5 principles of Object Oriented Design correspond to the Software Design Principles that Robert Martin (and his son Micah Martin) promotes in the book Agile Principles, Patterns, and Practices in C#. Robert Martin also discusses these principles in the Object Mentor blog:

I found two additional books that contained useful information on Software Design Principles: Head First Design Patterns by Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates and Head First Object-Oriented Analysis and Design by Brett McLaughlin, Gary Pollice, and David West. The principles discussed in these books are not exactly the same as the Robert Martin principles, but they are close.

The truth is that all of these sources on Software Design Principles originate with Robert Martin’s work. Robert Martin did not invent all of the principles. However, he was the first one to gather the principles into a single list. Here are the Software Design Principles:

· SRP – Single Responsibility Principle

· OCP – Open Closed Principle

· LSP – Liskov Substitution Principle

· ISP – Interface Segregation Principle

· DIP – Dependency Inversion Principle

This collection of principles is collectively known by the acronym SOLID (Yes, SOLID is an acronym of acronyms).

Here is the list of the Software Design Principles from the Head First Design Patterns book:

· Encapsulate what varies

· Favor composition over inheritance

· Program to interfaces and not implementations

· Strive for loosely coupled designs between objects that interact

· Classes should be open for extension but closed for modification

· Depend on abstractions. Do not depend on concrete classes

· Only talk to your friends

· Don’t call me, we’ll call you

· A class should have only one reason to change

Again, there is a lot of overlap between this list of principles and the previous list. For example, the Single Responsibility Principle is the same as the principle that a class should have only one reason to change. However, the emphasis is slightly different. I recommend that you investigate both sources.

What motivates all of these design principles is the desire to build software that can survive change. The principles highlight different principles for creating software that can stand the test of time.

Software Design Patterns

Software Design Patterns represent strategies for applying Software Design Principles. In other words, a Software Design Principle is a good idea and a Software Design Pattern is the tool that you use to implement the good idea (It’s the hammer).

The idea behind Software Design Patterns was originally promoted by the book Design Patterns: Elements of Reusable Object-Oriented Software (This book is known as the Gang of Four book). This book has inspired many other books that describe Software Design Patterns.

The Head First Design Pattern book provides a more user-friendly introduction to the design patterns from the Gang of Four book. The Head First Design book devotes chapters to the following 14 patterns:

· Strategy

· Observer

· Decorator

· Factory

· Singleton

· Command

· Adaptor

· Façade

· Template

· Iterator

· Composite

· State

· Proxy

· Compound

Another influential book on Software Design Patterns is Martin Fowler’s book Patterns of Enterprise Application Architecture. This book has a companion website which lists the patterns from the book at:

Software Design Patterns provide you with patterns for making your code more resilient to change. For example, when building the Forums application, we’ll be taking advantage of a Software Design Pattern named the Repository Pattern. Eric Evans, in his book Domain-Driven Design, describes the Repository pattern like this:

A REPOSITORY represents all objects of a certain type as a conceptual set (usually emulated). It acts like a collection, except with more elaborate querying capability. Objects of the appropriate type are added and removed, and the machinery behind the REPOSITORY inserts them or deletes them from the database. (see page 151)

According to Evans, one of the major benefits of the Repository pattern is that it enables you to “decouple application and domain design from persistence technology, multiple database strategies, or even multiple data sources.” (ibid) In other words, the Repository pattern enables you to shield your application from changes in how you perform database access.

We’ll be taking advantage of the Repository pattern in order to isolate our forums application from a particular persistence technology. The forums application will be designed in such a way that we could switch between different data access technologies such as LINQ to SQL, the Entity Framework, or even NHibernate.

Test-Driven Development

I’m going to build the MVC Forums application by using test-driven development. In particular, before I write any application code, I will first write a unit test for the application code.

Test-driven development results in better code for the following reasons:

(1) Building tests for your code provides you with a safety net for change.

(2) Building tests for your code forces you to write loosely coupled code.

(3) Building tests for your code before you write your code forces you to take a user perspective on the code.

Let’s look more closely at each of these benefits.

First, unit tests provide you with a safety net for change. This is a point that Michael Feathers emphasizes again and again in his book Working Effectively with Legacy Code. In fact, he defines legacy code as “simply code without tests” (see xvi).

When your application code is covered by unit tests, you can modify the code without the fear that the modifications will break the functionality of your code. Unit tests make your code safe to refactor. If you can refactor, then you can modify your code using Software Design Patterns which results in better code that is more resilient to change.

Second, practicing test-driven development forces you to write code in a particular way. Testable code tends to be loosely coupled code. A unit test performs a test on a unit of code in isolation. In order to build your application so that it is testable, you need to build the application in such a way that it has isolatable components.

One class is loosely coupled to a second class when you can change the first class without changing the second class. Test-driven development often forces you to write very loosely coupled code. Loosely coupled code is resistant to change.

Finally, writing tests before you write your code forces you to take a user’s perspective on the code. By writing a test first, you take on the same perspective as a developer who will use your code in the future. Since writing tests forces you to think about how a developer (perhaps, your future self) will use your code, the code tends to be better designed.

Short Term Pain, Long Term Gain

Building software using test-driven development requires more upfront effort. Writing tests takes time. However, the idea is that the initial effort required to build the unit tests will pay huge dividends in the future.

There are two ways to be a developer. You can be a cowboy or you can be a craftsman. A cowboy jumps right in and starts coding. A cowboy can build a software application quickly. The problem with being a cowboy is that software must be maintained over time.

A craftsman is patient. A craftsman builds software carefully by hand. A craftsman is careful to build unit tests that cover all the code in an application. It takes longer for a craftsman to create an application. However, after the application is created, it is easier to fix bugs in the application and add new features to the application.


The goal is to build an MVC Forums application that will stand the test of time. It should not only work right now, the application should continue to work in the future as the needs of the people who use the application change.

I’m going to write the application by taking advantage of the Microsoft ASP.NET MVC framework. This framework makes it easy for me to write tests for my code. The ASP.NET MVC Framework was designed from the ground up to support test-driven development.



SQL Live Monitor (Quản lý SQL trực tuyến)


a .NET application that provides realtime performance data on the target SQL Server instance.

No installation required, data displayed in realtime, and can also be logged to CSV for offline analysis. Will also capture SQL data for processing uing PAL.


This tool is designed to provide realtime performance data on SQL Server, as well as data capture for offline analysis. The tools features are:

  • Realtime SQL and System performance data
  • Colour coded alerts
  • Capture data logging to CSV – sample interval configurable
  • PAL Perfmon counter logged to .blg or .csv for offline analysis using PAL – sample interval configurable
  • Detailed view of certain SQL Areas via DMVs
  • List Top 20 Queries by CPU, IO and Execution Count
  • View SQL Waits by category
  • View SQL Scheduler and CPU worker threads
  • Monitor Kernel Pools and System PTE’s
  • Supports SQL 2000,SQL 2005, SQL 2008, SQL 2012, SQL 2014
  • Captures data from local and remote servers
  • Captures data from default and named instances (stand alone & clustered)
  • Supports both SQL and Windows Authetication
  • Supports x86 and x64
  • No installation required
  • Application small in size with minimal overhead when running
  • Run multiple instances on same PC


LINK: SQL Live Monitor

Cải tiến mã nguồn (code refactoring)

Khái niệm

Mỗi người có một khái niệm cải tiến mã nguồn (code refactoring) khác nhau, và đặc biệt khi chuyển ngữ sang tiếng(việt) để tìm một thuật ngữ chính xác càng khó hơn. Ở đây tôi xin chuyển nghĩa từ refactoring thành cải tiến và chọn định nghĩa của Martin Fowler:

Refactoring là thay đổi ở cấu trúc bên trong mà không làm thay đổi hành vi với bên ngoài của hệ thống.

Cải tiến là một quá trình cơ học, hình thức và trong nhiều trường hợp rất đơn giản để làm việc với mã của hệ thống đã tồn tại để chúng trở nên “tốt hơn”. Khái niệm “tốt hơn” là một khái niệm mang tính chủ quan, và không có nghĩa là luôn làm ứng dụng chạy nhanh hơn mà thường được hiểu là theo các kỹ thuật hướng đối tượng, tăng an toàn kiểu dữ liệu, cải thiện hiệu xuất , đễ đọc, dễ bảo trì và mở rộng.

Hiệu quả của cải tiến

Sản xuất phần mềm sẽ là không hiệu quả nếu như bạn không thể theo kịp thay đổi của thế giới. Nếu như chúng ta chỉ sản xuất ra các phần mềm trong một vài ngày thì đơn giản hơn rất nhiều. Nhưng trong thế giới này chúng ta có rất nhiều đối thủ cạnh tranh. Nên nếu bạn không cải tiến phần mềm của mình, khi đối thủ có một số tính năng hưu ích mới mà bạn không cập nhật thì sản phẩm của bạn nhanh chóng bị lạc hậu. Bởi thế là một lập trình viên bạn phải đón nhận và hành động một cách thích hợp với những thay đổi. Và khi thực hiện cải tiến mã là bạn đang làm điều đó.

Cải thiện thiết kế

Nếu không áp dụng cải tiến khi phát triển ứng dụng, thì thiết kế sẽ ngày càng tồi đi. Vì khi phát triển ứng dụng thì ta sẽ ưu tiên cho các mục tiêu ngắn hạn (đặc biệt khi áp dụng các quy trình phát triển linh hoạt), nên mã ngày càng mất đi cấu trúc. Một trong những tên của vấn đề này gọi là technical debt (nợ kỹ thuật). Khi xảy ra vấn đề thì rất khó để quản lý và dễ bị tổn thương  .Thế nên việc áp dụng cải tiến sẽ giúp cho mã giữ được thiết kế tốt hơn là ưu điểm quan trọng.

Mã dễ đọc hơn

Khi lập trình là chúng ta đang giao tiếp với máy tính để yêu cầu chúng làm điều mình muốn. Nhưng còn có người khác tham gia vào quá trình này là các lập trình viên khác hay chính chúng ta trong tương lai. Chúng ta biết khi lập trình thường sẽ có người phải đọc để kiểm tra xem có vấn đề với mã đó không hoặc để mở rộng hệ thống.

Nhưng có một vấn đề là khi làm việc, lập trình viên thường không nghĩ tới những người đó trong tương lai. Vậy thì trong trường hợp này cải tiến đóng vai quan trọng là giúp cải thiện thiết kế của hệ thống, từ đó cũng giúp đọc mã dễ hơn.

Lợi ích hệ quả

Từ những lợi ích cơ bản ở trên ta có thêm các lợi ích khác: do hệ thống hiện thời có một thiết kế tốt hơn và mã dễ hiểu hơn, từ đó thì việc mở rộng hệ thống dễ dàng hơn, khó bị tổn thương hơn, nên tốc độ phát triển hệ thống luôn được duy trì; mã và thiết kế dễ đọc hơn, từ đó giúp tìm ra lỗi dễ dàng hơn; vì những mục tiêu ngắn hạn lập trình viên có thể chấp nhận một lỗ hổng nào đó về công nghệ hay thiết kế mà hiện thời không gây ảnh hưởng gì tới hệ thống, nhưng khi hệ thống lớn dần thì những lỗ hổng này được tích tụ và làm cho hệ thống dễ bị tổn thương, thể nên việc cải tiến giúp nhanh chóng sửa những lỗ hổng này.

Thời điểm thực hiện

Khi thêm một chức năng mới

Khi thêm một chức năng mới, ta phải đọc lại mã để hiểu. Như vậy nếu lúc này ta thực hiện việc cải tiến, mã sẽ dễ hiểu hơn, cộng với đó là này ta cũng dễ dàng hiểu mã hơn vì mình là người đã đọc và thực hiện việc cải tiến. Một lý do khác là khi thực hiện việc cải tiến vào thời điểm này thì thiết kế của hệ thống sẽ tốt hơn, từ đó việc mở rộng cũng dễ dàng hơn.

Khi sửa lỗi

Khi sửa lỗi ta cũng phải đọc mã, và như vậy việc cải tiến làm mã dễ đọc hơn, có cấu trúc rõ ràng hơn từ đó dễ dàng phát hiện lỗi là điều cần thiết. Và bởi thế nếu bạn được gán là người sửa một lỗi nào đó thì bạn cũng thường được gán là người phải cải tiến mã.

Khi rà soát mã

Nhiều tổ chức thực hiện việc rà soát mã (code review).  Rà soát mã giúp cho các lập trình viên giỏi truyền lại cho các lập trình viên ít kinh nghiệm hơn, giúp cho mọi người viết mã rõ ràng hơn. Mã có thể là rất rõ ràng với tác giả, nhưng với người khác thì có thể không, bởi thế rà soát mã sẽ làm cho nhiều người đọc mã hơn. Có nhiều người đọc mã thì mã phải dễ đọc hơn và có nhiều ý tường hơn được trao đổi giữa các thành viên trong nhóm hơn. Bởi thế khi bạn thực hiện rà soát bạn phải đọc mã. Lần đầu bạn đọc, bạn bắt đầu hiểu mã. Lần tiếp theo bạn sẽ có nhiều ý tưởng hơn để cải tiến mã, từ đó bạn có thể thực hiện việc cải tiến.


Các “mã bẩn” thường gặp

Chúng ta đã biết cần thực hiện cải tiến khi nào, nhưng có một câu hỏi khác là mã như thế nào thì cần cải tiến? Khái niệm mã bẩn (code smell) là mã có thể sinh vấn đề một cách lâu dài, sẽ giúp ta phát hiện mã cần phải cải tiến. Sau đâu chúng ta sẽ liệt kê một số loại mã bẩn thường gặp:

  • Mã lặp

Là những đoạn mã xuất hiện nhiều hơn một lần trong một hoặc nhiều ứng dụng của một chủ thể. Đó là hệ quả của các hành động: sao chép mã; các chức năng tương tự được viết bởi các lập trình viên khác nhau. Hệ quả là mã trở nên dài hơn, khó hiểu hơn và khó bảo trì hơn.

Ví dụ đoạn mã tính giá trị trung bình của một mảng số nguyên trên C:

extern int array1[];

extern int array2[];


int sum1 = 0;

int sum2 = 0;

int average1 = 0;

int average2 = 0;


for (int i = 0; i < 4; i++){

sum1 += array1[i];


average1 = sum1/4;

for (int i = 0; i < 4; i++){

sum2 += array2[i];


average2 = sum2/4;

Ta thấy hai vòng lặp for là giống nhau!

  • Hàm dài

Hàm dài là quá phức tạp, có lượng mã lớn. Nên khó để hiểu, triển khai, bảo trì và tái sử dụng. Nên việc tách thành các hàm nhỏ hơn là điều cần thiết.

  • Lớp lớn

Lớp lớn là lớp chứa quá nhiều thuộc tính và chức năng, thường là của nhiều lớp khác. Bởi thế cũng khó để đọc, bảo trì và tái sử dụng. Nên cần thực hiện các kỹ thuật cần thiết để phân bổ thành nhiều lớp khác nhau.

  • Hàm có nhiều tham số đầu vào

Khi một hàm có nhiều tham số đầu vào sẽ gây khó khăn để đọc, dùng và thay đổi. Với các ngôn ngữ lập trình hướng đối tượng ta có thể nhóm các tham số có liên quan vào một đối tượng để giảm số lượng tham số đầu vào.

  • Tính năng không phải của lớp

Là hiện tượng một phương thức không nên thuộc một lớp, nhưng do phương thức muốn sử dụng các dữ liệu của lớp đó nên lập trình viên đã gán phương thức  cho lớp. Đây là một vi phạm trong lập trình hướng đối tượng. Ta cần trả phương thức đó về đúng đối tượng.

  • Lớp có quan hệ quá gần gũi

Đó là hiện tượng hai lớp có thể truy xuất vào các thuột tính riêng tư của nhau một cách không cần thiết. Điều đó đẫn đến là chính các lớp đó hay lớp con của chúng có thể thay đổi các thuộc tính của lớp con lại một cách “vô thức”.

  • Lớp quá nhỏ

Việc tạo, bảo trì và hiểu một lớp tốn tài nguyên. Vậy nếu lớp đó quá nhỏ thì ta nên xóa bỏ lớp đó đi.

  • Lệnh switch

Một trong những dấu hiệu tốt của lập trình hướng đối tượng là việc không dùng lệnh switch. Vấn đề của lệnh switch chủ yếu là vấn đề lặp mã. Bạn thường gặp những lệnh switch để phân bổ các chức năng ở nhiều nơi khác nhau trong cùng một ứng dụng. Và mỗi khi bạn thêm một tính năng mới, bạn phải tìm ở tất cả các lệnh này để thay đổi.

  • Từ chối kế thừa

Điều này xảy ra khi một lớp được thừa kế dữ liệu cũng như các tính năng của lớp cha, nhưng lại không cần phải dùng tới chúng. Chúng ta không thể cấm đoán điều, nhưng nếu điều này xảy ra thường dẫn tới vấn đề hiểu lầm và vấn đề.

  • Định danh quá dài hoặc quá ngắn

Các định danh cần mô tả đủ ý nghĩa để mã dễ đọc hơn và tránh gây hiểu nhầm. Bởi thế các định danh quá ngẵn thường không mô tả hết ý nghĩa và gây ra nhầm lẫn.  Nhưng các định danh quá dài cũng có vấn đề tương tự. Bởi thế trong trường hợp này chúng ta có thể viết tắt hay tìm định danh thay thế.

  • Dùng quá nhiều giá trị

Nếu trong mã có nhiều giá trị  thì khi cần phải thay đổi các giá trị đó vì một lý do nào đó (ví dụ thay đổi độ chính xác) thì bạn cần phải thay đổi ở nhiều nơi. Không chỉ thế mà không phải ai và lúc nào cũng nhớ những giá trị đó có ý nghĩa gì, nên làm cho mã trở nên khó đọc hơn. Trong trường hợp này bạn có thể thay bằng cách đặt tên cho các hằng.


Các kỹ thuật cải tiến cơ bản

Các kỹ thuật cải tiến được chia thành các nhóm tùy theo tiêu chí. Ở đây chúng ta sẽ chia theo mục đích.

  1. Trừu tượng hóa mã nguồn
  2. Chia nhỏ mã nguồn
  3. Chuẩn hóa mã nguồn

Kết luận

Cải tiến là công việc cần thiết và đem lại hiệu quả cao. Nhưng lượng các kỹ thuật mà ta áp dụng được cho dự án của mình thì rất nhiều và tốn kém thời gian. Trong bài viết này tôi không hy vọng sẽ trình bày được tất cả hay nhiều kỹ thuật mà chỉ là một số kỹ thuật căn bản nhất.


Giải pháp khoá thông minh sử dụng công nghệ RFID phục vụ cho việc giám sát container

    Sau một thời gian hợp tác nghiên cứu và phát triển, Trung tâm nghiên cứu và đào tạo thiết kế vi mạch (ICDREC) thuộc Đại học Quốc gia TP.HCM và Trung tâm nghiên cứu và phát triển (SHTPLABS) thuộc Khu công nghệ cao TP.HCM đã công bố ứng dụng chip SG8V1 và HF RFID của VN trong hệ thống giám sát container (CTS-01).
    CTS-01 là một hệ thống giám sát và quản lý container từ xa với một hệ thống server và cơ sở dữ liệu tập trung. Thiết bị đầu cuối CTS-01 là một khóa được lắp vào container thay thế cho cách bấm seal truyền thống, để mở khóa phải dùng 1 thẻ RFID đã được khai báo trước, thiết bị gửi dữ liệu về trung tâm qua mạng GSM cho biết vị trí, vận tốc, hành trình của xe, trạng thái đóng/mở khóa, xác thực người đóng mở khóa theo thời gian thực và hiển thị trên phần mềm Tracking, bản đồ số của hệ thống.

    CTS-01 cũng hỗ trợ các tính năng hệ thống đặc biệt hữu dụng cho công tác quản lý và giám sát container hàng hóa, điển hình là hàng hóa tạm nhập tái xuất của các cơ quan quản lý nhà nước và Hải quan. Bên cạnh đó là các tính năng phục vụ cho nhu cầu điều hành, quản lý của các doanh nghiệp vận tải.

    Sau một quá trình thử nghiệm với các doanh nghiệp vận tải thì hệ thống CTS-01 đã được các doanh nghiệp đánh giá cao và cho biết sẵn sàng hợp tác với ICDREC và SHTPLABS để tiếp tục phát triển sản phẩm này cho hoàn thiện hơn. Theo các doanh nghiệp vận tải đã thử nghiệm thì CTS-01 giúp họ yên tâm hơn với những hàng hoá giá trị lớn, không lo bị mất cắp, không sợ bị trễ hẹn giao hàng vì các lý do chủ quan,…

    Theo ông Ngô Đức Hoàng, giám đốc ICDREC cho biết thì một hệ thống CTS-01 căn bản có giá chỉ bằng một nửa so với những sản phẩm từ nước ngoài, cụ thể là vào khoảng 350 USD.

    Và trong sự kiện công bố, Trung tâm ICDREC và SHTPLABS đã ký thỏa thuận hợp tác về phát triển và mở rộng thị trường cho sản phẩm CTS-01 với hai đối tác là Công ty TM-XNK-SX Hưng Thái và Công ty Vận tải Nam Thắng, mở ra cơ hội thương mại hóa sản phẩm mạnh mẽ trong thời gian tới.

    Video giới thiệu và thử nghiệm hệ thống CTS-01:

    Hình ảnh trên tay ổ khoá “thông minh” cho xe container: