組織優(yōu)秀代碼的四原則

代碼寫了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)凌彬,我在那里等你

小熊的開源社區(qū).jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市循衰,隨后出現(xiàn)的幾起案子铲敛,更是在濱河造成了極大的恐慌,老刑警劉巖会钝,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伐蒋,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡迁酸,警方通過(guò)查閱死者的電腦和手機(jī)先鱼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)奸鬓,“玉大人焙畔,你說(shuō)我怎么就攤上這事〈叮” “怎么了宏多?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)澡罚。 經(jīng)常有香客問(wèn)我伸但,道長(zhǎng),這世上最難降的妖魔是什么留搔? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任更胖,我火速辦了婚禮,結(jié)果婚禮上隔显,老公的妹妹穿的比我還像新娘函喉。我一直安慰自己,他們只是感情好荣月,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著梳毙,像睡著了一般哺窄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上账锹,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天萌业,我揣著相機(jī)與錄音,去河邊找鬼奸柬。 笑死生年,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的廓奕。 我是一名探鬼主播抱婉,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼档叔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蒸绩?” 一聲冷哼從身側(cè)響起衙四,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎患亿,沒(méi)想到半個(gè)月后传蹈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡步藕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年惦界,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咙冗。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沾歪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乞娄,到底是詐尸還是另有隱情瞬逊,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布仪或,位于F島的核電站确镊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏范删。R本人自食惡果不足惜蕾域,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望到旦。 院中可真熱鬧旨巷,春花似錦、人聲如沸添忘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)搁骑。三九已至斧吐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間仲器,已是汗流浹背煤率。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乏冀,地道東北人蝶糯。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像辆沦,于是被迫代替她去往敵國(guó)和親昼捍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子识虚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容