關於編碼的思考

來源:互聯網
上載者:User
[原創] 關於編碼的思考

  摘要:代碼也分種類?哪種代碼能夠自動產生?自動產生代碼會不會讓程式員沒有飯吃?或者會顛覆現有的編程模式?

寫在前面

  學習編程,再加上實際開發,寫代碼也有7個年頭了。雖然不敢說有多少多少經驗,但思考總是有一些的。這兩年慢慢發現,原來代碼和代碼也是不同的。

  編程越來越趨於自動化,尤其在微軟的產品裡,程式員總是可以很懶惰。但懶惰之餘也有顧慮,35歲的年限讓很多人從25歲就開始焦慮,就開始“尋求出路”。而我卻越來越戀上編程,也曾想過將來做管理。但德魯克告訴我們,每個人都是自己的管理者,無論從事什麼工作。

  現在的工作離編程好像越來越遠了,但從事教育,在給別人澄清問題的時候也讓自己對很多知識產生了更深入的理解,更重要的是,產生了更深入的思考。

  本文就是很長一段日子以來思考的結果,主要是對代碼的一些認識。今後也還將就這些問題繼續思考,但決不會停止編程的步伐。

聲明性代碼和行為性代碼

  我認為自己最有價值的思考就是將代碼分成了這兩種類別——聲明性代碼和行為性代碼。聲明性代碼這個名詞忘了在哪裡看到過的(Declarative
Codes),而行為性代碼這個名詞則是我根據這個詞的對立面自編出來的。

  聲明性代碼指的是本身不完成任何實際工作,只是為編譯器和運行環境提供與程式相關資訊的代碼。

  行為性代碼指的是真正用來完成實際工作中某一步驟任務的代碼。

  就以Hello World為例。

01: using System;
02:
03: namespace AndersLiu.Samples
04: {
05:    public class Hello
06:    {
07:        static void Main()
08:        {
09:           
Console.WriteLine("Hello, world!");
10:        }
11:    }
12: }

  除了第09行屬於行為性代碼以外,其他代碼都是聲明性代碼。例如第01行,其作用僅僅是告訴編譯器,對於System命名空間中的類型,程式中可能僅會提到類型的名字,而不會給出完整名字,需要編譯器自己進行解析。又如第03、05、07行,分別告訴編譯器,這裡有個名為AndersLiu.Samples的命名空間、當前命名空間中有個名為Hello的公用類型、當前類型中有一個名為Main靜態私人方法,當然最終這些資訊會保留在程式集中,指導CLR的運作。

  而第09行,才真正完成程式的功能,向螢幕上寫一個字串。

  現在就可以明確一個問題了。眾所周知,一個C#源檔案被編譯後將產生一個程式集,而程式集中存放的是IL代碼和中繼資料。那麼,究竟哪些代碼經過編譯後會產生IL代碼,哪些代碼經過編譯後會產生中繼資料呢?答案不言而喻,聲明性代碼經過編譯後要麼被丟棄,要麼形成中繼資料;而行為性代碼經過編譯後,會變成IL代碼。聲明性代碼中,用來指導編譯器進行編譯的代碼將會被丟棄,而用來指導CLR運作的代碼,被保留在程式集中形成中繼資料。

  這是在.NET世界中,那麼對於其他編程技術或語言呢?不難發現,任何程式設計語言的構成結構中都會有這樣兩種代碼存在。而在程式設計語言之外,有很多純聲明性的語言存在,比如各種標記語言(HTML、XML、VRML等)。不過純行為性語言的存在值得質疑,目前沒有那種語言中僅存在行為性代碼,這是因為任何時候編譯器都要從代碼中擷取一些資訊,而這些資訊幾乎總是通過聲明性代碼來傳達的。

  在程式設計語言之中,聲明性語言的最大特徵就是沒有明顯的先後順序性。例如下面兩個變數(或域)的聲明:

int i;
int j;

  交換上面這兩條語句的順序,不會對程式產生任何影響。

  而行為性代碼就具有很強烈的順序性,如果兩條代碼引用了相關的實體,那麼調換其順序必然會導致程式行為的異常。像i++;
j++;這樣的語句交換順序沒問題,這僅僅是因為兩條語句沒有什麼相關性而已。

  另外,聲明性代碼和行為性代碼並不是以語句作為劃分單位的。例如int i = 5;,雖然這是一個完整的語句,但稱它是聲明性代碼或是行為性代碼是沒有意義的,因為它實際上包含兩條代碼:int
i;(變數聲明,聲明性代碼)和i = 5;(賦值,行為性代碼)。不過對於常數聲明來說,例如const
int c = 5;,儘管其中出現了賦值運算子=,但仍屬於聲明性代碼。

  對於C#語言來說,行為性代碼只能出現在方法體、屬性/索引器的get/set訪問器中。而類型的成員(域、屬性、方法和事件)聲明,都是聲明性代碼。那麼,為什麼上面提到的int
i = 5;在C#中可以作為一個類型的域聲明呢?來看一個例子,例如有下面這樣一個簡單的類定義:

namespace AndersLiu.Test
{
    class CSample
    {
        int i = 10;
        static int si = 5;
    }
}

  使用/t:library參數將其編譯為一個dll,並使用ILDASM對其進行Dump,可以從返回編出來的代碼中看到這樣的類定義(其中的中文注釋是我自己添加的):

.class private auto ansi beforefieldinit AndersLiu.Test.CSample
extends [mscorlib]System.Object
{
// 兩個私人域的定義,一個執行個體域i,一個靜態域si
.field private int32 i
.field private static int32 si

// 編譯器自動產生的執行個體預設構造器 .ctor
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
    // Code size 16 (0x10)
    .maxstack 8
    IL_0000: ldarg.0

    // 為執行個體域i賦初值10
    IL_0001: ldc.i4.s 10
    IL_0003: stfld int32 AndersLiu.Test.CSample::i

    // 賦值完畢,調用父類執行個體預設構造器
    IL_0008: ldarg.0
    IL_0009: call instance void [mscorlib]System.Object::.ctor()
    IL_000e: nop
    IL_000f: ret
} // end of method CSample::.ctor

// 編譯器自動產生的靜態構造器 .cctor
.method private hidebysig specialname rtspecialname static
void .cctor() cil managed
{
    // Code size 7 (0x7)
    .maxstack 8

    // 為靜態域賦si初值5
    IL_0000: ldc.i4.5
    IL_0001: stsfld int32 AndersLiu.Test.CSample::si

    // 賦值完畢,返回
    IL_0006: ret
} // end of method CSample::.cctor

  從這裡可以看出,編譯器自動將帶有初始化器的域聲明代碼拆成了兩個部分,域的聲明保留在類型(中繼資料)中,而對域的賦值則被插入到了自動產生的構造器代碼的最前面
(形成IL代碼)。

  而下面的代碼就沒有那麼幸運了,它們只能作為局部變數,如果將它們作為類型的域定義,就會發生編譯錯誤。

int i = 5;
int j = i + 5;

  這是因為C#編譯器只會將無順序性的(不相關的)行為性代碼轉移到構造器中,上面的代碼明顯存在強烈的順序性,因此編譯器為了確保程式行為的一致性,就會拒絕翻譯這段代碼。

小議代碼自動產生

  各大軟體公司(姑且這麼稱呼他們)和各種電腦方面的研究機構都一直在研究代碼自動產生的技術。編譯器其實是代碼自動產生的最好例子,我們編寫程式的行為可以認為是在幹涉編譯器,影響它產生代碼的行為。

  不過提到代碼自動產生,更多人的直觀認識是“原始碼的自動產生”,其實本文要討論的,也正是原始碼的自動產生。因此在本文中,如果不是特殊強調,就認為代碼自動產生等於原始碼自動產生。

  研究機構我不清楚,但在商業領域,在代碼自動產生技術上走得最遠的恐怕就是微軟了。從很久很久以前,微軟的各種開發工具(甚至包括像Office這類非嚴格意義上的開發工具)就都提供了豐富的代碼自動產生功能。這些功能體現在各種各樣的開發嚮導上,如著名的MFC應用程式架構、Visual
Basic的“所見即所得 (WYSIWYG)”開發環境等等。

  過去的代碼自動產生功能往往有限,雖然產生了大量的代碼,但程式員的工作依然是比較繁重的。且不說很多工作要靠程式員手工完成,遇到產生的程式碼難以滿足系統需求時,修改自動產生的程式碼的任務量就足以讓一般開發愛好者望而卻步。甚至,有時自動產生的程式碼還會出現BUG,要靠程式員手工fix。

  但自動產生代碼的功能還是或多或少會在程式員中引發一些焦慮。隨著.NET的出現(尤其是Visual Studio
2005的出現),很多代碼是不需要程式員來完成的,甚至程式員都可以忽視它們的存在。比如Typed DataSet、Web Services
Proxy,有多少一線的程式員有空或者是願意去看看它們的代碼是什麼樣子的?

  前不久參加了Vista的開發培訓,看到無論是WPF、WCF還是WWF,開發起來都不用編寫太多的代碼,無非就是改改設定檔,或是寫上一兩句“膠水代碼”。難道,程式員的“末日”真的來臨了?

  在解決這個問題之前,還是看看究竟哪些代碼能夠自動產生吧。

  很簡單,一句話可以概括:聲明性代碼和形成了模式的行為性代碼可以自動產生。

  以Visual Studio 2005的Class Diagram為例,Class
Diagram除了可以將項目中現有代碼中的類結構表示出來以外,還可以通過將Toolbox中表示各種類型和類型間關係的圖示拖到類圖中來完成系統的設計。通過圖形化方式進行編程的時代終於正式到來了。

  但是對Class
Diagram自動產生的程式碼稍作觀察就能發現,這些代碼只是類型的一個大致的“架構”,只是類型及其成員的聲明而已——這些不都是聲明性代碼麼。真的遇到方法體或者屬性/索引器的get/set訪問器,還不是要拋一個NotImplementedException異常出來?

  另外一類能夠自動產生的程式碼是已經形成了模式的行為性代碼。例如前面提到的Typed DataSet和Web Services
Proxy,其中都有一些行為性代碼存在,這些代碼很簡單,任誰都會編寫這樣的代碼去完成相應的工作,因此可以自動產生。還有一類形成了模式的行為性代碼,它們以“文法糖”的形式出現,由編譯器在真正的編譯開始之前完成代碼自動產生工作,例如C#中的foreach語句、using語句(並非“using指令”)和lock語句等。

  此外,Visual Studio 2005中還強調了Code Snippets的概念,這從某些角度來看,也是在自動產生形成了模式的行為性代碼。

程式員的出路

  文章進行到這裡,結論不言而喻了吧?

  不過這一部分的標題起得不好,僅作為標題使用,請不要就這個標題對我的闡述進行攻擊。首先就微軟的作風來講,不會把程式員逼到“找出路”的境地。微軟很懂得“生態環境”的概念,明白沒有更多的開發人員就沒有更多的Windows應用,沒有更多的Windows應用就沒有更多的Windows市場,沒有更多的Windows市場,微軟也就失去了生機。因此微軟“自古以來”就一直給開發人員提供者最好的資源和廣泛的生存空間,無論是初出茅廬的編程新手,還是深諳理論和實踐的技術大師,在微軟的平台上都有自己的舞台。今天是這樣,今後也是這樣。其次,就算程式員真的要“找出路”,這裡一沒給出最佳選擇,二並沒有提到所有可供參考的選擇,只是說一些自己的想法而已。說到這裡不得不申明以下,本文中提到的“程式員”,都特指“微軟平台上的程式員”。

  因此,對於想一直搞開發,而不想轉向管理者或轉向其他領域的程式員來說,這部分內容可能會有一些參考意義。

  綜合前幾部分的論述,程式員要想找到“出路”,或者想使自己的工作更有意義,無外乎向兩個方向發展——一是向宏觀發展,做系統架構師,或者至少是做設計者;二就是向微觀發展,在沒有模式的行為性代碼上下功夫。

  當代的開發工具儘管可以極大程度地便利設計工作,但畢竟只是工具,真正的設計思想和設計實踐依然是開發人員自己的財富。我不敢說設計工作在將來能不能實現自動化(實際上有些已經實現了),但目前很多設計工作還是靠人為來完成的。學會站在一個很高的層次上,對系統整體進行把握,在很長時間內還是可以利於不敗之地的。

  然而,設計上也存在很多模式,如果選擇作為一個設計者,絕對不能沉浸在已有的模式中沾沾自喜。一旦某日設計工作得以完善的自動化,形成了模式的設計思想將是第一批被設計工具所淹沒的。一定要在反覆的設計工作中磨練自己的思維,清醒地認識到那些設計已經形成了模式,在套用模式的同時對現有思路進行突破。

  而所謂的行為性代碼,其實往往體現著一系列的演算法。何謂“演算法”?解決特定理論問題的思維模式而已。因此,在學習現有演算法的原理和使用現有演算法解決問題的同時,仍不要忘記突破模式,尋求更新鮮的思路。如果只是掌握了很多爆難無比的演算法的使用,依然尋求不到“出路”,因為它仍然是模式,仍然可以自動產生。比如編譯原理,很多人並不能深刻掌握,但有很多工具可以自動產生詞法和文法的分析器原始碼。那麼,掌握了編譯原理中的理論,掌握了分析器產生器的使用方法,能解決問題嗎?

  總而言之,程式員,優秀的程式員並不好做,以前是這樣,以後也是這樣。只有提高自己的思維能力,說白了就是做個聰明人,才能有飯吃。不管啥年頭,混電腦這行光靠體力活可不行……

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.