SlideShare a Scribd company logo
Code tốt có nghĩa là ???
Matsui Nobuyuki
Code tốt có nghĩa là:
• (Đặt tại môi trường doanh nghiệp)Code tốt có nghĩa là
「dễ đọc, dễ hiểu và dễ sửa chữa」
• Tuy nhiên không đồng nghĩa phải giúp giảm lượng truyền tải I/O
hay lượng sử dụng bộ nhớ
• Cũng không phải giúp hệ thống hoạt động nhanh hơn
• Tuy nhiên với các phần mềm game hay hoạt động tại môi trường đặc
thù thì đặc điểm trên cũng được tính vào để đánh giá code tốt
• Không phải code sử dụng các thủ pháp trick để giúp viết ngắn mà
hệ thống vẫn hoạt động
• Tại các cuộc thi programming, đặc điểm trên được tính là code tốt
Tại sao viết được code “tốt” lại cần
thiết ?
• Tại doanh nghiệp, việc phát triển thường xuyên được làm
theo nhóm.
• Cho dù là một mình phát triển đi chăng nữa, bản thân ở
hiện tại và sau 3 tháng là 2 trình độ hoàn toàn khác nhau.
• Ở môi trường doanh nghiệp, code đại đa số là “được đọc”
hơn là “được viết"
• Do ở môi trường doanh nghiệp rất hay có việc về mở rộng chức
năng, cho nên phải đọc tất cả những đoạn code “có vẻ" liên quan
đến chỗ đó.
• Khi xảy ra lỗi, cần phải đọc thật nhanh code liên quan đến đoạn
gây lỗi
• Cho nên điều quan trọng không phải là viết ra những
đoạn code “có thể chạy được” mà là “dễ đọc và dễ hiểu"
Phương châm cơ bản để viết được
code tốt
• Cách viết để dễ đọc
• Đơn giản hoá logic
• Cấu trúc lại code(refactoring)thường xuyên
• Viết để có thể test được
Cách viết để dễ đọc
• Sử dụng tên hợp lý
• Chọn từ rõ nghĩa thể hiện đúng điều mà variable hay function
muốn làm
• Những tên function như get hay tên variable kiểu result không thể hiện
được bên trong nó có gì
• Hãy thêm vào những từ rõ nghĩa, cung cấp thông tin
• Ví dụ với biến chứa thông tin filesize => có thể đặt tên là uploaded_file_mb
• Tránh dùng những từ chung chung như tmp hay buf
• Tuy nhiên với trường hợp tên biến chỉ bó hẹp trong phạm vi một màn
hình thì vẫn có thể sử dụng không sao cả.
• Do phạm vi của các biến loop cũng bị giới hạn cho nên kiểu tên như “i”
hay “j" cũng ok
• Với các trường hợp không thể chọn được tên rõ ràng và muốn đặt
tên dài, cũng có nghĩa là chưa phân chia ra được các module hợp
lý
• Ví dụ nếu muốn đặt tên là canvas_max_px, tại sao không tách ra class
Canvas chứa biến instance tên là max_px?
Cách viết để dễ đọc
• Tuân theo cách đặt tên và coding thích hợp
• Hãy cố gắng tuân theo phong cách đã trở thành tiêu chuẩn đối với
từng loại ngôn ngữ, hạn chế tạo ra các quy luật mới mình nghĩ ra
• Ví dụ với Python:
• PEP8
• http://legacy.python.org/dev/peps/pep-0008/
• Google Python Style Guide
• http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
• Indent và xuống dòng đều có ý nghĩa của nó cho nên cũng phải
theo quy luật
• Với Python, mặc dù indent không có liên quan trực tiếp tới control
structure, vẫn phải ý thức khi sử dụng
Cách viết để dễ đọc
• Chú trọng tính thống nhất cho vẻ ngoài
• Ví dụ
• Trường hợp có nhiều function lấy chung một variable làm argument,
cho chung một thứ tự
• Nếu định nghĩa variable mang ý nghĩa giống nhau tại nhiều module, cho
tên giống nhau
• Làm sao để người đọc không bị rơi tình trạng「Quái, cái hồi trước
có phải thế này không nhỉ?」
Cách viết để dễ đọc
• Hạn chế việc tự viết
• Sử dụng tối đa các chức năng thông dụng hay đã được đóng
library sẵn với mỗi ngôn ngữ
• Các xử lý tìm kiếm hay sắp xếp hầu hết đều được cung cấp code chạy
rất nhanh và an toàn từ các dòng xử lý ngôn ngữ
• Những chức năng mà ai cũng muốn như xử lý chuỗi string.. hầu hết
đều được cung cấp sẵn. Với Java là apache commons, Ruby thì là
active support
• Nên đọc qua không chỉ về specs ngôn ngữ mình cần sử dụng, mà
cả về specs những library chính cũng như function được cung cấp.
Cách viết để dễ đọc
• Thêm comment thích hợp
• Không ghi những comment vô nghĩa kiểu như「đây là quy định
của dự án」
• Comment về tư tưởng thiết kế và ý đồ tại sao implement method
và class đó
• Cái này vốn được tạo ra để làm gì?
• Tại sao lại chọn logic này?Có cách thức nào khác không?
• Comment những chỗ mình cảm thấy mơ hồ
• Ví dụ
• Với logic này cũng có thể chạy được tuy nhiên lượng cần tính toán với data
sẽ là O(n^2)
• Do là destructive method、internal data sẽ bị thay đổi sau khi được gọi dù chỉ
1 lần
• Không comment những đoạn code nhìn cái là hiểu ý nghĩa
• Những đoạn code phải comment về thứ tự xử lý để hiểu => bị coi là
code không tốt
Đơn giản hoá logic
• Phân nhánh điều kiện
• Đưa những điều kiện quan trọng và đơn giản lên trước
• Sử dụng luật De
Morgan( https://vi.wikipedia.org/wiki/Lu%E1%BA%ADt_De_Morgan
) hay Bìa
Karnaugh( https://vi.wikipedia.org/wiki/B%C3%ACa_Karnaugh ) để
đơn giản hoá điều kiện đi
• Luật De Morgan
• not (A or B) == (not A) and (not B)
• not (A and B) == (not A) or (not B)
Đơn giản hoá Logic
• Sử dụng hiệu quả Bìa Karnaugh(by @kawasima)
• Ví dụ trường hợp có điều kiện như dưới đây
User profile (mục đang được lấy)
Số điện thoại mail address địa chỉ cách liên lạc
mail
mail
Điện thoại
Mail Version
Mail Version
Không có
Đơn giản hoá Logic
• Sử dụng hiệu quả Bìa Karnaugh(by @kawasima)
• Nếu implement thông thường sẽ là:
Đơn giản hoá logic
• Sử dụng hiệu quả Bìa Karnaugh(by @kawasima)
• Khi viết thử bằng Bìa Karnaugh sẽ được như sau:
Điện thoại: mail
Địa chỉ
Nếu viết bằng bìa Karnaugh sẽ rất dễ hiểu
Tóm lại
Nếu mail address đã được đăng ký => email, nếu chưa được đăng ký nhưng địa
chỉ đã được đăng ký => DM, cả 2 cùng chưa đăng ký => điện thoại
Đơn giản hoá logic
• Sử dụng hiệu quả Bìa Karnaugh(by @kawasima)
• Có thể implement bằng điều kiện đơn giản hơn:
Đơn giản hoá logic
• Cố gắng cho method trả giá trị thật nhanh
• Thay vì phải nhớ mãi các điều kiện để phân định, khi xảy ra trường
hợp bất thường => cố gắng đưa ra ngoài function hiện tại nhanh sẽ
giúp code dễ hiểu hơn.
def construct_msg(num_pageview):
msg = ""
if (isValid(num_pageview)):
foo()
…
bar()
…
msg = buz()
else:
msg = "invalid"
return msg
def construct_msg(num_pageview):
if (not isValid(num_pageview)):
return "invalid"
foo()
…
bar()
…
return buz()
Đơn giản hoá logic
• Không viết những đoạn code trick
• Dù specs của ngôn ngữ đang dùng có support đi chăng nữa,
không viết những kiểu code trick
Không viết kiểu để tự mãn với bản thân
xx = 1
yy = 2
def f(x,y):
return x + y + xx + yy
globals().update({"xx":1,"yy":2,"f":lambda x,y:x+y+xx+yy})
=
Đơn giản hoá logic
•Không viết những đoạn code trick
•Dù có nói là được phép với specs của ngôn ngữ hiện tại đi chăng
nữa, không viết những kiểu code trick
Không viết kiểu để tự mãn với bản thân
def check(x):
if x%2 == 0:
return even()
else:
return odd()
def check(x): return odd() if x%2 else even()
=
def check(x): return (x%2 and [odd()] or [even()])[0]
=
def check(x): return [even, odd][x%2]()
=
Đơn giản hoá logic
• Những phần implement có tính chất giúp giảm thiểu bộ nhớ và nâng cao tính
năng để đến sau cùng
• Trong nguyên lý Pareto( https://vi.wikipedia.org/wiki/Nguy%C3%AAn_l%C3%BD_Pareto ) đã có
ghi: xét trên tổng thể, chỉ có 1 phần nhỏ các đoạn code gây ra việc tốn bộ nhớ và làm chức năng
kém đi
• Đầu tiên hãy chú ý tới viết code sao cho dễ hiểu
• Kiểm duyện lại tính năng trên toàn bộ hệ thống, sau đó lọc ra các điểm chính gây ảnh hưởng
tới bộ nhớ và làm giảm tính năng để tập trung sửa chữa
• Những chỗ cần thiết tính năng phải thật tốt, có thể xem xét viết 1 vài chỗ
bằng C cũng rất tốt
• Tuning cho SQL là cách hiệu quả nhất để nâng cao tính năng
• Tuy nhiên với những nest loop hay algorithm tìm kiếm O(n2)..
không có sẵn thì cần xem xét kỹ ngay từ đầu để tránh những đoạn
code hiệu suất thấp
※Nguyên lý Pareto
「Hầu hết các giá trị đều chỉ được sinh ra bởi 1 số thành phần
cấu trúc nên toàn thể mà thôi」
「Nguyên lý 8:2」
Tái cấu trúc code(Refactoring)
• Những xử lý không tóm gọn trong một màn hình cần suy
nghĩ xem có thể phân chia module được không
• Xử lý không liên quan trực tiếp tới việc đoạn code muốn thực hiện
(mục đích có thể tóm trong 1 dòng comment), cần cắt ra module
khác
• Nếu đặt tên một cách hợp lý, thậm chí không cần nhìn code của
module được cắt ra vẫn có thể hiểu được đại khái nội dung xử lý
của module đó => code cũ đã trở nên dễ hiểu hơn
• Vậy phải phân chia bằng cách nào?
Tái cấu trúc code(Refactoring
• the Open-Closed Principle(OCP)(định luật đóng-mở)
• 「Các element cấu trúc của software cần được mở với support mở
rộng chức năng, nhưng đóng với việc sửa chữa」
• Những module được ý thức theo luật OCP sẽ không làm ảnh
hưởng tới các module khác khi bị sửa chữa
=Nguyên lý của thiết kế hướng đối tượng
• Tầm quan trọng của specs API
• Nếu specs API công bố ra bên ngoài(ứng với input của method sẽ cho
output là gì, hay những “tác dụng phụ” xảy ra là gì)không thay đổi =>
Code phía trong bị thay đổi đi chăng nữa cũng không ai quan tâm
Tái cấu trúc code(Refactoring)
• Tác dụng phụ của function
• (ý nghĩa mặt toán học)function = thứ chuyển từ input sang
ouput
• Những thứ nằm ngoài việc chuyển input sang ouput, làm ảnh hưởng đến
môi trường ngoài function
=Tác dụng phụ
• Input/Output của network và file, input/output của màn hình, input/output
của database.. đều là tác dụng phụ
• input/output tới các variable ở phía ngoài function cũng là tác dụng phụ
• Function không có tác dụng phụ thì dù được gọi trong bất cứ trường hợp
nào cũng đều cho một kết quả
• Trở thành module dễ test và stable
• Ngôn ngữ functional programming về cơ bản tạo ra hệ thống dựa trên các
function không có tác dụng phụ => bằng việc hạn chế tối đa những tác
dụng phụ để có một hệ thống vững chắc.
• Tuy nhiên, một hệ thống hoàn toàn không có tác dụng phụ cũng không
có ý nghĩa đặc biệt gì cả
Tái cấu trúc code(Refactoring)
• Tận dụng ưu điểm của functional programming
• Scope của biến càng nhỏ càng tốt
• Tránh dùng global variable
• Chỉ set giá trị 1 lần(không sử dụng lại biến giống nhau và viết lại)
• Biến được giới hạn trong function nhỏ (ví dụ là biến loop) có thể viết lại cũng không sao.
• Nếu tạo ra function mà ngầm viết lại những biến phụ thuộc sẽ dẫn tới khả năng sinh bug rất
khó chữa ở những nơi mình không ngờ tới
• Cũng cần phải chú ý tới việc viết lại nội dung biến của function như list.append()
• Ví dụ: Nếu có ký hiệu list intension, list cũ sẽ vẫn như thế và list mới sẽ được
tạo
>>> x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> y = [i * 2 for i in x if i%2 == 0]
>>> y
[4, 8, 12, 16, 20]
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Tái cấu trúc code(Refactoring)
•Tận dụng ưu điểm của functional programming
• Không viết lại argument gửi tới function trong function đó
• Argument của function trong Java và Python được đưa để tham chiếu
• => Về mặt specs, có thể viết lại được nội dung argument object tuy
nhiên về cơ bản không được làm.
• Output trả về từ function tất cả phải dưới dạng return value
• Khi xảy ra exception, không phải return value mà phải raise exception
• Rút cuộc・・・
• Việc phân chia rõ ràng「phần được coi như là tác dụng
phụ(external input/output.. )」, 「phần thực hiện xử lý phụ thuộc
vào internal data của class」và「function không có tác dụng phụ」,
rồi sau đó localize phạm vi mà code đó ảnh hưởng là rất quan
trọng.
Tái cấu trúc code(Refactoring)
• the Single Responsibility Principle(SRP)(định luật
nhiệm vụ đơn)
• Nhiệm vụ của class chỉ có một
• Bắt buộc phải viết được nhiệm vụ của class chỉ bằng 1 dòng comment
dạng「Class này thực hiện nhiệm vụ “abc"」
• Lý do thay đổi implement của class chỉ có thể vì cần sửa chữa hay
mở rộng nhiệm vụ “abc" đó
• Khi sửa chữa program bằng 1 lý do ngoài việc「sửa chữa cho nhiệm
vụ “abc" ấy」mà code trong class nhiệm vụ “abc" phải bị thay đổi
• => việc phân chia class đã bị nhầm lẫn
Tái cấu trúc code(Refactoring)
• Để phân biệt class hợp lý cần sử dụng design pattern
• Tổng hợp best practice để phân chia class thật chuẩn
• Truyền thống nhất:GoF(Gang of Four)design pattern
( https://en.wikipedia.org/wiki/Design_Patterns )
• Ngoài GoF, có rất nhiều loại design pattern đã được đề ra.
• Tuy nhiên, nếu sử dụng pattern chỉ vì có cảm giác “muốn sử dụng
pattern" thì sẽ lợi bất cập hại
Tái cấu trúc code(Refactoring)
• Khi đánh giá độ hợp lý của code, cần sử dụng metrics
• Độ liên kết và độ kết hợp
• Tiêu chuẩn kiểm tra OCP và SRP của module
• Hoàn hảo nhất là độ liên kết cao và độ kết hợp thấp
• Có thể đưa ra con số cụ thể bằng code metric tool
• Những con số cụ thể không có ý nghĩa lắm, điều quan trọng là dùng nó để
nhìn ra thiên hướng chung
• Độ phức tạp tuần hoàn của McCabe
• Tiêu chuẩn kiểm tra độ phức tạp của code(mức độ của loop và phân
nhánh)
• Thông thường dưới 10 được coi là tốt
• Quá 30 sẽ bị coi là module có cấu trúc thất bại, quá 50 sẽ là không thể test,
quá 75 thì dù có sửa ít thế nào vẫn có thể sinh bug
Viết để có thể test được
• Những function không có tác dụng phụ sẽ có thể test dễ
dàng
• Càng đơn giản, càng bao phủ nhiều càng tốt
• Tuy nhiên không phải test mù quáng bằng rất nhiều giá trị, hãy suy
nghĩ lý do rõ ràng tại sao phải test bằng input đó
• Giá trị giới hạn
• Max và min của giá trị mong đợi cộng hoặc trừ với 1..
• Giá trị đặc biệt
• Với trường hợp số thì là 0
• Với trường hợp chữ(utf-8), bit pattern mà có chữ là 1 byte(US-ASCII),
chữ là 2 byte (Greek alphabet), chữ là 3 byte(kanji thông thường và số
tròn..), chữ có trên 4 byte(kanji tiêu chuẩn tầng 3, 4 của JIS X 0213)..
• Với trường hợp chữ(Shift-JIS và CP932), từ「表」và「ー」.. có byte thứ 2
là character 0x5c(backslash)và character bị hỏng do chuyển từ CP932
sang UTF-8(~)..
Viết để có thể test được
• Xử lý có tác dụng phụ
• Sử dụng stub và driver để viết test
• Sử dụng hợp lý chức năng được test framework cung cấp
• Bằng việc test liên tục, có tính tiếp nối với program đã
được phân chia module hợp lý và ý thức để test được
• => dù có develop theo nhóm đi chăng nữa vẫn có thể yên
tâm và mở rộng chức năng.

More Related Content

Viewers also liked

Visual Media Portfolio
Visual Media PortfolioVisual Media Portfolio
Visual Media Portfolio
Dee Wightman
 
Casas muertas
Casas muertasCasas muertas
Casas muertas
wartror
 
Customisation Options in Linnworks.net
Customisation Options in Linnworks.netCustomisation Options in Linnworks.net
Customisation Options in Linnworks.net
Linnworks
 
Tecnica de conexiones de Madera
Tecnica de conexiones de MaderaTecnica de conexiones de Madera
Tecnica de conexiones de Madera
JOHNNY JARA RAMOS
 
Feza Lakho Projects Company Profile - Copy - Copy
Feza Lakho Projects Company Profile - Copy - CopyFeza Lakho Projects Company Profile - Copy - Copy
Feza Lakho Projects Company Profile - Copy - CopyMpilonde Mgudlwa
 
Ronak Shah resume
Ronak Shah resumeRonak Shah resume
Ronak Shah resumeRonak Shah
 
jezriah_j__krubeck_proposal_AQR
jezriah_j__krubeck_proposal_AQRjezriah_j__krubeck_proposal_AQR
jezriah_j__krubeck_proposal_AQRJez Krubeck
 
Linnworks Data Exchange Masterclass
Linnworks Data Exchange MasterclassLinnworks Data Exchange Masterclass
Linnworks Data Exchange Masterclass
Linnworks
 
Evaluating a marine protected area in a developing country; Mafia Island Mari...
Evaluating a marine protected area in a developing country; Mafia Island Mari...Evaluating a marine protected area in a developing country; Mafia Island Mari...
Evaluating a marine protected area in a developing country; Mafia Island Mari...Marcus C
 
Social media
Social mediaSocial media
Social media
Abhisek Gupta
 
Eirik karlsen
Eirik karlsenEirik karlsen
Eirik karlsen
eirikak
 
Data preparation, training and validation using SystemML by Faraz Makari Mans...
Data preparation, training and validation using SystemML by Faraz Makari Mans...Data preparation, training and validation using SystemML by Faraz Makari Mans...
Data preparation, training and validation using SystemML by Faraz Makari Mans...
Arvind Surve
 
FY 2015 OSHA and Houston Update
FY 2015 OSHA and Houston UpdateFY 2015 OSHA and Houston Update
FY 2015 OSHA and Houston Update
James Shelton
 

Viewers also liked (13)

Visual Media Portfolio
Visual Media PortfolioVisual Media Portfolio
Visual Media Portfolio
 
Casas muertas
Casas muertasCasas muertas
Casas muertas
 
Customisation Options in Linnworks.net
Customisation Options in Linnworks.netCustomisation Options in Linnworks.net
Customisation Options in Linnworks.net
 
Tecnica de conexiones de Madera
Tecnica de conexiones de MaderaTecnica de conexiones de Madera
Tecnica de conexiones de Madera
 
Feza Lakho Projects Company Profile - Copy - Copy
Feza Lakho Projects Company Profile - Copy - CopyFeza Lakho Projects Company Profile - Copy - Copy
Feza Lakho Projects Company Profile - Copy - Copy
 
Ronak Shah resume
Ronak Shah resumeRonak Shah resume
Ronak Shah resume
 
jezriah_j__krubeck_proposal_AQR
jezriah_j__krubeck_proposal_AQRjezriah_j__krubeck_proposal_AQR
jezriah_j__krubeck_proposal_AQR
 
Linnworks Data Exchange Masterclass
Linnworks Data Exchange MasterclassLinnworks Data Exchange Masterclass
Linnworks Data Exchange Masterclass
 
Evaluating a marine protected area in a developing country; Mafia Island Mari...
Evaluating a marine protected area in a developing country; Mafia Island Mari...Evaluating a marine protected area in a developing country; Mafia Island Mari...
Evaluating a marine protected area in a developing country; Mafia Island Mari...
 
Social media
Social mediaSocial media
Social media
 
Eirik karlsen
Eirik karlsenEirik karlsen
Eirik karlsen
 
Data preparation, training and validation using SystemML by Faraz Makari Mans...
Data preparation, training and validation using SystemML by Faraz Makari Mans...Data preparation, training and validation using SystemML by Faraz Makari Mans...
Data preparation, training and validation using SystemML by Faraz Makari Mans...
 
FY 2015 OSHA and Houston Update
FY 2015 OSHA and Houston UpdateFY 2015 OSHA and Houston Update
FY 2015 OSHA and Houston Update
 

Similar to How to write good code

Programming
ProgrammingProgramming
Programming
Nguyên Thành Võ
 
Seminar clean code
Seminar clean codeSeminar clean code
Seminar clean code
Nguyen Thieu
 
Clean code
Clean codeClean code
Clean code
Nam Vo
 
Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++
Thang DV
 
C++ bưu chính viễn thông
C++ bưu chính viễn thôngC++ bưu chính viễn thông
C++ bưu chính viễn thông
Tiên Lý Rau Rút
 
Bai giang c++
Bai giang c++Bai giang c++
Bai giang c++
Nhân Tâm
 
Bai giang c++
Bai giang c++Bai giang c++
Bai giang c++
Thang DV
 
Bồi dưỡng HSG Tin chuyên đề thuật toán
Bồi dưỡng HSG Tin chuyên đề thuật toánBồi dưỡng HSG Tin chuyên đề thuật toán
Bồi dưỡng HSG Tin chuyên đề thuật toán
Nguyễn Đức
 
Clean code
Clean codeClean code
Clean code
Đàm Đàm
 
Code convention
Code conventionCode convention
Code convention
hanoiaptech
 
Design Pattern - Những công thức vàng trong thiết kế
Design Pattern - Những công thức vàng trong thiết kếDesign Pattern - Những công thức vàng trong thiết kế
Design Pattern - Những công thức vàng trong thiết kế
Nhật Nguyễn Khắc
 
Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++
Da To
 
Phong cach lap trinh c++
Phong cach lap trinh c++Phong cach lap trinh c++
Phong cach lap trinh c++
ptquang160492
 
Tài liệu Lập trình Zend Framework 2.x
Tài liệu Lập trình Zend Framework 2.xTài liệu Lập trình Zend Framework 2.x
Tài liệu Lập trình Zend Framework 2.x
ZendVN
 
Chuong 1. tong quan
Chuong 1. tong quanChuong 1. tong quan
Chuong 1. tong quanVũ Nam
 
Lập trình hướng đối tượng với java
Lập trình hướng đối tượng với javaLập trình hướng đối tượng với java
Lập trình hướng đối tượng với java
Ngô Đăng Tân
 

Similar to How to write good code (20)

Programming
ProgrammingProgramming
Programming
 
Seminar clean code
Seminar clean codeSeminar clean code
Seminar clean code
 
Clean code
Clean codeClean code
Clean code
 
Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++
 
C++ buu chinh vien thong
C++ buu chinh vien thongC++ buu chinh vien thong
C++ buu chinh vien thong
 
C++ bưu chính viễn thông
C++ bưu chính viễn thôngC++ bưu chính viễn thông
C++ bưu chính viễn thông
 
Ngon ngu lap_trinh_c__
Ngon ngu lap_trinh_c__Ngon ngu lap_trinh_c__
Ngon ngu lap_trinh_c__
 
Bai giang c++
Bai giang c++Bai giang c++
Bai giang c++
 
Bai giang c++
Bai giang c++Bai giang c++
Bai giang c++
 
C++ PTIT
C++ PTITC++ PTIT
C++ PTIT
 
Bồi dưỡng HSG Tin chuyên đề thuật toán
Bồi dưỡng HSG Tin chuyên đề thuật toánBồi dưỡng HSG Tin chuyên đề thuật toán
Bồi dưỡng HSG Tin chuyên đề thuật toán
 
Clean code
Clean codeClean code
Clean code
 
Code convention
Code conventionCode convention
Code convention
 
Design Pattern - Những công thức vàng trong thiết kế
Design Pattern - Những công thức vàng trong thiết kếDesign Pattern - Những công thức vàng trong thiết kế
Design Pattern - Những công thức vàng trong thiết kế
 
Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++
 
Phong cach lap trinh c++
Phong cach lap trinh c++Phong cach lap trinh c++
Phong cach lap trinh c++
 
Phong cach lap trinh c++
Phong cach lap trinh c++Phong cach lap trinh c++
Phong cach lap trinh c++
 
Tài liệu Lập trình Zend Framework 2.x
Tài liệu Lập trình Zend Framework 2.xTài liệu Lập trình Zend Framework 2.x
Tài liệu Lập trình Zend Framework 2.x
 
Chuong 1. tong quan
Chuong 1. tong quanChuong 1. tong quan
Chuong 1. tong quan
 
Lập trình hướng đối tượng với java
Lập trình hướng đối tượng với javaLập trình hướng đối tượng với java
Lập trình hướng đối tượng với java
 

How to write good code

  • 1. Code tốt có nghĩa là ??? Matsui Nobuyuki
  • 2. Code tốt có nghĩa là: • (Đặt tại môi trường doanh nghiệp)Code tốt có nghĩa là 「dễ đọc, dễ hiểu và dễ sửa chữa」 • Tuy nhiên không đồng nghĩa phải giúp giảm lượng truyền tải I/O hay lượng sử dụng bộ nhớ • Cũng không phải giúp hệ thống hoạt động nhanh hơn • Tuy nhiên với các phần mềm game hay hoạt động tại môi trường đặc thù thì đặc điểm trên cũng được tính vào để đánh giá code tốt • Không phải code sử dụng các thủ pháp trick để giúp viết ngắn mà hệ thống vẫn hoạt động • Tại các cuộc thi programming, đặc điểm trên được tính là code tốt
  • 3. Tại sao viết được code “tốt” lại cần thiết ? • Tại doanh nghiệp, việc phát triển thường xuyên được làm theo nhóm. • Cho dù là một mình phát triển đi chăng nữa, bản thân ở hiện tại và sau 3 tháng là 2 trình độ hoàn toàn khác nhau. • Ở môi trường doanh nghiệp, code đại đa số là “được đọc” hơn là “được viết" • Do ở môi trường doanh nghiệp rất hay có việc về mở rộng chức năng, cho nên phải đọc tất cả những đoạn code “có vẻ" liên quan đến chỗ đó. • Khi xảy ra lỗi, cần phải đọc thật nhanh code liên quan đến đoạn gây lỗi • Cho nên điều quan trọng không phải là viết ra những đoạn code “có thể chạy được” mà là “dễ đọc và dễ hiểu"
  • 4. Phương châm cơ bản để viết được code tốt • Cách viết để dễ đọc • Đơn giản hoá logic • Cấu trúc lại code(refactoring)thường xuyên • Viết để có thể test được
  • 5. Cách viết để dễ đọc • Sử dụng tên hợp lý • Chọn từ rõ nghĩa thể hiện đúng điều mà variable hay function muốn làm • Những tên function như get hay tên variable kiểu result không thể hiện được bên trong nó có gì • Hãy thêm vào những từ rõ nghĩa, cung cấp thông tin • Ví dụ với biến chứa thông tin filesize => có thể đặt tên là uploaded_file_mb • Tránh dùng những từ chung chung như tmp hay buf • Tuy nhiên với trường hợp tên biến chỉ bó hẹp trong phạm vi một màn hình thì vẫn có thể sử dụng không sao cả. • Do phạm vi của các biến loop cũng bị giới hạn cho nên kiểu tên như “i” hay “j" cũng ok • Với các trường hợp không thể chọn được tên rõ ràng và muốn đặt tên dài, cũng có nghĩa là chưa phân chia ra được các module hợp lý • Ví dụ nếu muốn đặt tên là canvas_max_px, tại sao không tách ra class Canvas chứa biến instance tên là max_px?
  • 6. Cách viết để dễ đọc • Tuân theo cách đặt tên và coding thích hợp • Hãy cố gắng tuân theo phong cách đã trở thành tiêu chuẩn đối với từng loại ngôn ngữ, hạn chế tạo ra các quy luật mới mình nghĩ ra • Ví dụ với Python: • PEP8 • http://legacy.python.org/dev/peps/pep-0008/ • Google Python Style Guide • http://google-styleguide.googlecode.com/svn/trunk/pyguide.html • Indent và xuống dòng đều có ý nghĩa của nó cho nên cũng phải theo quy luật • Với Python, mặc dù indent không có liên quan trực tiếp tới control structure, vẫn phải ý thức khi sử dụng
  • 7. Cách viết để dễ đọc • Chú trọng tính thống nhất cho vẻ ngoài • Ví dụ • Trường hợp có nhiều function lấy chung một variable làm argument, cho chung một thứ tự • Nếu định nghĩa variable mang ý nghĩa giống nhau tại nhiều module, cho tên giống nhau • Làm sao để người đọc không bị rơi tình trạng「Quái, cái hồi trước có phải thế này không nhỉ?」
  • 8. Cách viết để dễ đọc • Hạn chế việc tự viết • Sử dụng tối đa các chức năng thông dụng hay đã được đóng library sẵn với mỗi ngôn ngữ • Các xử lý tìm kiếm hay sắp xếp hầu hết đều được cung cấp code chạy rất nhanh và an toàn từ các dòng xử lý ngôn ngữ • Những chức năng mà ai cũng muốn như xử lý chuỗi string.. hầu hết đều được cung cấp sẵn. Với Java là apache commons, Ruby thì là active support • Nên đọc qua không chỉ về specs ngôn ngữ mình cần sử dụng, mà cả về specs những library chính cũng như function được cung cấp.
  • 9. Cách viết để dễ đọc • Thêm comment thích hợp • Không ghi những comment vô nghĩa kiểu như「đây là quy định của dự án」 • Comment về tư tưởng thiết kế và ý đồ tại sao implement method và class đó • Cái này vốn được tạo ra để làm gì? • Tại sao lại chọn logic này?Có cách thức nào khác không? • Comment những chỗ mình cảm thấy mơ hồ • Ví dụ • Với logic này cũng có thể chạy được tuy nhiên lượng cần tính toán với data sẽ là O(n^2) • Do là destructive method、internal data sẽ bị thay đổi sau khi được gọi dù chỉ 1 lần • Không comment những đoạn code nhìn cái là hiểu ý nghĩa • Những đoạn code phải comment về thứ tự xử lý để hiểu => bị coi là code không tốt
  • 10. Đơn giản hoá logic • Phân nhánh điều kiện • Đưa những điều kiện quan trọng và đơn giản lên trước • Sử dụng luật De Morgan( https://vi.wikipedia.org/wiki/Lu%E1%BA%ADt_De_Morgan ) hay Bìa Karnaugh( https://vi.wikipedia.org/wiki/B%C3%ACa_Karnaugh ) để đơn giản hoá điều kiện đi • Luật De Morgan • not (A or B) == (not A) and (not B) • not (A and B) == (not A) or (not B)
  • 11. Đơn giản hoá Logic • Sử dụng hiệu quả Bìa Karnaugh(by @kawasima) • Ví dụ trường hợp có điều kiện như dưới đây User profile (mục đang được lấy) Số điện thoại mail address địa chỉ cách liên lạc mail mail Điện thoại Mail Version Mail Version Không có
  • 12. Đơn giản hoá Logic • Sử dụng hiệu quả Bìa Karnaugh(by @kawasima) • Nếu implement thông thường sẽ là:
  • 13. Đơn giản hoá logic • Sử dụng hiệu quả Bìa Karnaugh(by @kawasima) • Khi viết thử bằng Bìa Karnaugh sẽ được như sau: Điện thoại: mail Địa chỉ Nếu viết bằng bìa Karnaugh sẽ rất dễ hiểu Tóm lại Nếu mail address đã được đăng ký => email, nếu chưa được đăng ký nhưng địa chỉ đã được đăng ký => DM, cả 2 cùng chưa đăng ký => điện thoại
  • 14. Đơn giản hoá logic • Sử dụng hiệu quả Bìa Karnaugh(by @kawasima) • Có thể implement bằng điều kiện đơn giản hơn:
  • 15. Đơn giản hoá logic • Cố gắng cho method trả giá trị thật nhanh • Thay vì phải nhớ mãi các điều kiện để phân định, khi xảy ra trường hợp bất thường => cố gắng đưa ra ngoài function hiện tại nhanh sẽ giúp code dễ hiểu hơn. def construct_msg(num_pageview): msg = "" if (isValid(num_pageview)): foo() … bar() … msg = buz() else: msg = "invalid" return msg def construct_msg(num_pageview): if (not isValid(num_pageview)): return "invalid" foo() … bar() … return buz()
  • 16. Đơn giản hoá logic • Không viết những đoạn code trick • Dù specs của ngôn ngữ đang dùng có support đi chăng nữa, không viết những kiểu code trick Không viết kiểu để tự mãn với bản thân xx = 1 yy = 2 def f(x,y): return x + y + xx + yy globals().update({"xx":1,"yy":2,"f":lambda x,y:x+y+xx+yy}) =
  • 17. Đơn giản hoá logic •Không viết những đoạn code trick •Dù có nói là được phép với specs của ngôn ngữ hiện tại đi chăng nữa, không viết những kiểu code trick Không viết kiểu để tự mãn với bản thân def check(x): if x%2 == 0: return even() else: return odd() def check(x): return odd() if x%2 else even() = def check(x): return (x%2 and [odd()] or [even()])[0] = def check(x): return [even, odd][x%2]() =
  • 18. Đơn giản hoá logic • Những phần implement có tính chất giúp giảm thiểu bộ nhớ và nâng cao tính năng để đến sau cùng • Trong nguyên lý Pareto( https://vi.wikipedia.org/wiki/Nguy%C3%AAn_l%C3%BD_Pareto ) đã có ghi: xét trên tổng thể, chỉ có 1 phần nhỏ các đoạn code gây ra việc tốn bộ nhớ và làm chức năng kém đi • Đầu tiên hãy chú ý tới viết code sao cho dễ hiểu • Kiểm duyện lại tính năng trên toàn bộ hệ thống, sau đó lọc ra các điểm chính gây ảnh hưởng tới bộ nhớ và làm giảm tính năng để tập trung sửa chữa • Những chỗ cần thiết tính năng phải thật tốt, có thể xem xét viết 1 vài chỗ bằng C cũng rất tốt • Tuning cho SQL là cách hiệu quả nhất để nâng cao tính năng • Tuy nhiên với những nest loop hay algorithm tìm kiếm O(n2).. không có sẵn thì cần xem xét kỹ ngay từ đầu để tránh những đoạn code hiệu suất thấp ※Nguyên lý Pareto 「Hầu hết các giá trị đều chỉ được sinh ra bởi 1 số thành phần cấu trúc nên toàn thể mà thôi」 「Nguyên lý 8:2」
  • 19. Tái cấu trúc code(Refactoring) • Những xử lý không tóm gọn trong một màn hình cần suy nghĩ xem có thể phân chia module được không • Xử lý không liên quan trực tiếp tới việc đoạn code muốn thực hiện (mục đích có thể tóm trong 1 dòng comment), cần cắt ra module khác • Nếu đặt tên một cách hợp lý, thậm chí không cần nhìn code của module được cắt ra vẫn có thể hiểu được đại khái nội dung xử lý của module đó => code cũ đã trở nên dễ hiểu hơn • Vậy phải phân chia bằng cách nào?
  • 20. Tái cấu trúc code(Refactoring • the Open-Closed Principle(OCP)(định luật đóng-mở) • 「Các element cấu trúc của software cần được mở với support mở rộng chức năng, nhưng đóng với việc sửa chữa」 • Những module được ý thức theo luật OCP sẽ không làm ảnh hưởng tới các module khác khi bị sửa chữa =Nguyên lý của thiết kế hướng đối tượng • Tầm quan trọng của specs API • Nếu specs API công bố ra bên ngoài(ứng với input của method sẽ cho output là gì, hay những “tác dụng phụ” xảy ra là gì)không thay đổi => Code phía trong bị thay đổi đi chăng nữa cũng không ai quan tâm
  • 21. Tái cấu trúc code(Refactoring) • Tác dụng phụ của function • (ý nghĩa mặt toán học)function = thứ chuyển từ input sang ouput • Những thứ nằm ngoài việc chuyển input sang ouput, làm ảnh hưởng đến môi trường ngoài function =Tác dụng phụ • Input/Output của network và file, input/output của màn hình, input/output của database.. đều là tác dụng phụ • input/output tới các variable ở phía ngoài function cũng là tác dụng phụ • Function không có tác dụng phụ thì dù được gọi trong bất cứ trường hợp nào cũng đều cho một kết quả • Trở thành module dễ test và stable • Ngôn ngữ functional programming về cơ bản tạo ra hệ thống dựa trên các function không có tác dụng phụ => bằng việc hạn chế tối đa những tác dụng phụ để có một hệ thống vững chắc. • Tuy nhiên, một hệ thống hoàn toàn không có tác dụng phụ cũng không có ý nghĩa đặc biệt gì cả
  • 22. Tái cấu trúc code(Refactoring) • Tận dụng ưu điểm của functional programming • Scope của biến càng nhỏ càng tốt • Tránh dùng global variable • Chỉ set giá trị 1 lần(không sử dụng lại biến giống nhau và viết lại) • Biến được giới hạn trong function nhỏ (ví dụ là biến loop) có thể viết lại cũng không sao. • Nếu tạo ra function mà ngầm viết lại những biến phụ thuộc sẽ dẫn tới khả năng sinh bug rất khó chữa ở những nơi mình không ngờ tới • Cũng cần phải chú ý tới việc viết lại nội dung biến của function như list.append() • Ví dụ: Nếu có ký hiệu list intension, list cũ sẽ vẫn như thế và list mới sẽ được tạo >>> x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> y = [i * 2 for i in x if i%2 == 0] >>> y [4, 8, 12, 16, 20] >>> x [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • 23. Tái cấu trúc code(Refactoring) •Tận dụng ưu điểm của functional programming • Không viết lại argument gửi tới function trong function đó • Argument của function trong Java và Python được đưa để tham chiếu • => Về mặt specs, có thể viết lại được nội dung argument object tuy nhiên về cơ bản không được làm. • Output trả về từ function tất cả phải dưới dạng return value • Khi xảy ra exception, không phải return value mà phải raise exception • Rút cuộc・・・ • Việc phân chia rõ ràng「phần được coi như là tác dụng phụ(external input/output.. )」, 「phần thực hiện xử lý phụ thuộc vào internal data của class」và「function không có tác dụng phụ」, rồi sau đó localize phạm vi mà code đó ảnh hưởng là rất quan trọng.
  • 24. Tái cấu trúc code(Refactoring) • the Single Responsibility Principle(SRP)(định luật nhiệm vụ đơn) • Nhiệm vụ của class chỉ có một • Bắt buộc phải viết được nhiệm vụ của class chỉ bằng 1 dòng comment dạng「Class này thực hiện nhiệm vụ “abc"」 • Lý do thay đổi implement của class chỉ có thể vì cần sửa chữa hay mở rộng nhiệm vụ “abc" đó • Khi sửa chữa program bằng 1 lý do ngoài việc「sửa chữa cho nhiệm vụ “abc" ấy」mà code trong class nhiệm vụ “abc" phải bị thay đổi • => việc phân chia class đã bị nhầm lẫn
  • 25. Tái cấu trúc code(Refactoring) • Để phân biệt class hợp lý cần sử dụng design pattern • Tổng hợp best practice để phân chia class thật chuẩn • Truyền thống nhất:GoF(Gang of Four)design pattern ( https://en.wikipedia.org/wiki/Design_Patterns ) • Ngoài GoF, có rất nhiều loại design pattern đã được đề ra. • Tuy nhiên, nếu sử dụng pattern chỉ vì có cảm giác “muốn sử dụng pattern" thì sẽ lợi bất cập hại
  • 26. Tái cấu trúc code(Refactoring) • Khi đánh giá độ hợp lý của code, cần sử dụng metrics • Độ liên kết và độ kết hợp • Tiêu chuẩn kiểm tra OCP và SRP của module • Hoàn hảo nhất là độ liên kết cao và độ kết hợp thấp • Có thể đưa ra con số cụ thể bằng code metric tool • Những con số cụ thể không có ý nghĩa lắm, điều quan trọng là dùng nó để nhìn ra thiên hướng chung • Độ phức tạp tuần hoàn của McCabe • Tiêu chuẩn kiểm tra độ phức tạp của code(mức độ của loop và phân nhánh) • Thông thường dưới 10 được coi là tốt • Quá 30 sẽ bị coi là module có cấu trúc thất bại, quá 50 sẽ là không thể test, quá 75 thì dù có sửa ít thế nào vẫn có thể sinh bug
  • 27. Viết để có thể test được • Những function không có tác dụng phụ sẽ có thể test dễ dàng • Càng đơn giản, càng bao phủ nhiều càng tốt • Tuy nhiên không phải test mù quáng bằng rất nhiều giá trị, hãy suy nghĩ lý do rõ ràng tại sao phải test bằng input đó • Giá trị giới hạn • Max và min của giá trị mong đợi cộng hoặc trừ với 1.. • Giá trị đặc biệt • Với trường hợp số thì là 0 • Với trường hợp chữ(utf-8), bit pattern mà có chữ là 1 byte(US-ASCII), chữ là 2 byte (Greek alphabet), chữ là 3 byte(kanji thông thường và số tròn..), chữ có trên 4 byte(kanji tiêu chuẩn tầng 3, 4 của JIS X 0213).. • Với trường hợp chữ(Shift-JIS và CP932), từ「表」và「ー」.. có byte thứ 2 là character 0x5c(backslash)và character bị hỏng do chuyển từ CP932 sang UTF-8(~)..
  • 28. Viết để có thể test được • Xử lý có tác dụng phụ • Sử dụng stub và driver để viết test • Sử dụng hợp lý chức năng được test framework cung cấp • Bằng việc test liên tục, có tính tiếp nối với program đã được phân chia module hợp lý và ý thức để test được • => dù có develop theo nhóm đi chăng nữa vẫn có thể yên tâm và mở rộng chức năng.