論:如何成為有思想、能創(chuàng)新的程序員
寫這篇文章也源于我和新員工的一些談話心得,一些基礎(chǔ)比較薄弱的技術(shù)人員,看起來(lái)有點(diǎn)像沒(méi)有思想和靈魂的程序員。你可能也會(huì)覺(jué)得國(guó)內(nèi)有很多小企業(yè)出來(lái)的人或者剛畢業(yè)的人,會(huì)的最多也是CRUD和拖拉控件。我也接觸過(guò)一些技術(shù)人員,他們告訴我他們?cè)僖膊幌敫慵夹g(shù)了,因?yàn)榧夹g(shù)是在太無(wú)聊了,特別年紀(jì)稍大一點(diǎn)的,想的最多的就是轉(zhuǎn)行。曾經(jīng)我非常驚訝于這樣的狀況,事實(shí)上,寫程序是一件很有創(chuàng)造力的事情,但為何很多人都會(huì)覺(jué)得無(wú)聊呢。
隨著年紀(jì)的增長(zhǎng),這些問(wèn)題的答案慢慢變得清晰一些。在這里,我不敢說(shuō),我說(shuō)的都是正確的,我只是在一直不停的探索。在探索之后,我對(duì)我的新員工說(shuō)了以下的話:“進(jìn)入我們公司,雖然我們也是很不起眼的剛創(chuàng)業(yè)的小公司,但是,你在這里需要做一些改變了。我知道你們以前的工作性質(zhì)可能是上司給你交代任務(wù),告訴你怎么做,然后你管也不管就照章辦事,拉拉控件,以完成項(xiàng)目功能為首要任務(wù)。在我們這里,你需要成為一個(gè)有思想的程序員。有思想的程序員需要懂得如何使用聰明的腦袋瓜。事實(shí)上,很多人都不知道我們的腦袋瓜到底能做多少事情,不過(guò),一旦你嘗試了,你就會(huì)體會(huì)到‘不是做不到,而是想不到’。需要記住這些話,從思想上改變,從今天開始。首先,我們是做軟件產(chǎn)品的公司,質(zhì)量是產(chǎn)品生存的首要標(biāo)準(zhǔn),產(chǎn)品質(zhì)量的最低要求就是易用性;其次,我們要保證產(chǎn)品的質(zhì)量,代碼的質(zhì)量首先要過(guò)關(guān),標(biāo)準(zhǔn)編碼方式、異常處理方式、代碼的生命周期管理、編碼的完整性都需要兼顧;第三,避免寫一些垃圾代碼和重復(fù)的代碼,這需要?jiǎng)佑媚懵斆鞯哪X袋,我曾經(jīng)寫了10幾個(gè)的CRUD產(chǎn)品,從而自主創(chuàng)新了控件關(guān)系映射、對(duì)象-對(duì)象映射、通用窗體框架,乃至我們現(xiàn)在的OSGi.NET產(chǎn)品和云計(jì)算SaaS商店平臺(tái),都是從這些重復(fù)的勞作中不斷思索發(fā)明的。我看到設(shè)計(jì)模式的書時(shí),可以驕傲的向同學(xué)們吹牛,我也設(shè)計(jì)過(guò)幾個(gè)‘模式’;第四,學(xué)會(huì)發(fā)現(xiàn)問(wèn)題,探索問(wèn)題,積極詢問(wèn),避免把問(wèn)題遺留下來(lái)或者拖機(jī)取巧。浪費(fèi)一個(gè)發(fā)現(xiàn)問(wèn)題和解決問(wèn)題的機(jī)會(huì),相當(dāng)于浪費(fèi)提高自己的機(jī)會(huì)。最后,你要有信心成為一流有思想和靈魂的技術(shù)人員,別哪一天你離開尤埃時(shí),丟我們的臉,:)。”
我不敢說(shuō),我現(xiàn)在多有思想,但是,我隱隱約約感覺(jué)到一些這樣的有意思的東西。我崇拜“道法自然”,它告訴我違反規(guī)律就會(huì)受到懲罰,因此,我會(huì)時(shí)刻反省我是否有做錯(cuò)的事情,包括在平時(shí)編碼、設(shè)計(jì)和架構(gòu)的時(shí)候,以及平時(shí)生活上的為人處事。接下來(lái),我介紹一下,我如何來(lái)發(fā)明我曾經(jīng)的產(chǎn)品,希望能夠給人一些啟發(fā)。
1 我是如何發(fā)明了控件關(guān)系映射組件
控件關(guān)系映射的發(fā)明源自于我在參與一款MIS系統(tǒng)的設(shè)計(jì),該系統(tǒng)是一個(gè)鋼管管理系統(tǒng),每一個(gè)鋼管的信息有很多很多的屬性,我記得鋼管廠給我們的數(shù)據(jù)說(shuō)明書里面,一個(gè)管子的信息有驚人的380多列。因此,我們?cè)诓樵?、修改、添加記錄的時(shí)候,總是會(huì)有類似以下成片成片的代碼。
- var add***Sql = "insert into Test(a1,a2,....aN) values(@a1,@a2,....@aN)";
 - ......
 - var para1 = new SqlParameter("@a1", SqlDbType.String, a1.Text.Trim();
 - var para2 = new SqlParameter("@a2", SqlDbType.String, a1.Text.Trim();
 - ......
 - var paraN = new SqlParameter("@aN", SqlDbType.String, a1.Text.Trim();
 
(忽略中間的N-3行代碼,以及查詢、修改和刪除的代碼)
我記得,我們一起做的另一個(gè)小伙拿了一個(gè)CRUD一千多個(gè)字段的表來(lái)向我們顯耀說(shuō):“我他媽的把這功能實(shí)現(xiàn)了!”。我不知道大家是否反感這樣的代碼,反正我是厭倦了。當(dāng)我想到這是一件很痛苦的事情的時(shí)候,我考慮了如何來(lái)解決它。經(jīng)過(guò)一些思考,我驚訝的發(fā)現(xiàn),所有的CRUD以及界面的流程都可以抽象為“輸入-處理-輸出-輸入-處理-輸出......”的過(guò)程,處理的過(guò)程實(shí)際上是獲取輸入,然后組裝成SQL語(yǔ)句,最后在響應(yīng)到界面。這個(gè)過(guò)程是以SQL語(yǔ)句為中心,SQL語(yǔ)句的參數(shù)來(lái)源于界面的控件或者界面類的其它成員,SQL語(yǔ)句執(zhí)行的結(jié)果可能是跑到另一個(gè)頁(yè)面、執(zhí)行DataGrid綁定、執(zhí)行下拉列表綁定、給控件賦值。因此,我想到一個(gè)方法,可以設(shè)計(jì)一個(gè)SQL映射的配置,即利用這個(gè)配置,直接將界面控件映射到數(shù)據(jù)庫(kù),并且也可以執(zhí)行反向映射。以下是映射SQL的配置:
- <?xml version="1.0" encoding="utf-8"?>
 - <CrmMappings Class="HumanDispSolution.login" >
 - <MappingSQL GenType="None" Name="Login" Value="select UID,Name,Sys_User.RID,Role from Sys_User,Sys_Role where Sys_User.RID=Sys_Role.RID AND UID=@UID AND Password = @PWD" SqlOpType="SELECT" CmdType="Text" >
 - <SqlParams >
 - <SqlParam Name="@UID" ControlID="UID" ParamType="String" IsFile="False" >
 - </SqlParam>
 - <SqlParam Name="@PWD" ControlID="PWD" ParamType="String" IsFile="False" >
 - </SqlParam>
 - </SqlParams>
 - <SqlResults >
 - <SqlResult Field="Name" MemberID="UserName" IsStatic="True" AssemblyName="HumanDispSolution" StaticTypeName="HumanDispSolution.UserConfig" >
 - </SqlResult>
 - <SqlResult Field="UID" MemberID="UserID" IsStatic="True" AssemblyName="HumanDispSolution" StaticTypeName="HumanDispSolution.UserConfig" >
 - </SqlResult>
 - <SqlResult Field="RID" MemberID="RID" IsStatic="True" AssemblyName="HumanDispSolution" StaticTypeName="HumanDispSolution.UserConfig" >
 - </SqlResult>
 - <SqlResult Field="Role" MemberID="Role" IsStatic="True" AssemblyName="HumanDispSolution" StaticTypeName="HumanDispSolution.UserConfig" >
 - </SqlResult>
 - <SqlResult InvokeMethod="Log" IsStatic="True" AssemblyName="HumanDispSolution" StaticTypeName="HumanDispSolution.Logger" >
 - <InvokeParam Value="登入系統(tǒng)" >
 - </InvokeParam>
 - </SqlResult>
 - </SqlResults>
 - </MappingSQL>
 - </CrmMappings>
 
以下是調(diào)用映射SQL語(yǔ)句實(shí)現(xiàn)CRUD中的一個(gè)操作。
- namespace HumanDispSolution
 - {
 - public class login : CrmPage
 - {
 - private void btnLogin_Click(object sender, System.EventArgs e)
 - {
 - DataSet ds = this.ExecuteMapping("Login") as DataSet;
 - if(ds.Tables[0].Rows.Count > 0) //登入
 - {System.Web.Security.FormsAuthentication.RedirectFromLoginPage(UID.Text,false);
 - }
 - else
 - this.lAlert.Text = "<script language='javascript'>alert('登錄失敗,請(qǐng)重新輸入帳戶信息!');</script>";
 - }
 - }
 - }
 
另外,我還編寫了一個(gè)工具來(lái)自動(dòng)生成這樣的配置文件,從此以后,關(guān)于數(shù)據(jù)庫(kù)的CRUD,我爽了??!
2 我是如何發(fā)明了通用窗體框架
控件關(guān)系映射的發(fā)明也是源于上面提到的鋼管系統(tǒng)。當(dāng)超過(guò)2個(gè)人一起參與一個(gè)復(fù)雜項(xiàng)目時(shí),可能他們都需要操作主界面,在主界面加上各自模塊需要的菜單、需要的界面元素,此外兩個(gè)人設(shè)計(jì)的東西也完全不一致。這就造成一些問(wèn)題了,因?yàn)槿绾螌?shí)現(xiàn)兩個(gè)人的集成就有一些麻煩,而且經(jīng)常出現(xiàn)意外。于是我就發(fā)明了一個(gè)通用窗體框架,這個(gè)框架提供了以下功能:
(1)集成用戶權(quán)限;
(2)集成數(shù)據(jù)訪問(wèn);
(3)插件式支持,每一個(gè)人都可以并行開發(fā),集成時(shí)僅需要將配置文件集成一起就形成一個(gè)組裝起來(lái)的軟件了。
每一個(gè)開發(fā)人員只需要編寫類似以下的配置文件就可以集成了:
- <?xml version="1.0" encoding="utf-8" ?>
 - <MainForm>
 - <Menus Name="菜單">
 - <Menu Name="系統(tǒng)(S)" LeftIndex="3" TopIndex="1" Command="" Class="">
 - <Menu Name="登錄管理" LeftIndex="1" TopIndex="1" Command="" Class=""/>
 - <Menu Name="歡迎" LeftIndex="2" TopIndex="2" Command="" Class="CZB.Framework.WelcomeForm"/>
 - <Menu Name="退出" LeftIndex="3" TopIndex="3" Command="Close" Class=""/>
 - </Menu>
 - <Menu Name="數(shù)據(jù)導(dǎo)出(B)" LeftIndex="2" TopIndex="3" Command="" Class="">
 - <Menu Name="導(dǎo)出Excel" LeftIndex="2" TopIndex="2" Command="" Class="SalaryManagement.UI.frmExport"/>
 - </Menu>
 - </Menus>
 - <ToolButtons Name="工具欄">
 - <ToolButton Name="工具欄名稱" Index="1" ImageIndex="1" Visible="true" Roles="" Command="HideOrShow" Class="工具欄名稱" />
 - <ToolButton Name="工具欄名稱1" Index="2" ImageIndex="2" Visible="false" Roles="" Command="" Class="工具欄名稱1" />
 - </ToolButtons>
 - </MainForm>
 
3 我是如何設(shè)計(jì)了對(duì)象-對(duì)象關(guān)系映射
ORM對(duì)于一些小型應(yīng)用感覺(jué)有點(diǎn)龐大,但是對(duì)于大型應(yīng)用,我想是一個(gè)比較總要的組件了。在我們使用ORM組件時(shí),也經(jīng)常會(huì)寫以下代碼。
- var user = new User();
 - user.Name = NameTextBox.Text.Trim();
 - user.Password = PasswordTextBox.Text.Trim();
 - ......
 - OrmFactory.Save(user);
 - ----------------------------------------------
 - var user = OrmFactory.QueryScalar(...);
 - NameTextBox.Text = user.Name;
 - ......
 
如果一個(gè)MIS系統(tǒng)充斥了大量這樣的代碼,估計(jì)你也會(huì)膩味,從而喪失對(duì)編程的興趣了。記得我剛才說(shuō)什么來(lái)了,“有問(wèn)題,意味著升華”,“做一個(gè)有思想的程序員”。因此,接下來(lái)的問(wèn)題就是,我們?nèi)绾蝸?lái)解決類似這樣重復(fù)的勞動(dòng)。我在2006年時(shí)想到的辦法就是實(shí)現(xiàn)一個(gè)對(duì)象-對(duì)象的映射。首先,設(shè)計(jì)如下實(shí)體類:
- public class UserEntity
 - {
 - ……
 - [Member]
 - public int Age;
 - [Control]
 - public string Name
 - {
 - get { return this._Name; }
 - set { this._Name = value; }
 - }
 - [Control("CardNo.Text")]
 - public string CardNo
 - {
 - get { return this._CardNo; }
 - set { this._CardNo = value; }
 - }
 - ……
 - }
 - public class EmployeeEntity
 - {
 - ……
 - [Reference(typeof(UserEntity))]
 - public UserEntity User
 - {
 - get { return this._User; }
 - set { this._User = value; }
 - }
 - [Control]
 - public float PostSalary
 - {
 - get { return this._PostSalary; }
 - set { this._PostSalary = value; }
 - }
 - ……
 - }
 
其次,調(diào)用ObjectEngine實(shí)現(xiàn)OO映射。
A 實(shí)現(xiàn)表單類與實(shí)體類映射
- private void Map_Click(object sender, System.EventArgs e)
 - {
 - this.o = CZB.ObjectMapper.ObjectEngine.Map(this,typeof(EmployeeEntity)) as EmployeeEntity;
 - }
 
B 實(shí)現(xiàn)實(shí)體類與表單類的映射
- private void InverseMap_Click(object sender, System.EventArgs e)
 - {
 - this.o.User.Name = "c.z.b in";
 - this.o.User.Age = 19;
 - this.o.CompoInsurance = 0;
 - CZB.ObjectMapper.ObjectEngine.InverseMap(this,o);
 - }
 
4 我是如何設(shè)計(jì)OSGi.NET和SaaS商店產(chǎn)品
至于OSGi.NET和SaaS商店是我在不斷思索通用窗體框架以及對(duì)現(xiàn)有科技的趨勢(shì)的把握下,由幾個(gè)很有創(chuàng)造力的編程人員,在建立了完善的產(chǎn)品保障體系下,構(gòu)建起來(lái)的。這兩個(gè)產(chǎn)品我會(huì)在后面介紹如何設(shè)計(jì)的。他們的設(shè)計(jì)我用了很長(zhǎng)的時(shí)間。
我不是什么老鳥,希望我們?cè)谌绱硕嗟募夹g(shù)的世界中能夠多多交流,共同進(jìn)步。解決這些問(wèn)題,不僅增加了編程的樂(lè)趣,更是增加了自己的見(jiàn)識(shí),從而避免自己成為一個(gè)沒(méi)有思想的程序員!我也知道,我們可以找到很多理由來(lái)反駁文中提到的做法和觀點(diǎn),但是,提高自己才是最重要的,不要去著急的否定一些什么,并給自己找借口。
原文鏈接:http://www.cnblogs.com/baihmpgy/archive/2010/12/14/1905144.html
【編輯推薦】















 
 
 





 
 
 
 