代碼寫了5年,必然會(huì)產(chǎn)生審丑疲勞牡肉,代碼混亂不堪捧灰,無(wú)法維護(hù),可閱讀性基本沒(méi)有统锤。面對(duì)種種的問(wèn)題毛俏,如何使代碼更優(yōu)雅,更具可讀性便成了迫切需要解決的問(wèn)題饲窿。下面我從實(shí)戰(zhàn)中總結(jié)了四項(xiàng)基本原則煌寇,只要你靈活運(yùn)用,我保證你的代碼絕對(duì)漂亮的讓自己不敢相信逾雄。下面我嘗試以一種教學(xué)的方式教給你這四項(xiàng)基本原則阀溶。
一腻脏、把代碼按邏輯相關(guān)性分成不同的段落,亮點(diǎn)是每個(gè)段落可以給個(gè)總結(jié)性的注釋
我們可能都寫過(guò)作文,試想一下银锻,如果一篇文章沒(méi)有任何分段永品,一氣呵成,你閱讀之后會(huì)有什么感想击纬?會(huì)不會(huì)想殺了作者鼎姐?
其實(shí),碼代碼和寫文章是可以類比的掉弛,如果你寫得代碼中沒(méi)有任何分段症见,對(duì)于代碼閱讀者來(lái)說(shuō)難道不是地獄嗎?可能語(yǔ)言的描述終究是太抽象殃饿,那我就呈上兩個(gè)例子讓大家吐槽一下吧谋作。
示例1:
public interface FrontendServer {
void viewProfile(HttpRequest request);
void openDatabase(String location,String user);
void saveProfile(HttpRequest request);
String extractQueryParam(HttpRequest request,String param);
void replyOK(HttpRequest request,String html);
void findFriends(HttpRequest request);
void replyNotFound(HttpRequest request,String error);
void closeDatabase(String location);
}
示例2:
# Import the user's email contracts, and match them to users in our system.
# Then display a list of those users that he/she isn't already friends with.
def suggest_new_friends(user,email_password):
friends = user.friends()
friend_emails = set(f.email for f in friends)
contacts = import_contacts(user.email,email_password)
contact_emails = set(c.email for c in contacts)
non_friend_emails = contact_emails-friend_emails
suggested_friends = User.objects.select(email_in=non_friend_emails)
display['user'] = user
display['friends'] = friends
display['suggested_friends'] = suggested_friends
return render("suggested_friends.html",display)
吐槽時(shí)間。乎芳。遵蚜。
嘗試使用一下我們的代碼分段原則,閃亮的結(jié)果如下:
示例1應(yīng)用原則一:
public interface FrontendServer {
// Handlers
void viewProfile(HttpRequest request);
void saveProfile(HttpRequest request);
void findFriends(HttpRequest request);
// Request/Reply Utilities
String extractQueryParam(HttpRequest request,String param);
void replyOK(HttpRequest request,String html);
void replyNotFound(HttpRequest request,String error);
// Database Helpers
void openDatabase(String location,String user);
void closeDatabase(String location);
}
示例2應(yīng)用原則一:
# Import the user's email contracts, and match them to users in our system.
# Then display a list of those users that he/she isn't already friends with.
def suggest_new_friends(user,email_password):
# Get the user's friends' email addresses.
friends = user.friends()
friend_emails = set(f.email for f in friends)
# Import all email addresses from this user's email account.
contacts = import_contacts(user.email,email_password)
contact_emails = set(c.email for c in contacts)
# Find matching users that they aren't already friends with.
non_friend_emails = contact_emails-friend_emails
suggested_friends = User.objects.select(email_in=non_friend_emails)
@ Display these lists on the page.
display['user'] = user
display['friends'] = friends
display['suggested_friends'] = suggested_friends
return render("suggested_friends.html",display)
二奈惑、使用一致的布局吭净,讓相似的代碼看起來(lái)相似
你要問(wèn)我為什么讓相似的代碼看起來(lái)相似會(huì)使代碼更清晰更容易理解,我竟然無(wú)言以對(duì)肴甸。自以為可能是人類的認(rèn)知原理導(dǎo)致的寂殉,我無(wú)法給出更官方的解釋,但是我可以給你幾個(gè)例子讓你好好體會(huì)一下如果不這么做帶來(lái)的后果原在。
示例1:
public class PerformanceTester {
public static final TcpConnectionSimulator wifi = new TcpConnectionSimulator(
500, /* kpbs */
80, /* millisecs latency */
200, /* jitter */
1 /* packet loss % */);
public static final TcpConnectionSimulator t3_fiber =
new TcpConnectionSimulator(
500, /* kpbs */
80, /* millisecs latency */
200, /* jitter */
1 /* packet loss % */);
public static final TcpConnectionSimulator cell = new TcpConnectionSimulator(
100, /* kbps */
400, /* millisecs latency */
250, /* jitter */
5 /* packet loss % */);
}
我們使用原則二來(lái)變化示例1友扰,結(jié)果如下:
public class PerformanceTester {
public static final TcpConnectionSimulator wifi =
new TcpConnectionSimulator(
500, /* kpbs */
80, /* millisecs latency */
200, /* jitter */
1 /* packet loss % */);
public static final TcpConnectionSimulator t3_fiber =
new TcpConnectionSimulator(
500, /* kpbs */
80, /* millisecs latency */
200, /* jitter */
1 /* packet loss % */);
public static final TcpConnectionSimulator cell =
new TcpConnectionSimulator(
100, /* kbps */
400, /* millisecs latency */
250, /* jitter */
5 /* packet loss % */);
}
變換的結(jié)果很讓人眼前一亮,但還不是很完美庶柿,通過(guò)原則三村怪,會(huì)將完美進(jìn)行到極致。我們首先介紹一下原則三浮庐。
三甚负、使用方法或者其他技術(shù)消除重復(fù)的代碼
消除代碼塊中重復(fù)的代碼,會(huì)使得代碼邏輯更加簡(jiǎn)潔清晰审残,更具表達(dá)性梭域,重點(diǎn)更加突出。
示例1:
public class PerformanceTester {
public static final TcpConnectionSimulator wifi =
new TcpConnectionSimulator(
500, /* kpbs */
80, /* millisecs latency */
200, /* jitter */
1 /* packet loss % */);
public static final TcpConnectionSimulator t3_fiber =
new TcpConnectionSimulator(
500, /* kpbs */
80, /* millisecs latency */
200, /* jitter */
1 /* packet loss % */);
public static final TcpConnectionSimulator cell =
new TcpConnectionSimulator(
100, /* kbps */
400, /* millisecs latency */
250, /* jitter */
5 /* packet loss % */);
示例1應(yīng)用原則三:
public class PerformanceTester {
// TcpConnectionSimulator(throughput, latency, jitter, packet_loss)
// [Kbps] [ms] [ms] [percent]
public static final TcpConnectionSimulator wifi =
new TcpConnectionSimulator(500, 80, 200, 1);
public static final TcpConnectionSimulator t3_fiber =
new TcpConnectionSimulator(500, 80, 200, 1);
public static final TcpConnectionSimulator cell =
new TcpConnectionSimulator(100, 400, 250, 5);
}
示例2:
DatabaseConnectio database_connection;
string error;
assert(expandFullName(database_connection,"Doug Adams",&error)=="Mr. Douglas Adams");
assert(error == "");
assert(expandFullName(database_connection,"No Such Guy",&error)=="");
assert(error =="no match found");
assert(expandFullName(database_connection,"John",&error)=="");
assert(error =="more than one result");
示例2應(yīng)用原則三:
checkFullName("Doug Adams","Mr. Douglas Adams","");
checkFullName("Jake Brown","Mr. Jake Brown III","");
checkFullName("No Such Guy","","no match found");
checkFullName("John","","more than one result");
void checkFullName(String partial_name,
String expeted_full_name,
String expected_error){
// database_connection is now a class member
String error;
String full_name = expandFullName(database_connection,partial_name,&error);
assert(error == expected_error);
assert(full_name == expeted_full_name);
}
四搅轿、使用列對(duì)齊來(lái)使代碼更加易讀
使用列對(duì)齊的方式組織代碼碰辅,可以讓語(yǔ)句之間的對(duì)應(yīng)關(guān)系清晰明顯,閱讀者從中很容易獲取方法的調(diào)用規(guī)則等信息介时,這對(duì)于理解代碼和發(fā)現(xiàn)代碼中的錯(cuò)誤有極大幫助没宾。
示例1:
checkFullName("Doug Adams","Mr. Douglas Adams","");
checkFullName("Jake Brown","Mr. Jake Brown III","");
checkFullName("No Such Guy","","no match found");
checkFullName("John","","more than one result");
示例1應(yīng)用原則四:
checkFullName("Doug Adams" , "Mr. Douglas Adams" , "");
checkFullName("Jake Brown" , "Mr. Jake Brown III" , "");
checkFullName("No Such Guy" , "" , "no match found");
checkFullName("John" , "" , "more than one result");
示例2:
# Extract POST parameters to local variables
details = request.POST.get('details')
location = request.POST.get('location')
phone = request.POST.get('phone')
email = request.POST.get('email')
url = request.POST.get('url')
示例2應(yīng)用原則四:
# Extract POST parameters to local variables
details = request.POST.get('details')
location = request.POST.get('location')
phone = request.POST.get('phone')
email = request.POST.get('email')
url = request.POST.get('url')
如果想了解更多信息或者對(duì)開源項(xiàng)目感興,請(qǐng)加我的微信公眾號(hào)凌彬,我在那里等你