Chuyển đến nội dung chính

Coding Style

Tài liệu này liệt kê ra các quy chuẩn lập trình C++ thông dụng. Các quy chuẩn này được đưa ra dựa trên nhiều nguồn tin, khảo sát, kinh nghiệm cá nhân của những lập trình viên C++.
Có nhiều lý do mà các quy chuẩn này được đưa ra, trong đó lý do chính là đa phần các lập trình viên quá cá nhân và gói gọn trong quy tắc của riêng họ, gây khó hiểu cho người tiếp nhận mã nguồn, do đó những quy tắc cụ thể (đặc biệt là về đặt tên) cần phải được xây dựng chung.
Những quy tắc này có kèm theo một số ví dụ để người đọc để hiểu và dễ vận dụng. Trong các dự án thực thường xảy ra vấn đề pha trộn giữa ngôn ngữ bình thường và ngôn ngữ kỹ thuật gây khó hiểu, tài liệu này sẽ không đề cập đến bất kỳ kỹ thuật lập trình C++ nào cả, mà tập trung vào hướng dẫn phong cách lập trình.
Các IDE có thể cải thiện khả năng đọc mã nguồn thông qua khả năng nhảy con trỏ (đến các hàm, biến trong chương trình), thay đổi màu từ khóa, tự động điền… vân vân…. tuy nhiên các lập trình viên không nên phụ thuộc vào những tiện ích này. Mã nguồn không phải lúc nào cũng được đọc bằng một IDE nhất định, nó cần được phát triển độc lập và tối đa hóa khả năng đọc mã nguồn trên bất kỳ công cụ nào.

1.  Hướng dẫn đọc

Các quy tắc được gom nhóm theo chủ đề và được đánh số để tiện đọc.
Các quy tắc được trình bày như sau:
Trình bày ngắn gọn về quy tắc này.
Ví dụ (nếu có)
Lý do nên dùng, bối cảnh dùng và các thông tin thêm.
Cần chú ý phần Lý do, các tiêu chuẩn này có thể khác nhau trong các môi trường, văn hóa, ngôn ngữ khác nhau.

2.   Chú ý quan trọng

Bạn nên chú ý các từ khóa “phải, nên, có thể”, “phải” đại diện cho một quy tắc bạn phải tuân thủ theo, “nên” là các quy tắc được khuyến cáo nên dùng, và “có thể” là các hướng dẫn chung, gợi ý.

B.Các quy tắc chung

Được phép vi phạm mọi quy tắc của tài liệu này nếu nó cải thiện khả năng đọc mã của bạn.

Mục tiêu chính của tài liệu là gia tăng khả năng đọc mã cho lập trình viên để gia tăng sự thông hiểu đối với mã nguồn và khả năng chỉnh sửa, bảo trì mã nguồn đó. Bộ quy tắc này không thể bao hàm tất cả các trường hợp, nên lập trình viên cũng cần linh hoạt tiếp thu theo môi trường học tập và làm việc.

Được phép vi phạm mọi quy tắc nếu có sự phản đối nào đó mà bạn phải tuân thủ.

Mục đích của người biên soạn là tạo ra một hướng dẫn, không phải để ép buộc người đọc sử dụng một phong cách mang tính cá nhân, dù sao thì các lập trình viên có kinh nghiệm có thể sẽ muốn áp dụng những quy tắc khác, nhưng có một điều, ít nhất bạn hãy làm quen với quy tắc này, để bạn có thể bắt đầu làm quen với vấn đề phong cách lập trình và bước đầu tìm ra thói quen của mình khi lập trình.
Mặt khác, các lập trình viên chưa có kinh nghiệm cũng nên sử dụng một phong cách để tiện lợi hơn trong việc lập trình và đặt tên.

C. Quy ước đặt tên

1. Quy ước đặt tên chung

Tên của các kiểu dữ liệu (class, struct, enum…) phải viết hoa chữ cái đầu tiên của mỗi từ.
Line, SavingAccount
Quy tắc này đã khá phổ biến trong cộng đồng lập trình C++.

Tên biến phải bắt đầu với chữ cái thường và viết hoa chữ cái đầu của các từ sau.
line, savingAccount
Khá phổ biến, quy tắc này giúp phân biệt biến và kiểu dữ liệu và có tác dụng giải quyết lỗi trong khai báo: Line line;

Tên của các hằng (kể cả các giá trị của kiểu enum) phải viết hoa toàn bộ, sử dụng dấu gạch dưới để phân biệt các từ.
MAX_ITERATION, COLOR_RED, PI
Khá phổ biến trong cộng đồng C++. Tuy nhiên, nên giảm thiểu việc sử dụng các hằng số như vậy, thay vào đó tạo lập một hàm lấy về giá trị sẽ tốt hơn:

int getMaxIterations()   //THAY CHO: MAX_ITERATIONS = 25
{
                return 25;
}

Kiểu hàm này vừa dễ đọc vừa đảm bảo sự thống nhất về  Interface đối với các giá trị trong class.

Tên của các hàm phải bắt đầu bằng động từ và chữ cái đầu tiên phải viết thường.
getName(), computeTotalWidth()
Khá phổ biến trong cộng đồng C++. Khá giống tên biến, nhưng rất dễ dàng để phân biệt hàm với biến trong C++. Trong trường hợp lấy địa chỉ hàm, thì ta cũng dễ dàng thấy tên hàm luôn bắt đầu với động từ còn tên biến là tính từ hoặc danh từ.

Tên của namespace phải ghi thường toàn bộ.
model::analyzer, io::iomanager, common::math::geometry
Đã khá phổ biến trong cộng đồng C++.

Tên của các lớp mẫu trong template phải là một ký tự hoa duy nhất.
template<class T>....template<class C, class D>....
Khá phổ biến, cách đặt tên này giúp tên của các lớp mẫu nổi bật lên giữa các tên khác.

Các chữ cái trong những từ viết tắt không được viết hoa toàn bộ khi dùng để đặt tên.
exportHtmlSource();  //THAY CHO: exportHTMLSource();
openDvdPlayer();           //THAY CHO: openDVDPlayer();
Dùng chữ viết hoa cho các từ viết tắt sẽ gây mâu thuẫn với các quy tắc trên, những biến kiều này có thể đặt tên kiểu dVD, hTML nhưng sẽ khá khó đọc, hơn nữa rất khó phân biệt khi ta đặt những tên có nhiều từ (như trên) và các từ viết hoa bị nối liền với nhau.

Các biến toàn cục phải luôn được gọi bằng toán tử quan hệ (::)
::mainWindows.open(), ::applicationContext.getName()
Tuy nhiên nên hạn chế sử dụng biến toàn cục, thay vào đó hãy sử dụng singleton pattern.

Thuộc tính của các lớp nên có dấu gạch dưới sau tên.
class SomeClass { private: int length_;}
Ngoài tên và loại của thuộc tính thì phạm vi của biến là một điều quan trọng cần lưu ý. Quy tắc này giúp người đọc mã dễ dàng phân biệt các biến thuộc quyền quản lý của lớp đang viết và các biến trong hàm. Thuộc tính của lớp được đánh giá là quan trọng hơn so với các biến khác trong hàm, và đánh dấu như vậy, lập trình viên sẽ dễ dàng nhận ra chúng để “chăm sóc đặc biệt”.
Một tác dụng khác nữa là cách đặt tên này sẽ giải quyết vấn đề trùng tên của hàm set một cách nhanh gọn và đỡ nhức đầu:

void       setDepth(int depth)
{
                depth_ = depth;
}

Một vấn đề nữa là liệu dấu gạch chân nên được thêm vào trước hay sau tên thuộc tính. Thực ra cả 2 cách này đều thường được sử dụng, nhưng đặt gạch dưới sau tên được khuyến khích hơn vì nó ít ảnh hưởng hơn đến việc đọc và gõ tên biến.
Lưu ý rằng: việc đặt các ký hiệu xác định phạm vi trong tên biến vẫn còn một số tranh cãi, nhưng quy ước này vẫn đang dần được chấp nhận và ngày càng phổ biến hơn trong các môi trường chuyên nghiệp.

Các biến chung (Generic variables) nên đặt tên giống với kiểu của chúng.
void setTopic(Topic* topic) // NOT: void setTopic(Topic* value)
                           // NOT: void setTopic(Topic* aTopic)
                           // NOT: void setTopic(Topic* t)
void connect(Database* database) // NOT: void connect(Database* db)
                           // NOT: void connect (Database* oracleDB)
Giảm độ phức tạp bằng cách giảm số lượng tên sử dụng, hơn nước quy ước này làm cho người lập trình dễ dàng liên tưởng đến kiểu dữ liệu của biến.
Nếu vì lý do nào đó mà quy ước này “có vẻ không phù hợp” thì đó là dấu hiệu của việc đặt tên kiểu không phù hợp.
Những biến không chung là những biến giữ một vai trò nào đó, hay có nhiều biến cùng kiểu trong đoạn chương trình. Các biến này thường được đặt tên bằng cách kết hợp vai trò của biến và tên kiểu dữ liệu.

Point     startingPoint, centerPoint;
Name    loginName;

Tên biến phải được đặt bằng tiếng Anh.
fileName;  //NOT:tenfile
Tiếng Anh là ngôn ngữ ưu tiên trong lập trình, vì có khả năng phát triển quốc tế.

Phân biệt phạm vi của biến dựa theo độ dài của tên.

Các biến có phạm vi sử dụng rộng nên được đặt tên dài hơn các biến có phạm vi nhỏ, theo quy ước này, người lập trình có thể giả định được một số biến chỉ sử dụng trong một số dòng lệnh nhất định. Những cái tên phổ biến cho các biến số nguyên cục bộ là i,j,k,m,n và cho ký tự là c,d.

Nên tránh đặt tên hàm có từ đại diện được cho đối tượng.
line.getLength(); // NOT: line.getLineLength();
Đặt tên như vậy khiến tên hàm có vẻ tự nhiên, tuy nhiên điều đó không cần thiết (như ví dụ).

2. Quy ước đặt tên cụ thể.

Phải sử dụng bộ hàm get/set khi truy cập trực tiếp đến thuộc tính của đối tượng.
employee.getName();
employee.setName(name);

matrix.getElement(2, 4);
matrix.setElement(2, 4, value);


Thuật ngữ compute nên được dùng để đặt tên cho các hàm tính toán.
valueSet->computeAverage();
matrix->computeInverse()
Làm người đọc ngay lập tức nhận ra đây là thao tác cần nhiều thời gian nếu gọi nhiều lần, trong trường hợp đó, lập trình viên có thể xem xét việc lưu kết quả vào bộ nhớ đệm. Sử dụng bộ hàm này sẽ khiến mã dễ đọc hơn. (Trường hợp thao tác với nhiều lớp)

Thuật ngữ find nên được dùng để đặt tên cho các hàm tìm kiếm.
vertex.findNearestVertex();

matrix.findMinElement();
Giúp người đọc dễ dàng nhận ra đây là một hàm tìm kiếm thông thường với các phép tính đơn giản bên trong. Khiến mã dễ đọc hơn.

Tiền tố initialize có thể được dùng để đặt tên cho các hàm thiết lập đối tượng.
printer.initializeFontSet();
initialize (Anh – Mỹ) thường được dùng hơn initialise (Anh – Anh). Nên tránh tên viết tắt init.

Biến đại diện cho các đối tượng trên giao diện người dùng nên có hậu tố là tên kiểu dữ liệu của đối tượng.
mainWindow, propertiesDialog, widthScale, loginText, leftScrollbar, mainForm, fileMenu, minLabel, exitButton, yesToggle...
Giúp người đọc mã dễ dàng nhận ra kiểu dữ liệu và các nguồn tài nguyên đối tượng sử dụng.

Nên dùng dạng số nhiều của từ để đặt tên cho các biến có thể lưu trữ nhiều đối tượng.
vector<Point> points;
int values[];
Cho người đọc mã biết đây là một tập hợp các phần tử, có thể sử dụng toán tử lấy phần tử ([]) và thao tác lên các phần tử đó.

Nên đặt n trước các biến biểu thị tổng số lượng.
nPoints, nLines
Quy ước này tương tự như Toán, dùng để chỉ các biến lưu trữ số lượng của thứ gì đó.

Nên đặt tên các biến đếm là i,j,k…
for (int i = 0; i < nTables); i++) {
  :
}

for (vector<MyClass>::iterator i = list.begin(); i != list.end(); i++) {
  Element element = *i;
  ...
}
Quy ước này cũng lấy từ toán học, để chỉ ra đây là các biến đếm của vòng lặp.

Nên đặt is trước tên của các biến hoặc hàm logic.
isSet, isVisible, isFinished, isFound, isOpen
Đã phổ biến trong cộng dồng C++ và một phần của cộng đồng Java.
Sử dụng tiền tố is giúp lập trình viên giải quyết vấn đề lựa chọn tên cho các biến logic, tránh được các tên gây khó hiểu như status hoặc flag.isStatus hoặc isFlag.
Thực ra ngoài is ta có thể lựa chọn một số tiền tố khác tùy theo trường hợp:
bool hasLicense();
bool canEvaluate();
bool shouldSort();

Phải dùng đúng tên cho các bộ hàm bổ sung.
get/set, add/remove, create/destroy, start/stop, insert/delete, increment/decrement, old/new, begin/end, first/last, up/down, min/max, next/previous, old/new, open/close, show/hide, suspend/resume.....
Đơn giản hóa việc đặt tên cho các hàm có chức năng ngược nhau.

Nên tránh các từ viết tắt khi đặt tên.
computeAverage(); // NOT: compAvg();
Việc này cũng phân ra 2 nhóm từ:
-Nhóm thứ nhất – từ nguyên bản dễ gợi nhớ hơn từ viết tắt, nhóm này nên sử dụng các từ nguyên bản:
cmd   ->   command
cp    ->   copy
pt    ->   point
comp  ->   compute
init  ->   initialize….

-Nhóm thứ 2 – từ viết tắt được biết đến nhiều hơn và dễ gợi nhớ hơn từ gốc, nhóm này nên sử dụng các từ viết tắt:
HypertextMarkupLanguage  ->   html
CentralProcessingUnit    ->   CPU
PriceEarningRatio   ->  pe

Nên tránh sử dụng các từ ám chỉ con trỏ để đặt tên cho con trỏ.
Line* line;     //NOT: Line* pLine
                //NOT: Line* linePtr
Rất nhiều biến trong môi trường C/C++ là con trỏ nên ta gần như không thể tìm ra đủ tiền tố hay hậu tố cho các con trỏ. Ngoài ra mỗi đối tượng trong chương trình đều có một chức năng riêng, người lập trình sẽ theo chức năng để thao tác nên các tiền tố  (hậu tố) này không cần thiết. Chỉ nên nhấn mạnh kiểu của biến con trỏ khi nó có ý nghĩa đặc biệt.

Không nên đặt isNot hoặc isNo trước các tên (biến hoặc hàm) logic.
bool isError; // NOT: isNoError
bool isFound; // NOT: isNotFound
Cách đặt tên này gây khó khăn cho người đọc mã nếu trong mã nguồn của bạn xuất hiện vấn đề phủ định 2 lần một đối tượng nào đó. Ví dụ như: !isNotFound.

Các giá trị của kiểu enum có thể bắt đầu bởi một từ đặc trưng cho kiểu.
enum Color { COLOR_RED, COLOR_GREEN, COLOR_BLUE };
Cách viết này cho người đọc thông tin về kiểu dữ liệu của giá trị - nơi mà các giá trị tương tự được định nghĩa.
Một cách khác là luôn sử dụng tên kiểu để gọi giá trị: Color::RED. Airline::AIR_FRANCE…
Một lưu ý khác: tên của kiểu dữ liệu enum nên đặt ở số ít, ví dụ như Color. Sử dụng dạng số nhiều như Colors có thể không ảnh hưởng gì tuy nhiên dễ gây bối rối khi sử dụng, vì ta chỉ gọi một giá trị trong enum cho mỗi lần gọi tên lớp.

Các lớp định nghĩa biệt lệ nên có đuôi là Exception.
class AccessException{...}
Các lớp biệt lệ không nằm trong phạm vi chương trình, nên đặt tên kiểu này sẽ giúp chúng nổi bật hơn.

Các hàm/phương thức nên được đặt tên theo kết quả trả về (functions) hoặc chức năng của chúng (procedures).

Giúp lập trình viên dễ nhận ra chức năng và cách sử dụng của các hàm/thủ tục, qua đó tránh được các “tác dụng phụ” từ hàm/thủ tục.

D. Tập tin

1. Các tập tin mã nguồn

Các file header nên có phần mở rộng .h hoặc .hpp, còn các tập tin mã nguồn nên có đuôi .c++/.c/.cc/.cpp
MyClass.c++, MyClass.h
Tất cả những phần mở rộng này đều được C++ chấp nhận.

Một lớp nên được khai báo ở một file header và định nghĩa ở một file mã nguồn cùng tên.
MyClass.h, MyClass.c++
Giúp dễ dàng tìm kiếm các file liên kết với một lớp nào đó. Tuy nhiên, có một ngoại lệ, đó là các lớp khuôn mẫu (template) phải được khai báo và định nghĩa trong cùng 1 file.

Tất cả các định nghĩa phương thức của một lớp phải được đặt trong cùng một tập tin.
class MyClass {
public: int getValue () {return value_;} // NO!
... private: int value_;
.
.
};
Các file header chỉ bao gồm các khai báo, file mã nguồn mới là file định nghĩa các phương thức (ngoại trừ trường hợp template). Một định nghĩa phương thức dù ngắn đến đâu cũng phải nằm trong file mã nguồn của lớp.

Các câu lệnh phải ngắn, mỗi dòng chỉ được phép có 80 kí tự trở xuống tính từ lề trái của file.

80 kí tự là quy ước chung cho các trình soạn thảo, in ấn và debug, hơn nữa các tập tin này được chia sẻ giữa nhiều lập trình viên nên giữ cho dòng lệnh không quá dài sẽ giúp người đọc mã dễ dàng tiếp thu hơn.

Phải tránh các ký tự đặc biệt như Tab hay ngắt trang.

Các kí tự này dễ gây ra xung đột với các chương trình chỉnh sửa, in ấn, các trình giả lập và debug khi chương trình được phát triển theo nhiều công đoạn, bởi nhiều lập trình viên, trên nhiều nền tảng.

Các dòng lệnh phải được phân chia rõ ràng.
totalSum = a + b + c +
           d + e;

function (param1, param2,
          param3);

setText ("Long line split"
         "into two parts.");

for (int tableNo = 0; tableNo < nTables;
     tableNo += tableStep) {
  ...
}
Khi các dòng lệnh có nhiều hơn 80 kí tự thì chúng cần được chia thành nhiều dòng. Thực tế không có một quy định nào rõ ràng về việc chia dòng, nhưng thông thường, chúng ta nên đảm bảo các điều kiện sau:
-          Ngắt dòng sau dấu phẩy (hoặc một toán tử).
-          Hàng mới bắt đầu tại vị trí ngang với điểm bắt đầu danh sách đối số hoặc điểm bắt đầu tính toán của hàng trên.
-          Trường hợp xảy ra ngắt dòng lệnh phải thêm 1 khoảng trống giứa dòng lệnh vừa ngắt và dòng tiếp theo đó.

2. Khai báo và include thư viện.

Các file header (.h) phải chứa “khóa bảo vệ trùng file”.
#ifndef COM_COMPANY_MODULE_CLASSNAME_H
#define COM_COMPANY_MODULE_CLASSNAME_H
  :
#endif // COM_COMPANY_MODULE_CLASSNAME_H
Các khóa này nhằm bảo vệ chương trình khỏi các lỗi biên soạn. Khóa này nhằm định danh cho mã nguồn nằm bên trong khóa, qua đó tránh được lỗi về xung đột mã nguồn khi một hoặc nhiều đoạn mã được biên soạn lại.

Các khối include nên được phân loại và sắp xếp, sắp xếp theo sự phân cấp về vị trí, và các thư viện cơ sở nên được include trước. Đặt một khoảng trắng giữa các cấp.
#include <fstream>
#include <iomanip>

#include <qt/qbutton.h>
#include <qt/qtextfield.h>

#include "com/company/ui/PropertiesDialog.h"
#include "com/company/ui/MainWindow.h"
Ngoài ra để người đọc dễ hình dung, các directive include cũng cho phép người lập trình truyền vào đường dẫn đến thư viện được sử dụng.
Tránh sử dụng các đường dẫn tuyệt đối. Thay vì truyền vào file gốc chứa các thư viện được sử dụng, ta nên chỉ ra cụ thể các thư viện được sử dụng trong project.

Các Directive include phải được đặt ở đầu các file.

Nhằm tránh các lỗi không mong muốn, gây ra bởi các lệnh include nằm ẩn sâu trong mã nguồn.

E. Khai báo

1. Về khai báo.

Loại khai bảo sử dụng trong 1 file thì chỉ có thể được khai báo trong chính file đó.

Tính bảo mật dữ liệu.

Các phần của một class phải được sắp xếp theo thứ tự: public – protected – private.

Thiết lập trật tự cho các phần của class, người dùng có thể dừng đọc class khi lăn đến khu vực không được thao tác.

Luôn sử dụng khai báo ép kiểu một cách rõ ràng. Không bao giờ sử dụng ép kiểu “ngầm”.
floatValue = static_cast<float>(intValue);
// NOT: floatValue = intValue;
Bằng cách này, người lập trình chỉ ra được rằng: hai kiểu dữ liệu này ít nhiều có sự liên quan với nhau, và sự chuyển đổi này là có chủ ý.

2. Về biến.

Các biến nên được khởi tạo ngay tại nơi chúng được khai báo.

Điều này đảm bảo rằng biến luôn tồn tại giá trị phù hợp. Đôi khi ta không thể khởi tạo giá trị cho biến ngay khi khai báo, như ví dụ:

int x, y, z;
getCenter(&x, &y, &z);

Trong những trường hợp này, tốt hơn ta nên đặt giá trị rỗng cho biến chứ không nên tạo giá trị giả.

Biến phải đơn nghĩa.

Khiến mã nguồn dễ đọc hơn, một biến chỉ đại diện cho một khái niệm duy nhất, với một tác dụng duy nhất. Tránh được một số lỗi khi chuyển đổi công dụng của biến.

Nên hạn chế việc sử dụng biến toàn cục (global).

Trong C++ thì không có lý do gì để người lập trình buộc phải lựa chọn biến toàn cục cả. Điều này cũng tương tự đối với các hàm toàn cục và các khối biến toàn cục.

Thuộc tính của lớp không được khai báo công khai (public).

Việc khai báo thuộc tính ở phạm vi public sẽ vi phạm các quy phạm về tính đóng gói và mã hóa dữ liệu của C++. Thay vào đó, ta nên sử dụng các thuộc tính private và các hàm truy cập kèm theo. Quy tắc này có một ngoại lệ, đó là khi ta khai báo một lớp như một cấu trúc dữ liệu, không có bất kỳ phương thức nào (tương đương với Struct).
Lưu ý rằng: struct được giữ lại trong C++ chỉ để tương thích với C, tránh sử dụng sẽ giúp mã nguồn dễ đọc hơn (do giảm số lượng các cấu trúc sử dụng), thay cho struct, trong C++ ta nên dùng class.

Dấu hiệu con trỏ và tham chiếu trong C++ nên được đặt gần tên biến khi khai báo.
float* x; // NOT: float *x;
int& y;   // NOT: int &y;
Con trỏ và tham chiếu của một biến giống một thuộc tính trong kiểu hơn là tên một biến. Lập trình viên C thường sử dụng các tên thay thế gần nghĩa, trong khi đó, C++ thường sử dụng quy chuẩn này.

Các toán tử ngầm định với 0 không nên được sử dụng khi kiểu dữ liệu không phải boolean.
if (nLines != 0)  // NOT: if (nLines)
if (value != 0.0) // NOT: if (value)
C++ tiêu chuẩn không nhất thiệt định nghĩa số nguyên hay số thực với giá trị 0 là dãy bit 0. Hơn nữa, bằng cách sử dụng một toán tử so sánh rõ ràng sẽ giúp người đọc nhanh chóng nhận biết kiểu dữ liệu của biến được so sánh.

Nên khai báo phạm vi tồn tại của biến càng nhỏ càng tốt.

Việc giới hạn phạm vi tồn tại của biến thật nhỏ sẽ giúp người lập trình tránh được những tác dụng không mong muốn.

3. Về vòng lặp.

Chỉ duy nhất biến kiểm soát vòng lặp mới phải đưa vào cặp () của vòng lặp for.
sum = 0;                   // NOT: for (i = 0, sum = 0; i < 100; i++)
for (i = 0; i < 100; i++)            sum += value[i];
  sum += value[i];
Phân biệt được biến quản lý và các biến xử lý trong vòng lặp, hỗ trợ lập trình viên đọc và bảo trì mã nguồn.

Biến xử lý trong vòng lặp nên được khởi tạo ngay trước vòng lặp.
isDone = false;           // NOT: bool isDone = false;
while (!isDone) {         //      : //Many line
  ://Many line            //      while (!isDone) {
}                         //        : //Many line
                          //      }


Có thể tránh các vòng lặp do-while.

Vòng lặp do-while khó đọc hơn vòng while hay for thông thường, do điều kiện của các kiểu vòng lặp này được đặt ở đầu vòng lặp. Khi sử dụng do-while, người đọc phải đọc vào vòng lặp để hiểu cơ chế và điều kiện dừng của vòng lặp .
Thêm vào đó, ta không nhất thiết phải sử dụng vòng do-while, bất kỳ vòng do-while nào cũng có thể dễ dàng viết lại thành vòng while hay vòng for. Giảm số lượng cấu trúc sử dụng khi lập trình sẽ giúp mã nguồn đơn giản và dễ đọc hơn.

Nên tránh sử dụng break và continue trong vòng lặp.

Các từ khóa này chỉ nên được sử dụng trong các trường hợp ngoại lệ – khiến mã nguồn dễ đọc hơn.
*Đa phần sẽ khiến vòng lặp phức tạp hơn.

Nên dùng cấu trúc while(true) cho các vòng lặp vô hạn.
while (true) {
  :
}

for (;;) {  // NO!
  :
}

while (1) { // NO!
  :
}
Điều kiện kiểm tra là 1 sẽ không bao hàm đủ ý nghĩa, bên cạnh đó, dạng for(;;) lại chẳng dễ đọc tí nào, và cả 2 kiểu cấu trúc này đều không thể hiện rằng đó là một vòng lặp vô hạn.

4. Về cách đặt điều kiện.

Phải tránh các khối điều kiện phức tạp. Sử dụng biến bool để chia nhỏ điều kiện ra nếu nó quá rườm rà.
bool isFinished = (elementNo < 0) || (elementNo > maxElement);
bool isRepeatedEntry = elementNo == lastElement;
if (isFinished || isRepeatedEntry) {
  :
}

// NOT:
if ((elementNo < 0) || (elementNo > maxElement)||
     elementNo == lastElement) {
  :
}
Nhờ việc phân tích điều kiện ra nhiều biến boolean, các điều kiện sẽ trở nên dễ đọc, dễ bảo trì và sửa lỗi.

Các điều kiện kiểm tra sự tồn tại của một đối tượng nào đó nên được đặt vào if và đặt biệt lệ tương ứng vào else.
bool isOk = readFile (fileName);
if (isOk) {
  :
}
else {
  :
}
Đảm bảo rằng các biệt lệ có thể xảy ra sẽ không gây khó khắn cho việc thực hiện chương trình. Quy tắc này khá quan trọng trong việc khiến mã nguồn dễ đọc hơn và gia tăng hiệu suất chương trình.

Nhận xét

Bài đăng phổ biến từ blog này

Vẽ UML trong Visual Studio 2015

I. Giới thiệu       Hiện nay có rất nhiều công cụ để mô hình hóa trong đó có UML với các công cụ như: PowerDesigner, Visio, Draw.io,... Nhưng các công cụ này đều phải có bản quyền và hơn hết phải cài đặt thêm khá nặng máy. Ít ai biết đến bộ công cụ vẽ UML có sẵn trong Visual Studio. Vì dân IT hầu như ai cũng có sử dụng nó và hiện giờ đã có bản Visual Studio Community miễn phí cho tất cả các lập trình viên. Vậy chúng ta sẽ tìm hiểu cách vẽ UML trong Visual Studio nhé.

SmartGIT

Hướng dẫn cài đặt GIT Nói chung  Team Foundation Server  trong Visual Studio khá tốt và có nhiều tính năng hay. Nhưng lại giới hạn người dùng. Nếu team bạn nhiều hơn 5 người thì có thể xài GIT vậy. Được cái tất cả là Free.