反面情势,基础到集团应用架构

在软件工程中,一个反面模式(anti-pattern或antipattern)指的是在实践中明显出现但又低效或是有待优化的设计模式,是用来解决问题的带有共同性的不良方法。它们已经经过研究并分类,以防止日后重蹈覆辙,并能在研发尚未投产的系统时辨认出来。

[前言]

一、上章回顾

       上章我们主要讲述了系统设计规范与原则中的具体原则与规范及如何实现满足规范的设计,我们也讲述了通过分离功能点的方式来实现,而在软件开发过程中的具

体实现方式简单的分为面向过程与面向对象的开发方式,而目前更多的是面向对象的开发设计方式。并且我们也讲述了该如何通过设计手段去分析功能点及设计分离

点,应该如何在设计的过程中分析的角度及如何去满足设计规范与原则。首先我们通过下图来回顾下上章要点:

图片 1

Andrew Koenig在1995年造了anti-pattern这个词,灵感来自于GoF的《设计模式》一书。而这本书则在软件领域引入了“设计模式”(design pattern)的概念。三年后antipattern因《AntiPatterns》这本书而获得普及,而它的使用也从软件设计领域扩展到了日常的社会互动中。按《AntiPatterns》作者的说法,可以用至少两个关键因素来把反面模式和不良习惯、错误的实践或糟糕的想法区分开来:

design pattern是设计模式,通常是前人在软件开发过程中积累出来的解决一些问题

二、摘要

        本文将已架构的方式去分析分层结构中的业务层的设计,如何写出来内聚度,高耦合的业务逻辑层,并且如何根据我们的项目中的个功能需要去设计业务层。我

们本章将会通过几种可能的业务层的设计模式去分析,并且分析每种设计模式的优点与缺点及每种设计模式的应用场景,并且结合一定的使用实例来讲解,当然这些具体

的内容都是自己在项目中的经验与总结。错误之处,在所难免,本人抱着求真务实的态度,争取写好每一篇文章,错误之处还请大家匹配之处,如果您有好的意见或建

议,可以及时跟我沟通,如果对系统架构中的设计规范与模式不了解,可以点击这里查看上篇文章:系统架构师-基础到企业应用架构-系统设计规范与原则[下篇]

        本章讲解的内容我们先看下图中的几个简单模式:

        图片 2

  • 行动、过程和结构中的一些重复出现的乍一看是有益的,但最终得不偿失的模式
  • 在实践中证明且可重复的清晰记录的重构方案

的现成套路,按它们来做可获益无穷。anti-pattern也是一些现成的套路,但它们是现成的

三、本章大纲

       1、上章回顾。

       2、摘要。

       3、本章大纲。

       4、业务层设计分析。

       5、几种不同的业务设计模式。

       6、本章总结。

       7、系列进度。

       8、下篇预告。

很多反面模式只相当于是错误、咆哮、不可解的问题、或是可能可以避免的糟糕的实践,它们的名字通常都是一些用反话构成的词语。有些时候陷阱或黑色模式(dark patterns)这些不正式的说法会被用来指代各类反复出现的糟糕的解决方法。因此,一些有争议的候选的反面模式不会被正式承认。

错误套路,避免它们则亦可获益无穷。本文译者Korner Hill的更多其它翻译和原创文章可

四、业务层设计分析

        本节中将会对业务层的设计进行详细的分析。

        首先、我们知道业务层是一个系统中最核心的部分,业务层是实现系统业务功能的核心逻辑层。业务层我们通常说的BLL(Business Logic Layer)层,现在我们

一般的稍微复杂一些的业务逻辑都是通过分层结构来构建一个应用系统,我想大家在组织业务逻辑功能时大部分的情况下是使用BLL层单独负责相应的业务逻辑来实现

的。有些应用可能业务逻辑层并不复杂,这是我们可以把问题简单化,不用引入一些框架性的东西来提升系统的复杂度,但是有些业务规模较大,并且业务逻辑性较强

时,可能使用好的业务设计模式带来的优越性就显而易见了。 我们大家都知道业务逻辑层主要是用来处理领域模型对象之间的逻辑关系的部分。我们都知道业务层的数

据最终是要保存到数据库中,我们在进行业务层设计时一般是在架构中的分层架构模式中出现的。我们知道分层结构中一般是将领域模型与底层数据访问、表现层等进

行分开组织,这样可以让系统结构上清晰,并且容易降低他们之间的耦合性。

        其次、其实我们的很多操作都是可以在业务层来完成,比如说用户的角色权限,数据验证等一些基本的业务规则。当然这里说明业务层主要负责系统中的业务规

则的实现。这里我们需要知道2个概念,就是对象模型与领域模型:下面我们说下这2者的区别。

        图片 3 描述对象模型与领域模型的区别。

        最后、业务逻辑层作为分层系统中的中间位置,业务模型是表现层与数据层之间的纽带。当然一般我们在系统设计时,可能我们一般不会把领域模型中的领域实

体作为分层之间的传输信息,因为一般来说领域模型中的实体不但包含实体的数据信息,并且包含实体的行为。可能我们在各层中只会用到实体的数据信息,那么无疑

这时采用领域实体的形式进行传输,那么会增加系统的传输负载。当然这里就会出现我们平时所谓的3层模式中的Model层。当然Model层设计的主要作用就是实体数据

的承载,其中并不包含任何行为。具体的行为通过数据访问层来实现CRUD(DDL中的四个基本操作)的操作。

        图片 4 目前我们设计的分层结构中的对象模型中并不包含实体的行为。其实这里可以看作是比

较好的设计方式,因为采用对象模型的方式进行数据传输时可以降低系统的耦合。当然我们也可以把领域实体看作是多个对象实体的组合并且包含这些对象实体之间的

关系。所以我们在做系统架构时可能如何权衡就比较重要,具体是使用领域实体进行数据传输还是对象实体主要还是看业务的需要。

这个概念很容易推广到工程学以及工程以外需要人们付出努力去争取的领域。尽管在工程学以外很少用到这个术语,但其概念是通用的。

在blog上找到http://blog.csdn.net/KornerHill。

五、几种不同的业务设计模式

       首先我们在业务逻辑层设计时,必须首先确定是采用面向过程还是面向对象的模式来设计。 下面我们就将针对开篇介绍的几种模式进行分别介绍,错误之处请大

家批评指出。我们首先来讲解过程式的2类逻辑层的架构模式。

社会和组织结构

计算机领域内的很多词汇都缺少公认的中文翻译,anti-pattern也是如此,这里译为反面模

      过程式模式

组织结构

从天而降的责任(Accidental Ownership):雇员们接手了一个与当前系统完全无关的系统,在没有合适的训练、学习或关心下就得维护它

分析瘫痪(Analysis paralysis):花费太多精力在项目的分析阶段

血刃(Bleeding edge,刀锋):采用一些未经测试和/或尚不稳定的前沿技术来运营,从而导致成本超支、表现/性能不佳,和/或交付延期。

摇钱树:盈利的老产品通常会导致对新产品的自负

委员会设计(Design by committee):很多人同时进行设计,却没有统一的看法

承诺升级(Escalation of commitment):明知错了还不能收回之前的决定

独裁管理(Management by perkele):用完全听不进异议的独裁作风进行管理

目标管理(Management by objectives):通过数字管理,过于关注非本质而或不易取得的数字指标

道德风险(Moral hazard):不让做决定的人知道他的决定会带来什么结果

蘑菇管理(Mushroom management):不通知或是错误地通知雇员信息。雇员像蘑菇一样在黑暗中吸取养分,自生自灭

海鸥式管理(Seagull management):只有当出现问题的时候管理人员才会跟雇员进行接触和互动的管理模式。典型的场景就是,海鸥式的管理人员“飞”过来,嘁嘁喳喳,是人都批评一通,尔后“飞”走了!

烟囱式管理(Stovepipe or Silos,竖井式/发射井式/谷仓式管理):组织结构是由若干彼此孤立的团队组成,并且整个组织结构的范围内,上下沟通交流能够有效进行,而水平/横向的则不然。结构上支持数据主要在上下方面的流动,却禁止跨部门的通信。

厂商陷阱(Vendor lock-in,供应商套牢,供应商陷阱,厂商泥潭):使一个系统过于依赖于外部所提供的组件/部件。

式,乃是因为它本身是作为反面教材使用的模式。其实直接用“反面教材”更通俗易懂,但

       1、事务脚本模式

           事务脚本模式是面向过程的模式,那么我们就不会采用面向对象的设计思想。这种模式是将业务代码映射到用户的操作中。简单的理解就是将用户的每个操作

都对应一个方法,那么这个方法就是我们这里讲的事务脚本。 当然这里的“事务”就是指我们平时说的业务流程,“脚本”则是我们说的流程中的相应操作方法。这里

需要注意的是 ,不要认为数据库操作的相应方法也属于脚本中的内容,我们通常还是将数据访问层单独的书写,只不过脚本中调用而已。

           通常,事务脚本模式中都是一系列的逻辑判定或者循环或其他方式,通过一系列的函数调用来实现业务流程的。通常来说一般业务比较单一或者不是很复杂的

系统功能,通过该模式实现起来会比较简单。而且如果业务流程中的变化较为频繁的话不建议使用该模式来做。我们认为,我们对于这类简单的功能,我们没有必要花

费较大的代价去设计领域模型和其他方面的考虑。

          事务脚本模式的一大优势就是很简单,没有开始时的额外代价,它可以很好的进行快速的应用程序开发,一般情况下来说,如果一个项目的时间紧迫,逻辑简

单,并且使用强大的开发工具时,我们可以使用这样的模式来进行,无论是成本还是开发效率上都非常客观。

          我们根据上面的介绍可能认为,事务脚本模式的可重用性不高,并且耦合性太高,适应性并不好,当时我们仍然可以通过我们好的设计来实现代码的重用,

我们可以在进行“脚本”编写时将重用的部分抽象出来,写一个单独的函数,以达到复用的目的。

          事务脚本模式的一个重大缺点就是通过这样的设计很容易造成代码重复,通常来说我们很容易完成一系列的业务功能,但是随着应用程序功能的增加,那么应用

程序代码会变成非常复杂的程序结构,当然我们可以通过重构去环节该模式的这一劣势,当规模达到一定程度时,我们同样没办法去完成重构工作。

          通过上面的讲述,我们对事务脚本模式有了初步的认识,那么下来我们看看我们在进行业务逻辑层设计时的详细使用该模式的步骤及相关准则。

          图片 5 本图描述了事务脚本模式的设计过程,那么基本上每个系统流程都可以通过这样的流程来完成设计。下面我们就针对一个简单的实例来讲解下

如何通过这样的设计流程来实现系统的功能。

            我们这里以简单的购物流程来讲述。如何下一个订单

            首先、我们先来分析下用例:

            图片 6 我们知道注册的会员可以通过将产品添加到购物车中,然后通过去付款模块来进入支付系统,完成订单。

            其次、分析出事务。

            图片 7 一般来说购物的流程是这样的流程。当然这里也不是标准的形式。

            那么我们如何上述的几个步骤的内容,去完成这个事务的流程。

    public class BuyInfo 
    { 
        /// <summary> 
        /// 购物车中的产品列表 
        /// </summary> 
        private List<Product> proList = new List<Product>(); 

        public int CreateBuyCar(Product product) 
        { 
            //事务开始 
            this.BeginTranstion(); 

            //判定当前添加到购物车中的产品信息是否是自己发布的产品 
            if (!this.IsCanBuy(product.PutOutID)) 
                return; 
            //判定当前产品的库存信息是否大于当前购买的数量; 
            if(!this.IsLagerThenBuy(product.PutOutID)) 
                return; 

            //添加产品到购物车 
            proList.Add(product); 

            //处理生成订单信息 
           int orderID= this.CreateOrder(); 

            //事务结束 
            this.EndTranstion(); 

            return orderID; 
        } 

        /// <summary> 
        /// 生成订单 
        /// </summary> 
        /// <returns></returns> 
        private int CreateOrder() 
        { 
            Order order = new Order(this); 
            return order.CreateOrder(); 
        } 

        /// <summary> 
        /// 判定当前产品的库存信息是否大于当前购买的数量 
        /// </summary> 
        /// <param name="p"></param> 
        /// <returns></returns> 
        private bool IsLagerThenBuy(int p) 
        { 
            return false; 
        } 

        /// <summary> 
        /// 判定是否是自己发布的产品信息 
        /// </summary> 
        /// <param name="p"></param> 
        private bool IsCanBuy(int p) 
        { 
            return false; 
        } 

        private void EndTranstion() 
        { 
            //TODO.. 
        } 

        private void BeginTranstion() 
        { 
            //TODO.. 
        } 
    }

            这里定义的是添加到购物车的流程,下面将给出如何将购物车中的产品信息添加到订单中的具体流程。

    public class Order 
    { 
       private BuyInfo info; 
       public Order(BuyInfo buyInfo) 
       { 
           info = buyInfo; 
       } 

       public int CreateOrder() 
       { 
           //将BuyInfo购物车中的产品列表与订单信息进行关联。 
           this.InitOrderInfo(); 
           //将订单中的会员信息关联 
           this.InitOrderUserInfo(); 
           //将订单中的收货信息关联。 
           this.InitOrderReciveInfo(); 
           //将订单中的支付信息关联。 
           this.InitOrderPayInfo(); 
           //生成订单。 
       } 

       /// <summary> 
       /// 将购物车中的产品添加到数据库中 
       /// </summary> 
       private void InitOrderInfo() 
       { 
           throw new NotImplementedException(); 
       } 

       /// <summary> 
       /// 初始化订单的支付信息 
       /// </summary> 
       private void InitOrderPayInfo() 
       { 
           throw new NotImplementedException(); 
       } 
       /// <summary> 
       /// 初始化订单中的收货信息 
       /// </summary> 
       private void InitOrderReciveInfo() 
       { 
           throw new NotImplementedException(); 
       } 
       /// <summary> 
       /// 初始化订单的买家信息 
       /// </summary> 
       private void InitOrderUserInfo() 
       { 
           throw new NotImplementedException(); 
       } 
   }

            通过上面的形式基本上就完成了简单事务脚本模式的构建,当然我们也可以将所有的一系列的脚本封装到一个类里面,通过静态方法的方式来访问也是可以

的。只是组织方法的形式不同。当然我这里提高了,通过将脚本封装到一个类里面,通过静态方法的形式或者实例方法的形式都是可以的,那么我们来讲讲什么时候

封装成静态方法,什么时候封装成实例方法。

            图片 8

            我们如何将数据传入给实体脚本呢,通常我们是通过前面我们说的对象实体来完成的,因为数据对象实体只是包含实体的数据信息,并不包含具体的行为。

            那么我们来简单说说对象实体中的信息及格式,我想大家用过分层结构中的Model层的都会比较的清楚,下面我们看看,不详细介绍了:

    public class Product 
    { 
        private int putoutID; 

        public int PutOutID 
        { 
            get 
            { 
                return this.putoutID; 
            } 
            set 
            { 
                this.putoutID = value; 
            } 
        } 
        private int productID; 

        public int ProductID 
        { 
            get 
            { 
                return this.productID; 
            } 
            set 
            { 
                this.productID = value; 
            } 
        } 
        private int productName; 

        public int ProductName 
        { 
            get 
            { 
                return this.productName; 
            } 
            set 
            { 
                this.productName = value; 
            } 
        } 
        private int productUnit; 

        public int ProductUnit 
        { 
            get 
            { 
                return this.productUnit; 
            } 
            set 
            { 
                this.productUnit = value; 
            } 
        } 
        private int productClass; 

        public int ProductClass 
        { 
            get 
            { 
                return this.productClass; 
            } 
            set 
            { 
                this.productClass = value; 
            } 
        } 
    }

            我们看到了主要是通过get;set访问器来实现的。

            总结:业务逻辑层是将表现层触发一系列事务分别实现,那么对业务逻辑层的建模其实就是对事务的具体实现,将事务映射到业务逻辑层中的不同方法上,一

般来说事务代码维护起来比较难以维护,重用性低,难以理解。

       2、表模块模式

            表模块模式是对事务脚本模式的实践总结并优化而提出的新模式。相比而言,表模块模式结构性更强,总体来说,表模块就是就是将数据库中的某个表上的所

有可能的操作都写在一个类文件中,这个类文件中定义了该数据库表对应的所有的业务方法。表模块类是一个容器,它内部包含了类的数据信息和相应的行为。表模块

是映射数据库表的关系,因此表模块对应的是数据集合,那么无法将数据库表中的某个行记录进行区分,只能通过集合中的键或者索引来访问行记录的信息。

            表模块模式由于是在事务脚本模式发展的更有结构化的模式,那么可以说表模块模式虽然是面向过程的模式,但是它朝面向对象的模式已经迈了很大的一步,

我们知道,在将对象模型中的数据保存到关系数据库中时,需要使用相关的ORM工具去完成相应的转换。我们知道面向对象模型能够很灵活、更好的对领域模型建模。当

然,表模块模式仍然关注的是方法,而不是对象。

            通常我们在更好的结构设计指导的同时,那么我们需要考虑更多的规则,那么意味着我们需要书写更多的代码。表模块模式的具体实例可以参考Visio Studio

中的提供的DataSet和dataTable。

            表模块在处理简单的实体时具有很好的优势,但是当实体较复杂时,或者实体之间的关系紧密时无法很好的处理。下面我们来看看一个简单的例子来说明表模

式的使用。我们这里还是以刚才事务模型中的购买流程来讲解。

            图片 9 数据库表与表模块类的映射关系是通过.NET提供的内存数据对象DataSet、

DataTable来实现。

    public class Order 
    { 
         private System.Data.DataTable _orderItems; 
         private DataSet _ds; 
         public Order(DataSet ds) 
         { 
             _ds = ds; 
         } 

         /// <summary> 
         /// 返回订单对应的所有产品信息 
         /// </summary> 
         /// <returns></returns> 
         public DataTable Products() 
         { 
             return _orderItems; 
         } 

         /// <summary> 
         /// 返回当前索引号的订单信息 
         /// </summary> 
         /// <param name="index"></param> 
         /// <returns></returns> 
         public DataRow GetRow(int index) 
         { 
             return _ds.Tables[0].Rows[index]; 
         } 

         /// <summary> 
         /// 根据订单的ID返回订单的信息 
         /// </summary> 
         /// <param name="id"></param> 
         /// <returns></returns> 
         public DataRow GetRowByID(int id) 
         { 
             return _ds.Tables[0].Select("id="   id.ToString()); 
         } 

         public int Update(int orderID) 
         { 
             return 0; 
         } 

         public int Delete(int orderID) 
         { 
             return 0; 
         } 

         public int Insert(int orderID) 
         { 
             return 0; 
         } 
    }

           我们这里的数据如果发生变化时,我们如何将变化了的内存中的datatable或者dataset持久化到数据库中呢,ADO.NET为我们提供了dataadapter,通过这

个适配器我们完成datatable中的数据持久化到数据库表中。具体的形式就是上图中的流程,UI层通过数据请求方法,然后表模块层中有相应的方法,将发送数据请求访

问数据库,然后数据库返回相应结果通过datatable或dataset来初始化表模块类中的数据信息,然后返回给UI层相应的数据信息,然后绑定后显示。

          总结:表模块模式相比事务脚本模式。是我们推荐的使用模式。并且VS中自动继承了相应的datatable 与datas的相应的图形化设计方法,很方便的使用。并

且内部.NET framework 内置了相应的操作方法可以迅速的实现交互,在过程式模式中无疑是使用表模块模式是首选方案。

          表模块模式更关注的是与数据库表的映射关系,那么可以说表模块模式中包含了数据模型。有一些面向对象的味道,不过表模块模式中并不关注业务。

项目管理

雪崩模型(Avalanche):不合理地混搭或者说混合使用瀑布模型与敏捷开发方法。

死亡征途(Death march,死亡之旅):除了CEO,每个人都知道这个项目会成为一场灾难,但是真相却被隐瞒下来,以免项目被立即取消。(尽管CEO通常知道并且仍然继续试图最大化利润。)然而,真相被隐藏起来,直到大限来临("Big Bang")。另一种定义:雇员由于不合理的deadline,被迫在深夜和周末加班。

团队思维(Groupthink):在团队思维中,团队成员避免提出在一致观点之外的思维。

九九定律(Ninety-ninety rule):当项目“几近完成”时,低估完成项目所需时间的倾向。

过度设计(Overengineering):花费资源完成比实际需要的还要鲁棒和复杂的工程

障眼法(Smoke and mirrors):展示还没实现的功能,就像它们已经实现了一样

软件膨胀(Software bloat):允许系统的后续版本使用更多的资源

旁观冷漠(Bystander apathy):一个需求或者设计是错的,注意到这一点的人却不指出,因为这影响的是其他人。

这里为了保持它与设计模式之间的内在关联,而使用了“反面模式”一词。

      对象式模式

           我们来讲述下面向对象的模式中的2种方案

软件设计

抽象倒置(Abstraction inversion):不把用户需要的功能直接提供出来,导致他们要用更上层的函数来重复实现

用意不明(Ambiguous viewpoint):给出一个模型(通常是OOAD,面向对象分析与设计)却没有指出用意何在

大泥球(Big ball of mud):没有清晰结构的系统

数据库式进程间通信(Database-as-IPC):使用数据库进行进程间通信,而不使用更轻量级的合适的机制。或者说,对于常规的进程间通信,不是去采用轻量得多的合适机制,而是将数据库用作消息队列。

镀金(Gold plating):在项目达到最高价值后还继续工作。

内部平台效应(Inner-platform effect):系统可自定义的太多,以至于成为一个软件开发平台的蹩脚的复制品。

输入问题(Input kludge):无法确定和实现对异常输入的处理

接口膨胀(Interface bloat):把一个接口做得过于强大以至于极其难以实现

魔力按键(Magic pushbutton):直接在接口的代码里编写实现,而不使用抽象

竞争风险(Race hazard):输出结果受到事件执行顺序和时机的影响,在多线程环境和分布式系统中可能发生

烟囱系统(Stovepipe system):过度聚集数据和功能,忽视了与其他系统和模块的共享

来自Wikipedia, 自由百科全书

       1、活动记录模式

           我们知道业务逻辑层中的业务逻辑才是系统的核心,那么我们更关注的是业务逻辑或者领域逻辑。因为我们必须关系实体之间的交互。我们如果对领域模型建

模。我们需要使用面向对象的角度去分析需求。   我们先来看看基于对象模式的活动记录模式。

           活动记录模式是在表模块模式的基础上,将表模块的粗粒度的基于数据集上的映射细化到表中行记录的细粒度的映射,并且映射的对象中包含相应的数据库表

中的数据信息,并且包含对象的行为。例如,我们现在如果想将产品表中的产品信息映射到数据库中的表product中的行记录,那么我们需要构建一个product类,该

类中的属性与product表中的列信息一一对应。并且product类中还包含该对象所有的行为。例如CRUD的操作,其他的行为等。

           首先我们需要知道活动记录的优势是什么?首先我的理解就是活动记录模式容器理解,简单,并且目前有很多的框架支持这样的模式。首先就像Linq、Castle

框架都是采用这样的模式。。一般情况下,活动记录模式在关系型模型中可以很好的支持。如果在应用程序中不使用关系型模型来设计业务层的话,那么需要我们人工

来组织,协调活动记录与数据模型之间,其实这个就可以简单的理解为数据映射,一般的ORM框架中都提供这样的功能。

           我们需要知道,如果活动记录模式下的对象发生改变了,那么数据库也得跟着修改,或者数据库表发生改变了,那么你不得不修改对应的活动记录对象及相关代码。

           总而言之,如果我们在使用活动记录模式的过程中如果不能保证对象模型与数据模型之间的对应关系,那么我们将会很快失控,那么领域模型显然能够解决这

样的问题。下面我们来看下活动记录模式的实例。我们还是以购物流程为例。

   public class Order 
   { 
        private int _orderID; 
        public Order(int orderID) 
        { 
            _orderID = orderID; 
        } 

        public int OrderID 
        { 
            get 
            { 
                return this._orderID; 
            } 
            set 
            { 
                this._orderID = value; 
            } 
        } 

        private int  _orderState; 
        public int OrderState 
        { 
            get 
            { 
                return this._orderState; 
            } 
            set 
            { 
                this._orderState = value; 
            } 
        } 

        /// <summary> 
        /// 返回订单对应的所有产品信息 
        /// </summary> 
        /// <returns></returns> 
        public List<Product> Products() 
        { 
            return this.GetProducts(); 
        } 

        private List<Product> GetProducts() 
        { 
            List<Product> lists = new List<Product>(); 
            return lists; 
        } 

        public int Update() 
        { 
            return 0; 
        } 

        public int Delete() 
        { 
            return 0; 
        } 

        public int Insert() 
        { 
            return 0; 
        } 
   }

            我们可以看到区别,从原来的表模式中的通过ADO.NET提供的内存集合表中的形式,修改为通过对象中的属性的形式来保存对象的数据信息,显然这就是表

模式与活动记录模式的最大区别。不过实现的思想上差别不大。

            我们都知道数据库表之间如果有关联的话,那么我们通过的是外键的形式来进行关联,那么我们在活动记录中一般如何来标识某个类对应的外键对象信息呢。

            那么我们在订单中可能会有对应的用户ID,不过在不同的框架中可能对外键对应的对象信息的存储方式会有所不同,有些框架中在外键对象上通过属性的方式

返回对象的实例的应用。简单来说下这2种方式的区别:例如:

   public class Order 
   { 
        private int _orderID; 
        public Order(int orderID) 
        { 
            _orderID = orderID; 
        } 

        public int OrderID 
        { 
            get 
            { 
                return this._orderID; 
            } 
            set 
            { 
                this._orderID = value; 
            } 
        } 

        private int  _orderState; 
        public int OrderState 
        { 
            get 
            { 
                return this._orderState; 
            } 
            set 
            { 
                this._orderState = value; 
            } 
        } 

        private int _userID; 
        public int UserID 
        { 
            get 
            { 
                return this._userID; 
            } 
            set 
            { 
                this._userID=value; 
            } 
        } 
   }

            另外一种形式。直接将User用户的完整对象引用实例返回。

public class Order 
   { 
        private int _orderID; 
        public Order(int orderID) 
        { 
            _orderID = orderID; 
        } 

        public int OrderID 
        { 
            get 
            { 
                return this._orderID; 
            } 
            set 
            { 
                this._orderID = value; 
            } 
        } 

        private int  _orderState; 
        public int OrderState 
        { 
            get 
            { 
                return this._orderState; 
            } 
            set 
            { 
                this._orderState = value; 
            } 
        } 

        private UserInfo _userinfo; 
        public UserInfo User 
        { 
            get 
            { 
                return this._userinfo; 
            } 
            set 
            { 
                this._userinfo=value; 
            } 
        } 
   }

           上面我们看到了活动记录模式的简单使用方式,当然我这里没有说是写出来可以运行的实例代码。只是简单的显示了,使用这些模式可能的用法,当然如果大

家有更好的理解或者用法可以一起交流。当然活动记录模型一般就能满足我们的系统功能,如果说针对业务复杂的领域,那么必须设计领域模型去完成相应的业务逻辑

层的设计。下面我们将来介绍领域模型模式的相关实例。

面向对象设计

贫血的域模型(Anemic Domain Model):仅因为每个对象都要有属性和方法,而在使用域模型的时候没有加入非OOP的业务逻辑

:继承一个工具类的功能,而不是委托给它

调用父类(Call super):需要子类调用父类被重定义的方法

圆还是椭圆问题(Circle-ellipse problem):基于变量的子类化关系进行子类化

循环依赖(Circular dependency):在对象或软件模块中,直接或间接引入循环依赖。

常量接口(Constant interface):使用接口定义常量

上帝对象(God object):在设计的单一部分集中了过多的功能

对象粪池(Object cesspool):复用那些不满足复用条件的对象。对象池是一种管理对象的方法,在重复使用对象前,需要针对对象进行初始化,以避免上次使用后的状态等数据影响下次的使用

不羁的对象(Object orgy):没有成功封装对象,外部可以不受限制地访问它的内部

幽灵(Poltergeists):指这样一些对象,它们唯一的作用就是把信息传给其它对象

顺序耦合(Sequential coupling):指这样一些对象,它们的方法必须要按某种特定顺序调用

悠悠问题(Yo-yo problem):一个结构因为过度碎片化而变得难于理解编程

偶然复杂度(Accidental complexity):向一个方案中引入不必要的复杂度

远隔作用(Action at distance):意料之外的在系统分离的部分之间交互

盲目信任(Blind faith):缺乏对bugfix的校验或对子函数返回值的正确性检查

船锚(Boat anchor):在系统中保留无用的部分

忙等待(Busy waiting):在等待的时候不断占用CPU,通常是因为采用了重复检查而不是适当的消息机制

缓存失败(Caching failure):错误被修正后忘记把错误标志复位

拜物编程(Cargo cult programming):由于对模式的盲目崇拜,在不理解的情况下就使用模式和方法,企图得到好的结果

靠异常编程(Coding by exception):当有特例被发现时才添加新代码去解决

隐藏错误(Error hiding):在显示给用户之前捕捉到错误信息,要么什么都不显示,要么显示无意义的信息

硬编码(Hard code):将对系统环境的假设写入实现中

熔岩流(Lava flow):保留不想要的(冗余的或是低质量的)代码,仅因为除去这些代码的代价太高或是会带来不可预期的结果

循环-switch序列(Loop-switch sequence)在循环结构中使用switch语句来编写连续步骤

魔术数字(Magic numbers):在算法里直接使用数字,而不解释含义

魔幻字符串(Magic strings):直接在代码里使用常量字符串,例如用来比较,或是作为事件代码

自我复制(Repeating yourself):通过不断复制已有代码的模式或代码段进行编码;而非采用once and only once

软代码(Soft code):在配置文件里保存业务逻辑而不是在代码中

面条代码(Spaghetti code):指那些结构上完全不可理解的系统,尤其是因为误用代码结构

霰弹枪手术(Shotgun surgery):开发人员一次性在一个多个实现的代码基中增加功能方法论

拷贝粘贴编程(Copy and paste programming):拷贝现有的代码而不是构造通用的解决方案

黄金大锤(Golden hammer):认为自己最喜欢的解决方案是到处通用的

不可能因素(Improbability factor):认为已知的错误不可能发生

非我所创(Not invented here):拒绝使用组织外的主意或方案,但这也可能是出于版权等原因

这里发明的(invented here):拒绝组织内部实现的创新或解决方案,通常因为对成员没有信心

不成熟的优化(Premature optimization):在编码的早期追求代码的效率,牺牲了好的设计、可维护性、有时甚至是现实世界的效率

转换编程法或巧合编程(Programming by permutation or programming by accident):试图通过连续修改代码再看是否工作的方式来解决问题

重新发明方的轮子(Reinventing the square wheel):已经有一个很好的方案了,又再搞一个烂方案来替代它

银弹(Silver bullet):认为自己最喜欢的技术方案能解决一个更大的问题

测试人员驱动开发(Tester driven development):需求来自bug报告的软件工程

殒石式驱动开发(Meteorite driven development):需求来自任性的不具备专业知识及尊重的上层,以牺牲底层员工生活品质及削弱精神为主轴的开发方式,需求如陨石一般来自天上而不可回避配置管理

依赖地狱(Dependency hell):所依赖产品的版本所导致的问题

DLL地狱:不同版本DLL所带来的问题,包括DLL可见性和多版本问题,在微软的Windows上尤为突出

扩展冲突(Extension conflict):苹果系统在Mac OS X版本之前的不同扩展的问题

JAR地狱:JAR文件不同版本或路径带来的问题,通常是由于不懂类加载模型导致的

学习 设计模式 中无意 看到,觉得比较有意思,故摘要于此,以上内容摘自维基百科

在软件工程中,一个反面模式(anti-pattern或antipattern)指的是在实践中明显出现但

       2、领域模型模式

          我们前面讲解的几类模式,其实说白了都是以数据为中心进行抽象与设计的形式,当然采用这样的形式无疑是以业务中的数据为中心,并

不是关心的业务本身。以数据为核心的设计方法一般流程如下:

          图片 10 一般来说我们目前主流的方式都是这样的顺序来执行。当然通过这样的方式的

确一般的简单应用当然都是没有太大的问题。

          有的时候我们需要同时关系对象的数据与行为,那么显然以数据为核心的情况就会显得力不从心,当然简单的系统时不会有太大的体现,当时当系统的规模上升

到一定的程度时,哪怕添加一些新的需求时,对系统的影响都是致命的。

          领域模型关注的是系统期待的行为及系统正常工作所需要的数据流。一般我们在设计领域模型的时候需要这个领域的专家协助,最后以类的形式呈现出来。当然

领域模型模式中的实现方式,大家都知道的就是有名的DDD(领域驱动设计)。

          领域模型设计的最终目标就是与系统的概念模型匹配起来。我们可以把领域模型看作是概念模型的物理模型。在一个项目中可以说领域模型是最重要的,最关键

的部分。

          领域模型可以看作是一系列对象之间的交互。领域模型中的每一部分都需要用一个带有行为的类来表示。这个怎么理解呢,请看图:

          图片 11 订单信息对象首先会与订单中的产品对象有交互关系,产品项与产品分类有

交互关系。订单信息与用户买家有交互关系,订单的其他信息(物流信息、支付信息等)有交互关系。

          例如我们常说的记录的系统日志,不管是错误日志还是其他的所有系统中的日志,那么我们建议的方式采用AOP的方式来处理。那么我们来看看具体的代码实现:

   //定义接口

   public interface ILog 
   {

       //具体的写日志的方法 
       void WriteLog(); 
   }

    //简单实现

   public class BaseWrite : ILog 
   { 
       #region ILog 成员 

       /// <summary> 
       /// 基本的书写日志的方法 
       /// </summary> 
       public void WriteLog() 
       { 
           try 
           { 
               Write.WriteLog(this); 
           } 
           catch 
           { 

           } 
       } 

       #endregion 
   }

                具体调用的写日志的方法:

   public class Write 
   { 
       public static bool WriteLog(ILog log) 
       { 
           //具体的写如日志的方法。 

           return true; 
       } 
   }

             具体相关的产品类与产品分类对象的使用:

     /// <summary> 
     /// 产品类 
    /// </summary> 
    public class Product : BaseWrite 
    { 
        //产品的相关属性 
        public int ProductID { get;set;} 
        public int ProductName { get;set;} 
        public int ProductClassID { get;set;} 
        public int ProductSort { get;set;} 
        public int ProductIsEnable { get;set;} 
        //产品类相关的方法 
        public List<Product> GetAll() 
        { 
            return new List<Product>(); 
        } 
    } 

    public class ProductClass : BaseWrite 
    { 
       //产品分类相关属性 
        public int ProductClassID { get;set;} 
        public int ProductClassName { get;set;} 
        public int ProductClassCategory { get;set;} 
        public int ProductClassSort { get;set;} 
        public int ProductClassIsEnable { get;set;} 
       //产品分类相关的信息 
        public List<ProductClass> GetAll() 
        { 
            return new List<ProductClass>(); 
        } 
    }

         我们看到了在活动记录模式中会将数据访问层的代码写在该层,但是领域模型中一般不会出现这样的代码。领域模型中只关心跟业务流程相关的内容,具体的数

据持久化之类的内容一概不关心。领域模型中是一系列的对象之间的交互,那么我们可能会关心,如何将领域模型中的这些对象的状态进行保存呢,那么就会牵扯到对

象模型到关系型数据库中持久化的个问题了,在持久化的问题上,我们可能有几种选择,一种是采用现有的ORM框架去实现对象数据的自动持久化,当然这是一种解决

办法。有时候我们是通过手动的方式来进行持久化,可能就不存在这样的问题。

          我们通常在持久化数据的问题上我们希望能做到持久化的透明性,这样就可以说具体的业务层不需要书写持久化的操作代码,当然我们现在设计的时候可能都是

要么是通过特性来实现持久化,或者是通过继承基类的方式来做持久化的操作,那么可能带来如下的问题。

          图片 12

          一般我们知道,一个类如果想不写相应的持久化代码还能实现持久化的话,那么我们只能通过动态的注入持久化代码的方式来实现这样的持久化透明的方案,微

软的EntityFrameWork2.0中的POCO中的ORM方案,就是通过这样的方式来实现的。我们更关心的是代码应该放在何处,是在领域模型中还是领域模型外呢,当然目

前的一些常见的框架中已有实现方案,其中大家熟知的NHibernate就是持久化透明的方式,大家如果感兴趣可以参考NHibernate的实现思路来做。一般对于这种动态

注入代码的这样的方案,这里简单介绍下可能的实现,由于.NET framework 中提供了一个派生自特性类型的代理类,通过代理类来动态的将这个类的相关功能追加到

指定的对象中,这就是所谓的动态代理,当然针对某个特定的类型这样来做,WCF也是通过代理类的方式来实现这样的动态插入的形式。

又低效或是有待优化的设计模式。

六、本章总结

         本章主要是对业务层建模的不同的架构模式进行了相应的总结及简单说明,可能某些地方说明不是特别的清晰,当然我也是将平时自己的业务开发中的一些经验

和总结,部分内容是参考以前看的书上的内容,不足之处还请大家多多的指点,还有请感兴趣的朋友一起交流领域模型的设计,包括持久化的透明的实现方案等,欢迎

大家多提意见和建议。本人抱着学习和宁缺毋滥的原则,写好每一篇,可能看过这方面资料的同仁当温习下相关内容,没有看过同仁希望对你们有帮助,那就是我最大

的动力。

Andrew Koenig在1995年造了anti-pattern这个词,灵感来自于GoF的《设计模式》一书。而

七、系列进度

这本书则在软件领域发明了“设计模式”(design pattern)一词。三年后antipattern因

        前篇

      1、系统架构师-基础到企业应用架构系列之--开卷有益

      2、系统架构师-基础到企业应用架构-系统建模[上篇]

      3、系统架构师-基础到企业应用架构-系统建模[中篇](上)

      4、系统架构师-基础到企业应用架构-系统建模[中篇](下)

      5、系统架构师-基础到企业应用架构-系统建模[下篇]

      6、系统架构师-基础到企业应用架构-系统设计规范与原则[上篇]

      7、系统架构师-基础到企业应用架构-系统设计规范与原则[下篇]

      8、系统架构师-基础到企业应用架构-设计模式[上篇]

      9、系统架构师-基础到企业应用架构-设计模式[中篇]

      10、系统架构师-基础到企业应用架构-设计模式[下篇]

《AntiPatterns》这本书而获得普及,而它的使用也从软件设计领域扩展到了日常的社会互

       中篇

      11、系统架构师-基础到企业应用架构-企业应用架构

      12、系统架构师-基础到企业应用架构-分层[上篇]

      13、系统架构师-基础到企业应用架构-分层[中篇]

      14、系统架构师-基础到企业应用架构-分层[下篇]

      15、系统架构师-基础到企业应用架构-表现层

      16、系统架构师-基础到企业应用架构-服务层

      17、系统架构师-基础到企业应用架构-业务逻辑层

      18、系统架构师-基础到企业应用架构-数据访问层

      19、系统架构师-基础到企业应用架构-组件服务

      20、系统架构师-基础到企业应用架构-安全机制

动中。按《AntiPatterns》作者的说法,可以用至少两个关键因素来把反面模式和不良习惯

       后篇

      21、单机应用、客户端/服务器、多服务、企业数据总线全解析

      22、系统架构师-基础到企业应用架构-单机应用(实例及demo)

      23、系统架构师-基础到企业应用架构-客户端/服务器(实例及demo)

      24、系统架构师-基础到企业应用架构-多服务(实例及demo)

      25、系统架构师-基础到企业应用架构-企业数据总线(实例及demo)

      26、系统架构师-基础到企业应用架构-性能优化(架构瓶颈)

      27、系统架构师-基础到企业应用架构-完整的架构方案实例[上篇]

      28、系统架构师-基础到企业应用架构-完整的架构方案实例[中篇]

      29、系统架构师-基础到企业应用架构-完整的架构方案实例[下篇]

      30、系统架构师-基础到企业应用架构-总结及后续

、错误的实践或糟糕的想法区分开来:

八、下篇预告

        下一篇我们将会开始讲解软件设计中最重要也是最基本的技能-设计模式,希望大家多多提出已经,后面3篇我们将会讲解如何在项目中使用设计模式及使用设计

模式需要注意的事项,将会举例说明每个设计模式可能出现的场景。希望大家持续关注!

* 行动、过程和结构中的一些重复出现的乍一看是有益的,但最终得不偿失的模式

* 在实践中证明且可重复的清晰记录的重构方案

很多反面模式只相当于是错误、咆哮、不可解的问题、或是可能可以避免的糟糕的实践,它

们的名字通常都是一些用反话构成的词语。有些时候陷阱(pitfalls)或黑色模式(dark

patterns)这些不正式的说法会被用来指代各类反复出现的糟糕的解决方法。因此,一些有

争议的候选的反面模式不会被正式承认。

[1. 已知的反面模式]

[1.1 组织结构的反面模式]

* 从天而降的责任(accidental ownership):雇员们接手了一个与当前系统完全无关的系

统,在没有合适的训练、学习或关心下就得维护它(在90年代的电话->网络管理员中很常

见)

* 分析麻痹(Analysis paralysis):在项目的分析阶段付出的努力太少

* 引擎室里的船长(Captain in the engine room):团队带头人把时间和精力全花在技术

问题上,没有人开船

* 摇钱树(cash cow):盈利的老产品通常会导致对新产品的自满

* 持续退化(Continuous obsolescence):不成比例地投入精力把系统移植到新环境下

* 经费转移(Cost migration):项目经费转移到弱势的部门或商业伙伴那里

* 危机模式(Crisis mode)或救火模式(firefighting mode):硬是等到火烧屁屁的时候

才去解决问题,结果是每个问题都成了危机问题

* 委员会设计(Design by committee):很多人同时进行设计,却没有统一的看法

* 委员会扩张(Escalation of commitment):明知错了还不能收回之前的决定

* 英雄模式(Hero-mode):长期依赖成员的英雄式的努力来满足不可能的任务期限,同时

又忽视从一开始就没有注重软件品质带来的损失

* 我早就说过(I told you so):某人之前的警告没得到重视,事后又被人发现是正确的

,并引起了关注

* 主观管理(Management by hope):认为平静的表象就代表一切顺利

* 通过忽视的管理(Management by neglect):过多地委任

* 用数字管理(Management by numbers):过于关注非本质而又不易取得的数字指标

* Perkele管理(Management by perkele):用完全听不进异议的独裁作风进行管理

* 思考管理(Management by wondering):希望一个团队定义自己的目标,然后考虑他们

要做什么

* 精神危险(Moral hazard):不让做决定的人知道他的决定会带来什么结果

* 蘑菇管理(Mushroom management):有事也不通知雇员或是错误地通知(像种蘑菇一样

放在黑地里施肥)

* 不是这里发明的(Not invented here):拒绝使用组织外的主意或方案

* 精益求精(Polishing the polish):把已经完成的项目交给下属去做,禁止他们做其它

的事,又报怨他们低效率

* 规模爬行(另外两个类似的词是复杂度陷阱和功能主义者):不适当控制项目的规模的增

* 烟囱(Stovepipe):结构上支持数据主要在上下方面的流动,却禁止平行的通信

* 客户套牢(Vendor lock-in):使一个系统过于依赖外部提供的部件

* 小提琴弦组织(Violin string organization):高度调整和裁减却没有灵活性的组织

[1.2 项目管理的反面模式]

* 死亡征途(Death march):除了CEO,每个人都知道这个项目会完蛋。但是真相却被隐瞒

下来,直到大限来临

* 拖后腿的无知(Heel dragging blindness):项目经理的无知拖了后腿。出于某些动机

,员工趋向于减少努力来延长项目时限。例如,他们是按时间(而非结果)付费,又没有

能顺利转移过去的后续项目

* 烟和镜(Smoke and mirros):展示还没完成的函数会是怎样

* 软件膨胀(Software bloat):允许系统的后续版本使用更多的资源

[1.3 团队管理的反面模式]

* 缺席的经理(Absentee manager):经理长时间不出现的情况

* Cage match negotiator:经理用“不惜一切代价也要取胜”的方式来管理

* Doppelganger:某些经理或同事刚才还平易近人,过了一下就变得难于相处

* 无底洞(Fruitless hoops):经理在做出决定前要求大量的(通常是无意义的)数据

* 黄金小孩(Golden child):依据人情而不是实际的表现,特殊的责任、机会、认可、奖

励被给予团队成员

* 无头苍蝇(Headless chicken):经理总是处于恐慌中

* 领导而非经理(Leader not manager):经理是一个好的领导,却缺乏行政和管理能力

* 管理克隆(Managerial cloning):经理对所有人的雇佣和指导的方法都是一样的:像他

们的老板

* 经理而非领导(Manager not leader):经理能胜任行政和管理职责,却缺乏领导能力

* 指标滥用(Metric abuse):恶意或是不适当地使用指标

* 好好先生(Mr. nice guy):经理想成为每个人的朋友

* 鸵鸟(Ostrich):有些人员整天做些空洞的事情却忽视那些需要在最后期限前被解决的

事情还以为会没事,通常更希望看起来很忙,但实际上会浪费和用尽时间

* 平民英雄(Proletariat hero):口头上称赞普通员工技术如何如何之牛,实际上管理层

只是把他们当成棋子,目的是有借口更多的摊派任务以及增加生产目标

* 得势的暴发户(Rising upstart):指这样一些潜在的新星,他们急不可耐地想要爬上去

,不愿花费量些必要的时间去学习和成长

* 海鸥管理(Seagull management):飞进来,弄得鸡飞狗跳、一片儿狼藉,然后就拍拍屁

股走人

* 懦弱的执行者(Spineless executive):管理者没有勇气来面对当前形势、来承担责任

、或是来保护自己的下属

* 三个脑袋的骑士(Three-headed knight):没有决断力的管理者

* 终极武器(Ultimate weapon):有些人完全依赖自己的同事或是组织,好像他们自己只

是一个导体,把问题全部传给别人

* 热身状态(Warm bodies):指有些员工几乎不能达到工作的最低要求,因此不断地从一

个项目转到另一个项目,或是从一个团队换到另一个团队。

* 只会说是的人(Yes man):指一些管理者当面对CEO说的每句话都说是,CEO不在的情况

下他可能说的又是另一回事

[1.4 分析方式的反面模式]

* 尿布说明(Napkin specification):把给开发团队的功能或技术说明写在尿布上(即是

说,不正式,又缺乏细节),和根本就没有说明一样

* 假需求(Phony requirements):所有的需求都是通过网络会议或是电话通知给开发团队

的,没有任何功能、技术上的说明或其它说明文档

* 火箭说明(Retro-specification):在项目已经启动之后才开始写技术、功能说明

[1.5 通常的设计反面模式]

* 抽象倒置(Abstraction inversion):不把用户需要的功能直接提供出来,导致他们要

用更上层的函数来重复实现

* 用意不明(Ambiguous viewpoint):给出一个模型(通常是OOAD,面向对象分析与设计

)却没有指出用意何在

* 大泥球(Big ball of mud):系统的结构不清晰

* 斑点(Blob):参考上帝对象(God object)

* 气体工厂(Gas factory):复杂到不必要的设计

* 输入问题(Input kludge):无法指出和实现对不正确的输入的处理

* 接口膨胀(Interface bloat):把一个接口做得过于强大以至于极其难以实现

* 魔力按键(Magic pushbutton):直接在接口的代码里编写实现,而不使用抽象

* 竞争危机(Race hazard):无法知道事件在不同顺序下发生时产生的结果

* 铁轨方案(Railroaded solution):由于没有预见和在设计方面欠缺灵活性,提出的方

案即使很烂,也成了唯一选择

* 重复耦合(Re-coupling):不必要的对象依赖

* 烟囱系统(Stovepipe system):根本就不能维护的被病态的组合在一起的组件

* (Staralised schema):指这样的数据库方案,包含了两种用途的表,一是通用的,另

一种是有针对性的

[1.5.1 面向对象设计的反面模式]

* 贫血的域模型(Anemic Domain Model):仅因为每个对象都要有属性和方法,而在使用

域模型的时候没有加入非OOP的业务逻辑

* (BaseBean):继承一个工具类,而不是代理它

* 调用父类(Call super):需要子类调用父类被重载的方法

* 圆还是椭圆问题(Circle-ellipse problem):基于变量的子类化关系进行子类化(原句

是Subtyping variable-types on the basis of value-subtypes)

* 空子类的错误(Empty subclass failure):创建不能通过“空子类测试”的类,因为它

和直接从它继承而来没有做其它任何修改的子类表现得不同

* 上帝对象(God object):在设计的单一部分(某个类)集中了过多的功能

* 对象粪池(Object cesspool):复用那些不满足复用条件的对象

* 不羁的对象(Object orgy):没有成功封装对象,外部可以不受限制地访问它的内部

* 幽灵(Poltergeists):指这样一些对象,它们唯一的作用就是把信息传给其它对象

* 顺序耦合(Sequential coupling):指这样一些对象,它们的方法必须要按某种特定顺

序调用

* 单例爱好者(Singletonitis):滥用单例(singleton)模式

* 又TMD来一层(Yet Another Fucking Layer):向程序中添加不必要的层次结构、库或是

框架。自从第一本关于编程的模式的书出来之后这就变得很普遍。

* 唷唷问题(Yo-yo problem):一个结构(例如继承)因为过度分裂而变得难于理解

[1.6 编程方面的反面模式]

* 意外的复杂度(Accidental complexity):向一个方案中引入不必要的复杂度

* 积累再开火(Accumulate and fire):通过一系列全局变量设置函数的参数

* 在远处行动(Action at distance):意料之外的在系统分离的部分之间迭代

* 盲目信任(Blind faith):缺乏对bugfix或子函数返回值的正确性检查

* 船锚(Boat anchor):在系统中保留无用的部分

* bug磁铁(Bug magnet):指很少被调用以至于最容易引起错误的代码,或是易出错的构

造或实践

* 忙循环(Busy spin):在等待的时候不断占用CUP,通常是因为采用了重复检查而不是适

当的消息机制

* 缓存失败(Caching failure):错误被修正后忘记把错误标志复位

* 货运崇拜编程(Cargo cult programming):在不理解的情况下就使用模式和方法

* 检查类型而不是接口(Checking type instead of interface):仅是需要接口符合条件

的情况下却检查对象是否为某个特定类型。可能导致空子类失败

* 代码动力(Code momentum):过于限制系统的一些部分,因为在其它部分反复对这部分

的内容做出假设

* 靠异常编程(Coding by exception):当有特例被发现时才添加新代码去解决

* 隐藏错误(Error hiding):在显示给用户之前捕捉到错误信息,要么什么都不显示,要

么显示无意义的信息

* 异常处理(Expection handling):使用编程语言的错误处理系统实现平常的编程逻辑

* 硬编码(Hard code):在实现过程中对系统环境作假设

* 熔岩流(Lava flow):保留不想要的(冗余的或是低质量的)代码,仅因为除去这些代

码的代价太高或是会带来不可预期的结果

* loop-switch序列(Loop-switch sequence)使用循环结构来编写连续步骤而不是switch

语句

* 魔幻数字(Magic numbers):在算法里直接使用数字,而不解释含义

* 魔幻字符串(Magic strings):直接在代码里使用常量字符串,例如用来比较,或是作

为事件代码

* 猴子工作(Monkey work):指在一些代码复用性或设计上很差的项目中的反复出现的支

持性的代码。通常会被避免或是匆忙完成,因此易于出错,有可能会很快变为bug磁铁。

* Packratting:由于长时间不及时释放动态分配的内存而消耗了过量的内存

* 类似保护(Parallel protectionism):随着代码变得复杂和脆弱,很容易就克隆出一个

类似的的结构,而不是直接往现有的结构中添加一些琐碎的属性

* 巧合编程(Programming by accident):尝试用试验或是出错的方式解决问题,有时是

因为很烂的文档或是一开始就没把东西搞清楚

* 馄饨代码(Ravioli code):系统中有许多对象都是松散连接的

* 软代码(Soft code):在配置文件里保存业务逻辑而不是在代码中

* 面条代码(Spaghetti code):指那些结构上完全不可理解的系统,尤其是因为误用代码

结构

* 棉花里放羊毛(Wrapping wool in cottom):常见的情况是某些类的方法只有一行,就

是调用框架的代码,而没有任何其它有用的抽象

[1.7 方法学上的反面模式]

* 拷贝粘贴编程(Copy and paste programming):拷贝(然后修改)现有的代码而不是假

造通用的解决方案

* 拆除(De-factoring):去掉功能,把它转化成文档的过程

* 黄金大锤(Golden hammer):认为自己最喜欢的解决方案是到处通用的(见:银弹)

* 未必有之事(Improbability factor):认为已知的错误不会出现

* 低处的果子(Low hanging fruit):先处理更容易的问题而忽略更大更复杂的问题。这

个问题有些类似于这种情况:科学、哲学和技术上的发现在早期都比较容易得到,一旦问

题已经被人研究过了,再要有所创新就难了

* 不是这里做的(Not built here):见“重新发明轮子”、“不是这里发明的”

* 不成熟的优化(Premature optimization):在编码的早期追求代码的效率,牺牲了好的

设计、可维护性、有时甚至是现实世界的效率

* 转换编程法(Programming by permutation):试图通过连续修改代码再看是否工作的方

式来解决问题

* 重新发明方的轮子(Reinventing the square wheel):已经有一个很好的方案了,又再

搞一个烂方案来替代它

* 重新发明轮子(Reinventing the wheel):无法采纳现有的成熟的方案

* 银弹(Silver bullet):认为自己最喜欢的技术方案能解决一个更大的问题

* 测试人员驱动开发(Tester driven development):软件工程的需求来自bug报告

[1.8 测试反面模式]

* 敌意测试(hostile testing):对抗实际的开发方案,使用过量的测试

* 自身测试(Meta-testing):过度设计测试过程以至于它本身都需要测试,也被称为“看

门人的看门人”

* 移动标的(Moving target):连续修改设计和实现从而逃避现现有的测试过程

* 奴隶测试(Slave testing):通过发匿名电邮或贿赂的方式控制测试人员,从而达到股

东的要求

[1.9 配置管理反面模式]

* 依赖的地狱(Dependency hell):需要的产品的版本导致的问题

* 路径地狱(Classpath hell):和特定库有关的问题,例如依赖关系和要满足程序运行

所需的版本

* 扩展冲突(Extension conflict):苹果系统在Mac OS X版本之前的不同扩展的问题

* DLL地狱(DLL hell):不同版本带来的问题,DLL可见性和多版本问题,在微软的

Windows上尤为突出

* JAR地狱(JAR hell):JAR文件不同版本或路径带来的问题,通常是由于不懂类加载模

型导致的

本文由星彩网app下载发布于计算机编程,转载请注明出处:反面情势,基础到集团应用架构

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。