Abject-oriented programming is a set of practices for encouraging code reuse and making sure programmers are producing code that can be used in production for a long time. The number of lines of code in the application is a common measure of the importance of the application, and the number of lines a programmer can produce in a day, week, or month is a useful metric for project planning and resource allocation. Abject-oriented programming is one of the best ways to get the most lines of code in the shortest time.
abject: utterly hopeless, miserable, humiliating, or wretched: abject poverty.
Inheritance
Inheritance is a way to retain features of old code in newer code. The programmer derives from an existing function or block of code by making a copy of the code, then making changes to the copy. The derived code is often specialized by adding features not implemented in the original. In this way the old code is retained but the new code inherits from it.
Programs that use inheritance are characterized by similar blocks of code with small differences appearing throughout the source. Another sign of inheritance is static members: variables and code that are not directly referenced or used, but serve to maintain a link to the original base or parent code.
A pseudo-code example of inheritance:
function getCustName(custID)
{
    custRec = readFromDB("customer", custID);
    fullname = custRec[1] + ‘ ‘ + custRec[2];
    return fullname;
}
function getCustEmail(custID)
{
    custRec = readFromDatabase(”customer”, custID);
    fullname = custRec[1] + ‘ ‘ + custRec[2];
    /***************
    * 4/15/96 git : email address stored in
    * second fax field
    ***************/
    return custRec[17];
}
The function getCustEmail was inherited from getCustName when email addresses were added to the application. Inheriting code in this way leverages working code with less risk of introducing bugs.
Subtyping is a kind of inheritance where the variable types are changed when inheriting from the original code.
Modularity
A modular program is one that is divided into separate files that share a common header comment block. A module usually consists of:
  • Copyright notice
  • Legal disclaimers
  • Three to five lines of asterisks
  • Change history
  • Description of what the module was originally supposed to do
  • Three to five more lines of asterisks
  • Big block of whitespace surrounded by asterisks or other character, including the name of each function or subroutine, the author’s name or initials, and the date originally written
  • The code
Modules are usually kept to a reasonable size to reduce coupling and improve module strength. If a module gets too big divide it into smaller pieces, copying the copyright notice, legal disclaimers, etc. from the original. Comments can always safely be inherited when deriving one module from another so it’s safest to copy all of the original comments.
Components and Libraries
Abject-oriented programming lends itself to using plug-in components — bits of code found in books or on the Internet. Using a search engine a smart programmer can save time by finding pre-made software components to do almost anything. The best components are black boxes: the programmer doesn’t know or care how the component works. Many large applications are built with a combination of inheritance from other applications and components gleaned from the web.
Encapsulation
The idea behind encapsulation is to keep the data separate from the code. This is sometimes called data hiding, but the data is not really hidden, just protected inside another layer of code. For example, it’s not a good practice to scatter database lookups all over the place. An abject practice is to wrap or hide the database in functions or subroutines, thereby encapsulating the database. In the getCustName function above the database is not queried directly — a function is called to read the database record. All getCustName and getCustEmail (and the many other functions like them) “know” is where in the customer record to find the bits of data they need. How the customer record is read is encapsulated in some other module.
Some programming languages make the programmer declare variables as private or public or protected. That is not an abject practice, though. There’s no way for the author of a module to know which internal variables of their module may be needed to implement features in the future. Programmers should make all variables public (or global), and let the rest of the code decide what should and shouldn’t be private.
Polymorphism
When learning abject-oriented techniques, programmers frequently get stuck on polymorphism. It sounds hard but the idea is simple and easy to implement. Code is polymorphic when it gives different outputs for different kinds of inputs.
To give an example, the functions above can be rewritten as a single polymorphic function by inheriting the code that already works and then encapsulating it into a new function:
function getCustData(custId, what)
{
    if (what == 'name') {
        custRec = readFromDB("customer", custId);
        fullname = custRec[1] + ‘ ‘ + custRec[2];
        return fullname;
    } else if (what == ‘email’) {
        custRec = readFromDB(”customer”, custId);
        fullname = custRec[1] + ‘ ‘ + custRec[2];
        /***************
        * 4/15/96 git : email address stored in
        * second fax field
        ***************/
        return custRec[17];
    }
    /* … etc. */
}
Polymorphism is related to the idea of non-determinism and Turing’s finite state machines, which you may remember from your Comp Sci classes.
Is-A vs. Has-A
This is a subtlety of good abject-oriented design. When first learning abject principles programmers tend to do everything with inheritance (the is-a model). With more experience programmers find that the has-a relationship is often more appropriate. In the code example above, every customer has a name, but custRec is a database record.
Virtual Classes and Functions
A virtual class or function is code that the application will eventually need, but it isn’t written yet. This is commonly accomplished by providing a base class that the final code will be based on:
function calcSalesTax(price, isTaxable, state)
{
    /****************************************
    *
    * TO DO:
    *
    * get tax rate for the customer state
    * eventually from some table
    *
    *
    ****************************************/
    /** 02/07/99 git -- use WA rate for now **/
    return price * (7.25 / 100.0);
}
A fragile base class is a class or module that has been in the application for a long time, and any change to it will break the rest of the application.
Overloading
Overloading is when a module or chunk of code does more than one thing. An example would be a subroutine to get a customer’s name, email address, and state sales tax rate. Using overloaded functions cuts down on method dispatching, which is one of the reasons other programming styles can result in slow code.
Documentation
It’s said that code should be written for people to read, so it follows that documentation is written for no one to read. Documentation should be written for every new module and then maintained as changes are put into production, or at least the next time there’s a lull in the workload.
A good time to write documentation is when someone in the department gives two-weeks notice: use that time to make sure the departing team member documents all of their code.
Cluttering up the source code with lots of comments explaining what the code is trying to do is distracting and slows down the compiler. That’s why abject shops that follow “best practices” keep documentation in a document management system where programmers can’t accidentally delete it.
Version Control
Not really a programming practice per se, but abject shops tend to follow similar version control practices. Keeping previous versions of code around, and tracking changes to code, is important even if only one programmer works on the application. Experienced abject programmers follow a system similar to this:
  • Always add your initials and the date of the last revision to the source file’s header.
  • When you are editing a file and realize that your changes are big enough to make reverting hard, save a copy with a .bak extension.
  • Keep multiple backups around by appending your name or initials and the date to the backup file name: custdata_git20040321.bak.
  • Always store backups in the same directory or folder as the original code, to make it easier to see each file’s history.
Conclusion
You’ll probably find that most established shops already follow some or all of these abject-oriented practices. Fads like agile and “extreme” programming come and go, but the abject style has stood the test of time. Managers are familiar with abject practices and will expect you to be able to work with their abject-oriented code base.
 
中文译文:
下贱导向编程(Abject-Oriented Programming),指能增加代码复用率,并敦促程序员写出经久耐用之源代码的一系列手段。源代码行数是衡量软件重要性的通用标准,程序员每日、周、月能写出多少行源代码,亦为项目规划和资源分配的常用凭据。而下贱导向编程正是在最短的时间内得到最多代码的最佳手段之一。
Abject: utterly hopeless, miserable, humiliating, or wretched: abject poverty.
继承
继承是在新代码中保持旧有代码特性的手段。程序员通过现有函数或程序块衍生新代码的方式是,将代码复制一份,继而加以修改。
衍生出的代码一般通过增加原有代码未实现的特性而将功能专门化。这样一来旧有代码保留不变,新代码继承而来。
使用继承手段写出来的程序,其特征是源代码由相似的代码块构成,而细微差别随处可见。继承的另一个标志是静态成员,即那些不被一个程序块本身所使用或引用,而是仅用以维系与该程序块的“基代码”或“父代码”之联系的变量和代码。
继承关系的伪代码例子:
function getCustName(custID)
{
    custRec = readFromDB("customer", custID);
    fullname = custRec[1] + ‘ ‘ + custRec[2];
    return fullname;
}
function getCustEmail(custID)
{
    custRec = readFromDatabase(”customer”, custID);
    fullname = custRec[1] + ‘ ‘ + custRec[2];
    /***************
    * 4/15/96 git : email address stored in
    * second fax field
    ***************/
    return custRec[17];
}
为了给应用程序添加email地址功能,getCustEmail函数继承getCustName函数。通过继承我们复用了能工作的代码且少有引入bug的风险。子类型转化也是一种继承关系,即继承自旧有代码的变量,其类型被转化。
模块化
程序模块化,指将源程序分割为若干文件而在各文件起始共享通用注释块。一个模块通常包括:
版权声明
免责声明
三到五行星号
代码变更记录
对该模块本来打算做什么的描述
再三到五行星号
以星号或其他字符包含的大块空白,内含每一函数或子例程的名称,作者的名字或缩写,以及最初编辑时间
代码
模块通常保持在合理的大小以减少耦合度并增加强健性。若某模块变得太大,应将其分割为小块,并从原来的模块中复制版权声明、免责声明等等到各小块中。在衍生新的模块时,注释总是可以被安全地继承,所以复制所有注释最安全。
组件与库
下贱导向编程倾向于使用插件式组件——从书上或网上找到的小段代码。聪明的程序员可以通过使用搜索引擎找到各种功能的预制组件,从而节省时间。最好的组件是黑箱,即程序员不知道也不关心组件是怎样运作的。许多大型应用程序是通过继承其他程序及从网上搜集组件而构建的。
封装
封装的意义在于分离数据和代码。有时这叫数据隐藏,但是数据并未被真正隐藏,只不过被保护在另一层代码内罢了。比如,在程序中到处写数据库查询是不好的,而下贱的解决手段是将数据库包装或隐藏在程序或子例程内,从而将数据库封装。上例的getCustName函数中,数据库并未被直接查询——我们调用了一个函数来查询数据库。getCustName和getCustEmail所“知道”的东西就是在客户记录的什么地方可以找到它们需要的那点数据。至于怎么读出客户记录,是封装在其他模块中的功能。
有些编程语言允许用户声明变量为private、public或protected,但这并非下贱编程的手法。某模块的内部变量将来是否会用于实现新特性,模块作者无从知晓,故程序员应该将所有变量设为public或global,并让代码的其它部分决定什么应不应该是私有的。
多态
学习下贱导向技法时,程序员经常卡在多态上。多态听起来挺难,但其实很简单,而且易于实现。如果一段代码根据不同的输入给出不同的输出,那么它就具有多态性。
作为例子,我们可以将上例的函数转写为多态函数,方法是将运行良好的代码继承,然后封装为一个新函数:
function getCustData(custId, what)
{
    if (what == 'name') {
        custRec = readFromDB("customer", custId);
        fullname = custRec[1] + ‘ ‘ + custRec[2];
        return fullname;
    } else if (what == ‘email’) {
        custRec = readFromDB(”customer”, custId);
        fullname = custRec[1] + ‘ ‘ + custRec[2];
        /***************
        * 4/15/96 git : email address stored in
        * second fax field
        ***************/
        return custRec[17];
    }
    /* … etc. */
}
 你可能还记得计算机课上学过的非确定性和图灵有限状态机,这些概念都和多态相关。Is-A 与 Has-A
这是优秀的下贱导向设计之精妙所在。刚开始学习下贱导向要义的程序员试图将代码以继承方式组织(“是一个”),而更有经验的程序员会发现“有一个”关系常常更为适用。上述例子中,每个客户都有名字,但custRec是一条数据库记录。
虚类和虚函数
所谓虚类或虚函数是指应用程序以后需要,但是目前还没写的代码。这通常以提供一个能被以后的代码所扩展的基类来成:
function calcSalesTax(price, isTaxable, state)
{
    /****************************************
    *
    * TO DO:
    *
    * get tax rate for the customer state
    * eventually from some table
    *
    *
    ****************************************/
    /** 02/07/99 git -- use WA rate for now **/
    return price * (7.25 / 100.0);
}
 所谓“脆弱基类”是指已经存在于应用程序中很久的类或者模块,对它们做出任何微小修改都会毁掉程序的其他部分。重载
重载是指一个模块或者代码块能够完成不只一项工作,比如一个能够获取用户的名字,email地址,以及州消费税率的子例程就使用了重载。重载可以减少方法调度,后者正是其他编程风格所产生的代码效率不高的原因。
文档
据说代码应该写得让人能读懂,依此推论,文档就不是写给别人看的。应该为每个新模块写文档,然后在做出的改变真能被用到的时候更新文档,至少也应该在下次不那么忙的工作间隙更新一下。
部门中的某人还有两周就要闪人的时候是写文档的好时机,这段时间里应该确保将要离开的小组成员为其全部代码写好了文档。
散落于代码各处,解释代码在做什么的注释让人分心,也会让编译变慢。这就是为什么进行“最佳实践”的下贱工作组将所有文档放在文档管理系统中:这样一来程序员就不能意外地删除它们了。
版本控制
版本控制本身并非编程手段,但是各下贱编程项目组倾向于使用相似的版本控制方法。把之前版本的代码妥善保存,跟踪对代码的改变,是哪怕只有一个程序员在写代码的时候也很重要的事情。富有经验的下贱程序员会使用类似这样的系统:
每次要把自己的名字缩写以及最后修订日期放在源代码文件首部。
当意识到自己的修改大到足以导致回溯困难,就把源码做个.bak拷贝。
整理多个备份的方法是将自己的名字缩写以及日期附加到备份文件名后面: custdata_git20040321.bak。
所有备份文件都应放在与所修改的源代码相同的目录中,以便看到每个文件的历史。
结论
你可能会发现,多数现存的软件小组都或多或少地采用上述下贱导向编程手段。流行一时的什么敏捷或者“极限”编程来来往往,但只有下贱风格经得起时间的考验。项目经理熟悉下贱编程手段,并且也将要求你能够适应他们既有的下贱导向编程基础。
作者简介
Greg Jorgensen是典型的程序员,自1974年开始编程,涉及BASIC,Fortran,COBOL,以及汇编。他也做过编程之外的事,为nike和apple等等公司工作过。现在他工作于Portland的Inspiration Software,开发教学产品,也做些签约编程。
译者说明
本文是搞笑之作,方式比较geek。所谓Abject-Oriented是对Object Oriented的恶搞,后者是一种编程的范式(paradigm),大陆通常译作“面向对象”,台湾则作“物件导向”,文中的继承、多态等均为该范式的术语。在翻译时我一开始也试图对“面向对象”一词恶搞,但很难找到与abject对应的、可以“面向”的词汇,勉强作“面向猥琐”,但是原作的谐音趣味就没了。后来想到台湾的译法,遂定为“下贱导向”。如果谁有更好的主意,请不吝赐教。

本文来自CSDN博客,转载请标明出处: http://blog.csdn.net/KITTY_chenming/archive/2007/06/30/1672377.aspx