STDIO
Tìm kiếm gần đây
    • Nội dung
    • QR Code
    • 0
    • 0
    • Sao chép

    Tối Ưu Hóa - Coding Convention

    Hướng dẫn sử dụng và xây dựng Coding Convention.
    02/06/2014
    26/09/2020
    7 phút đọc
    Tối Ưu Hóa - Coding Convention

    Coding Convention là chuẩn mực và quy tắc để code, các lập trình viên trong 1 dự án phải tuân theo - tương tự như quy tắc soạn văn bản cần có quy tắc canh lề, quy tắc chữ to nhỏ, đậm nhạt.

    Xa hơn nữa, các dự án lớn đòi hỏi đồng bộ giữa các thành viên với nhau là cần thiết, các chuẩn mực sẽ giúp cho các lập trình viên cùng có cách hiểu, cùng nhìn về một hướng, tối ưu thời gian đọc code.

    Coding Convention trong bài viết dành cho một số ngôn ngữ họ C như: C, C++, C#, Java, JavaScript.

    Các vấn đề khi khai báo biến

    Cách đặt tên biến phải mang nghĩa nhất định

    Xét ví dụ:

    ConvergedSins* ConvergedSins::createConvergedSins(Color a, int b)
    {
    	ConvergedSins* ret = new ConvergedSins();
    
    	if(ret && ret->init(a, b))
    	{
    		ret->autorelease();
    		return ret;
    	}
    
    	SAFE_DEL(ret);
    	return NULL;
    }

    2 biến ab được truyền vào hàm createConvergedSins không mang ý nghĩa. Có thể làm tốt hơn nếu thay a bởi colorb bởi level do trong ngữ cảnh này ab mang 2 ý nghĩa đó.

    ConvergedSins* ConvergedSins::createConvergedSins(Color color, int level)
    {
    	ConvergedSins* ret = new ConvergedSins();
    
    	if(ret && ret->init(color, level))
    	{
    		ret->autorelease();
    		return ret;
    	}
    
    	SAFE_DEL(ret);
    	return NULL;
    }

    Sau khi thay đổi đoạn code như trên, khi bảo trì sẽ tránh mất thời gian tra cứu lại ý nghĩa của biến.

    Tuy nhiên, không nhất thiết phải lúc nào cũng tuân theo quy tắc, nếu như 1 điều quá hiển nhiên:

    int Add(int a, int b)
    {
    	return a + b;
    }

    Bảng liệt kê một số loại biến và cách đặt tên

    Loại biến Cách đặt tên biến Ví dụ
    Biến cục bộ
    (local)
    Chữ thường toàn bộ cho các ký tự, ngăn cách mỗi từ trong biến bởi dấu gạch dưới. int age_of_person
    char* name
    Biến toàn cục
    (global)
    Chữ thường toàn bộ cho các ký tự, tiền tố g_, ngăn cách mỗi từ trong biến bởi gạch dưới. int g_age_of_person
    char* g_name
    Biến dạng static Chữ thường toàn bộ cho các ký tự, tiền tố s_, ngăn cách mỗi từ trong biến bởi gạch dưới. int s_age_of_person
    char* s_name
    Biến dạng hằng
    (constant)
    Viết hoa toàn bộ các ký tự, tiền tố C_ hoặc k_, ngăn cách mỗi từ trong biến bởi gạch dưới. const int C_AGE_OF_PERSON
    const char* C_NAME
    Các trường
    của struct và class
    Chữ thường toàn bộ cho các ký tự, tiền tố m_, ngăn cách mỗi từ trong trường này bởi gạch dưới. int m_age_of_person
    char* m_name
    Các trường static của struct và class Chữ thường toàn bộ cho các ký tự, tiền tố s_, ngăn cách các từ trong trường bởi gạch dưới. int s_age_of_person
    char* s_name

    Các quy tắc khác

    • Biến truyền vào hàm sẽ viết thường toàn bộ các ký tự, ngăn cách các từ trong biến bởi dấu gạch dưới.
    • Cách khai báo một struct cần viết hoa các ký tự đầu của mỗi từ tên struct và bắt đầu với tiền tố S, ví dụ struct STesla.
    • Cách khai báo một class cần viết hoa các ký tự đầu của mỗi từ trong tên class và bắt đầu với tiền tố C, ví dụ class CMonster.

    Các vấn đề khi khai báo hàm

    Với Java, bản thân Java Coding Convention rất chặt chẽ, trong các khai báo hàm của Java sử dụng cách viết thường ký tự đầu tiên của tên hàm: createBasicSinsWithData(), playEffectDestroySins().

    Với Coding Convention có thể học hỏi từ Java Coding Convention hoặc viết hoa chữ cái đầu tiên của các từ trong tên hàm, ta có ví dụ cho cách thứ 2 này: CreateBasicSinsWithData(), PlayEffectDestroySins().

    Cách đặt tên hàm phải mang nghĩa nhất định

    Việc đặt tên hàm mang ý nghĩa cũng như đặt tên biến có ý nghĩa như đã trình bày ở trên, đặt tên hàm hay biến càng mang đầy đủ ý nghĩa sẽ càng tốt.

    Mức độ 1: xét ví dụ với hàm có ý nghĩa thấp sau, hàm create(...)

    LightSins* LightSins::create(eBasicSinsColor color)
    {
    	LightSins* ret = new LightSins();
    
    	if(ret && ret->init(color))
    	{
    		ret->autorelease();
    		return ret;
    	}
    
    	SAFE_DEL(ret);
    	return NULL;
    }

    Mức độ 2: gia tăng ý nghĩa hơn cho hàm create(...), đặt lại tên hàm với nhiều từ hơn, sửa create(...) thành createLightSins(...)

    LightSins* LightSins::createLightSins(eBasicSinsColor color)
    {
    	LightSins* ret = new LightSins();
    
    	if(ret && ret->init(color))
    	{
    		ret->autorelease();
    		return ret;
    	}
    
    	SAFE_DEL(ret);
    	return NULL;
    }

    Mức độ 3: làm rõ nghĩa hơn nữa, điều chỉnh thành createLightSinsWithColor(...)

    LightSins* LightSins::createLightSinsWithColor(eBasicSinsColor color)
    {
    	LightSins* ret = new LightSins();
    
    	if(ret && ret->init(color))
    	{
    		ret->autorelease();
    		return ret;
    	}
    
    	SAFE_DEL(ret);
    	return NULL;
    }

    Khi sử dụng hàm trên sẽ tránh mất thời gian hơn trong bảo trì xem cần truyền tham số thuộc loại nào vào hàm, đôi lúc không cần xem phần hiện thực cũng có thể đoán được ý nghĩa của hàm.

    Các vấn đề khác về soạn thảo văn bản

    Level của 1 khối code

    Việc đặt level đúng của 1 khối code là rất quan trọng, giúp xác định nhanh hơn "tầm vực" của 1 dòng code và xác định vấn đề nhanh hơn.

    Xét ví dụ sau, code không được trình bày đúng level

    if(m_fAdd1ScoreTimer == 0.0f)
    {
    	if(m_iScorePool > 0)
    	{
    	int addScore = (int)(m_iScorePool * 0.2f);
    	if(addScore < 1) 
    	addScore = 1;
    
    m_iScorePool -= addScore;
    m_iCurrentScore += addScore;
    m_fAdd1ScoreTimer = DELAY_ADD_1_SCORE;
    
    		if(m_iScorePool == 0)
    		{
    m_pScoreLabel->runAction(
    CCSequence::create(
    CCScaleTo::create(0.05f, 2.0f*m_ScaleFactorScore),
    CCScaleTo::create(0.1f, 1.0f*m_ScaleFactorScore), NULL
    ));
    	}
    	}
    }

    Với code như trên, có thể nhầm lẫn m_iCurrentScore += addScore; nằm cùng cấp với dòng if(m_fAdd1ScoreTimer == 0.0f), tức là nó không nằm trong if.

    Thay vì vậy, đưa nó vào đúng level của nó:

    if(m_fAdd1ScoreTimer == 0.0f)
    {
    	if(m_iScorePool > 0)
    	{
    		int addScore = (int)(m_iScorePool * 0.2f);
    		if(addScore < 1) 
    			addScore = 1;
    
    		m_iScorePool -= addScore;
    		m_iCurrentScore += addScore;
    		m_fAdd1ScoreTimer = DELAY_ADD_1_SCORE;
    
    		if(m_iScorePool == 0)
    		{
    			m_pScoreLabel->runAction(CCSequence::create(
    				CCScaleTo::create(0.05f, 2.0f*m_scaleFactorPts),
    				CCScaleTo::create(0.1f, 1.0f*m_scaleFactorPts),
    				NULL
    			));
    		}
    	}
    }

    Đặt dấu (chấm, phẩy, hai chấm, chấm phẩy, hỏi, chấm than)

    Theo phương pháp đặt dấu trong văn bản thì "dấu câu" trong code cũng có vài nét tương đồng. Nguyên tắc là dấu sẽ nằm ngay phía sau ký tự cuối và sau đó là đến khoảng trắng rồi mới đến ký tự kế tiếp.

    Ví dụ đặt dấu sai, xem xét khảo sát tại dấu phẩy , và dấu chấm .

    • Twinkle ,twinkle ,little star ,how I wonder what you are. (sai chỗ dấu phẩy, đúng chỗ dấu chấm)
    • Twinkle,twinkle,little star,how I wonder what you are . (sai chỗ dấu phẩy, sai chỗ dấu chấm)
    • Twinkle, twinkle, little star, how I wonder what you are . (đúng chỗ dấu phẩy, sai chỗ dấu chấm)

    Cách đặt dấu đúng dựa theo nguyên tắc đã đề cập phía trên:

    Twinkle, twinkle, little star, how I wonder what you are.

    Từ cách trình bày văn bản như trên, tận dụng vào việc trình bày code, xét ví dụ code về việc đặt dấu sau

    playActionFollowDelete(1,this,callfunc_selector(SinsDestroy::playDone))  ;

    Các dấu phẩy hay chấm phẩy như trên đặt không tốt, có thể trình bày lại như sau

    playActionFollowDelete(1, this, callfunc_selector(SinsDestroy::playDone));

    Cách dòng trong code

    Khảo sát đoạn code sau, đây là đoạn code đã cách dòng tốt

    void CLoadingData::releaseAllResource()
    {
    	m_iNumBackgroundAudios = 0;
    
    	// RELEASE SPRITE
    	for(u8 i = 0; i < m_tSpritePacks.size(); i++)
    	{
    		GetSpriteManager()->unloadSprite(m_tSpritePacks.at(i));
    	}
    	m_tSpritePacks.clear();
    	
    	// RELEASE AFX
    	for(u8 i = 0; i < m_tAudioPacks.size(); i++)
    	{
    		unloadEffect(m_tAudioPacks.at(i));			
    	}
    	m_tAudioPacks.clear();
    }

    Xem xét đoạn từ comment // RELEASE SPRITE và tới đoạn // RELEASE AFX, giữa 2 đoạn đó cách nhau bởi 1 dòng trống (blank) (dòng 11). Ý nghĩa của nó nhằm ngăn cách 2 khối code có 2 chức năng khác nhau, như vậy khi bảo trì có thể nhanh chóng xác định được đoạn code nào làm việc gì thay vì để liên tục từ trên xuống như đoạn code bên dưới.

    void CLoadingData::releaseAllResource()
    {
    	m_iNumBackgroundAudios = 0;
    	// RELEASE SPRITE
    	for(u8 i = 0; i < m_tSpritePacks.size(); i++)
    	{
    		GetSpriteManager()->unloadSprite(m_tSpritePacks.at(i));
    	}
    	m_tSpritePacks.clear();
    	// RELEASE AFX
    	for(u8 i = 0; i < m_tAudioPacks.size(); i++)
    	{
    		unloadEffect(m_tAudioPacks.at(i));			
    	}
    	m_tAudioPacks.clear();
    }

    Từ đây, bạn có thể tự thiết kế nên chuẩn mực chung của nhóm làm việc, hoặc học cách tuân theo chuẩn mực cho các dự án sau này.

    Bài chung series

    0
    Modern C++

    Modern C++

    STDIO Training - Đào Tạo Lập Trình C++.

    Khi bạn nhấn vào liên kết sản phẩm do STDIO đề xuất và mua hàng, STDIO có thể nhận được hoa hồng. Điều này hỗ trợ STDIO tạo thêm nhiều nội dung hữu ích.. Tìm hiểu thêm.

    Đề xuất

    Tối Ưu Hóa - Tối Ưu Hóa Code C++
    Các mẹo tối ưu hóa code làm tăng hiệu suất trong lập trình C++.
    SEO - Tối Ưu Đường Dẫn Thân Thiện Người Dùng
    Tối ưu hóa đường dẫn mang lại trải nghiệm thân thiện với người dùng và ...

    Khám phá

    Tối Ưu Hóa - Quản Lý Bộ Nhớ Nhỏ và Phân Mảnh
    Hướng dẫn tạo hệ thống tự cấp phát và thu hồi bộ nhớ dành cho bộ nhớ nhỏ ...
    Tối Ưu Mã C/C++ Cho Người Mới Bắt Đầu
    Giới thiệu các phương pháp tối ưu hoá mã nguồn C/C++.
    28/08/2015
    Đồ Hoạ trên Cửa Sổ Dòng Lệnh - Console Graphics
    Các thư viện đồ họa đã phát triển rất mạnh mẽ, tận dụng gần như tối đa ...
    02/10/2014
    Đồng Bộ Hóa Việc Đặt Tên - Naming Convention
    Giới thiệu Naming Convention - quy tắc đặt tên trong lập trình
    24/09/2014
    Sự Thật về Web Design và Graphic Design
    Web Design thường được hiểu nghĩa tiếng Việt đó là thiết kế web, Graphic ...
    Performance của switch-case so với if-else
    So sánh performance giữa switch-case so với if-else và các kĩ thuật tối ...
    Bí Mật Của SEO - Phần 3
    Tìm hiểu việc tối ưu hóa trải nghiệm người dùng từ hình ảnh, nội dung ...
    Tối Ưu Xử Lý Chuỗi với StringBuilder - Phần 1
    Bài viết giới thiệu và phân tích hiệu năng khi xử lí chuỗi với đối tượng ...
    03/02/2018
    STDIO
    Trang chính
    Công ty TNHH STDIO

    30, Trịnh Đình Thảo, Hòa Thạnh, Tân Phú, Hồ Chí Minh
    +84 28.36205514 - +84 942.111912
    developer@stdio.vn

    383/1 Quang Trung, Phường 10, Quận Gò Vấp, Hồ Chí Minh
    Số giấy phép ĐKKD: 0311563559 do sở Kế hoạch và Đầu Tư TPHCM cấp ngày 23/02/2012

    ©STDIO, 2013 - 2020