面向对象的概念和术语总结和UML类图说明

2010年2月7日 admin 1 条评论

最近打算给开发和QA的同学介绍一下面向对象和UML相关的内容。这是第一篇,介绍主要面向对象的基础概念和UML类图的绘制。

概念:类似对象的一种软件抽象,创建对象的模板。

UML图:属性和操作之前可附加一个可见性修饰符。加号(+)表示具有公共可见性。减号(-)表示私有可见性。#号表示受保护的可见性。省略这些修饰符表示具有package(包)级别的可见性。如果属性或操作具有下划线,表明它是静态的。在操作中,可同时列出它接受的参数,以及返回类型。

kmstheme

接口

概念:定义了一套内聚行为的一个或多个操作特性标记的集合。接口是确保送耦合的一种强大的方法。它们允许类参与一套共同的功能集,除了支持接口意外,不需要别的类知道任何有关他的事情。接口的设计要遵循“接口分离原则”,参见什么是面相对象设计的SOLID原则(s)

UML图:接口的UML图展现的样式会有几种变化,但内容都是一样的。interface

注:在StarUML中可以通过选择Interface元素的Format->【Stereotype Display】、【Suppress Attributes】、【Suppress Operations】来调整。

interface_ui

联系(Association)

概念:实体之间的一个结构化关系表明对象是相互连接的。箭头是可选的,它用于指定导航能力。如果没有箭头,暗示是一种双向的导航能力。

UML图:

image

  • 方向性。开口箭头指出关联的方向。只有一个开口箭头的关联是单向的:它仅可以在一个方向(箭头的方向)上移动。没有箭头时,表示关联是可以在两个方向上移动。
  • 标签。标签是可选的,一般有一到两个词组成,用来描述关联。
  • 多重性(Multiplicity)。关联的多重性在线的两端标出,每个方向有一个多重性指示器。

聚合(Aggregation)

概念:有时对象会有其他对象组成。例如,飞机由机身、机翼、引擎、起落架等组成。这些全部都是聚合这个概念的例子,它表示“is part of”关系。

UML图:

uml-aac-diff-02.png

class Node
{
  private:
    vector<Node*> itsNodes;
};
     上述代码只有当子节点不会成为父节点的父节点时(即,必须是树结构,不能是图结构),才能称之
为聚合。

组合(Composition)

     概念:组合是更强形式的聚合,其中“整体”负责部分,每个“部分”对象也仅与一个整体对象联系。例如,
在任何给定时间,引擎是且仅是飞机的一部分。而且,除了飞机以外,其他对象都不能直接与引擎对象发
生交互。
        UML图:
uml-aac-diff-03.png
class Car
{
  public:
    virtual ~Car() {delete itsCarb;}
  private:
    Carburetor* itsCarb
};

依赖(Dependency)

概念:对象之间存在临时关系,只有一个原因,它们可能会相互协作。一个对象与另一个对象进行协作,它需要了解这个对象。这意味着两个对象之间必须存在对象关系或part-of关系。当两个对象之间不存在持久关联的时候,我们需要在两个类之间建立依赖。

UML图:

dependency

泛化(Generalization)

概念:表示一个更泛化的元素和一个更具体的元素之间的关系。

UML图:

image

AbstractKmsTheme被标记为抽象的(名字是斜体)。

实现(Realization)

概念:指定两个实体之间的一个合同。换言之,一个实体定义一个合同,而另一个实体保证履行该合同。

UML图

image

总结面向对象的概念和术语汇总表

术语 描述
Abstract Class抽象类 不能实例化的类
Abstraction抽象 一个项目(可能是类或者操作)的本质特征
Aggregation聚合 两个类或者组件之间的关系,定义为“is part of”
Association关联 两个类或者对象之间的关系
Attribute属性 类了解的东西(数据/信息)
Cardinality基数 表示“有多少”的概念
Class类 类似对象的一种软件抽象,创建对象的模板
Cohesion内聚 封装单元(如组件或者类)的相关程度
Component组件 一种内聚功能单元,可以独立开发、发布、由其他组件编辑组成更大的单元。
Composition组合 强类型的聚合,其中“整体”完全负责各个组成部分,每个部分对象仅与一个“整体”对象相关联
Concrete Class具体类 可以从中实例化对象的类
Coupling耦合 两个项目之间的依赖程度
Generalization泛化 表示一个更泛化的元素和一个更具体的元素之间的关系。
Inheritance继承 定义为“is a”或者“is like”的关系
Instance实例 一个对象,它是某个类的一个示例
Instantiate实例化 从类定义中创建对象
Interface接口 定义了一套内聚行为的一个或多个操作特性标记的集合
Message消息 请求星系或者执行任务
Messaging消息传递 对象之间通过发送消息相互协作的过程
Method方法 有执行值操作的类实现的一个过程(与结构化编程中的函数相似)
Multiple Inheritance多重继承 直接继承自一个以上的类
Object对象 基于类定义的人物、地点、事件、事物等等
Optionality选择性 概念“你需要它吗?”
Override 在子类中重新定义属性和/或方法,以使它们与父类中的定义有区别
Pattern 在考虑相关因素的情况下,通用问题的一个可行性解决方案
Polymorphism多态 不同的对象可以以不同的方式响应同一消息,使对象可以交互而不需要知道确切的类型
Property 在UML2中,是一个命名的值,例如,属性和关联,包括组合,指定元素(例如类或者组件)的一个特征。在Java中,属性的组合包括Getter和Setter
Single Inheritance多重继承 仅从一个类直接继承
Stereotype构造型 建模元素的一种通用用法
Subclass子类 继承自另一个类的类
Superclass父类 另一个类从中继承的类

参考

The Ojbect Primer中文版第二章

UML中的联系、聚合与组合的区别

全面认识UML类图元素

分类: 软件设计 标签: ,

StarUML——免费好用的UML工具

2010年2月7日 admin 没有评论

别看UML工具有一大堆,好用而且免费的真是少之又少。StarUML 做的非常不错,所以推荐给大家使用。

用例图

类图

ER图

StarUML默认不支持ER图,需要通过扩展来支持,步骤如下:

  • 通过StarUML的Modules下载页面下载ER Diagram模块
  • 将zip包释放到StarUML的安装路径(例如,C:\Program Files\StarUML\modules)的modules目录下。
  • 重启StarUML即可!

StarUML主页

StarUML下载页面

其他相关工具

OpenProj —MS Project的开源替代品

分类: 应用软件 标签: ,

转载:Top 10 Internet Startup Scalability Killers

2010年2月6日 admin 没有评论

原文地址 http://gigaom.com/2009/12/20/top-10-internet-startup-scalability-killers/

  • Thinking Scalability is just about technology 认为Scalability 只是一个技术问题
  • Overuse of Synchronous calls 过度使用同步调用
  • Failure to weed or seed soon enough 不能够快速消除表现欠佳者并培养优秀的人才
  • Inappropriate use of databases 不合理地使用数据库
  • Cesspools instead of swim lanes 未能实现对故障以及失败的隔离
  • Reliance on Vertical scale 依赖纵向的扩展
  • Failure to Learn from History 不能从历史的失败中吸取教训
  • Changing Development methodologies to fix problems通过改变开发的方式方法来解决问题
  • Too little caching, too late 缓存的使用太少或者太晚
  • Overreliance on Third parties to scale过度依赖第三方来实现可扩展

更多的内容可以参考近期出版的新书“The Art of Scalability

分类: 可扩展性设计 标签:

软件开发沉思录阅读笔记一

2010年2月6日 admin 没有评论

软件开发沉思录简介

从编程技术到项目管理,Roy Singham、Martin Fowler、Rebecca Parsons等来自ThoughtWorks的思想领袖通过本书中的13篇美文,将自己多年沉思和实践所得倾囊相授,引领你走向敏捷软件开发的成功之路。
本书内容丰富,涵盖了软件开发的各个阶段,既包含DSL、SOA、多语言开发和领域驱动设计等热门主题,也有对象设计、一键发布、性能测试和项目管理等方面的经验之谈和独到见解。不论你是开发人员还是项目管理人员,都将从本书中获益匪浅。

第九章 对象健身操

  • 优秀设计背后的核心概念其实并不高深。比如内聚性、松耦合、零重复、封装、可测试性、可读性以及单一职责。这七条评判代码质量的原则就已经被广泛接受了。然而真正困难的是如何把这些概念付诸实践。理解了封装就是隐藏“数据、实现细节、类型、设计或者构造”,这只是设计出良好封装代码的第一步而已。
  • 更为严格的编码标准。
    • 方法只使用一级缩进
    • 拒绝使用else关键字
    • 封装所有的原生类型和字符串
    • 一行代码只有一个“.”运算符
    • 不要使用缩写
    • 保持实体对象简单清晰
    • 任何类型中的实例变量都不要超过两个
    • 使用一流的集合
    • 不使用任何Getter/Setter/Property
      • 这条规则通常被描述为“讲述而不要询问”(“Tell, dont’t ask”)
  • 如果努力地拥抱简单性,那么开发过程会快乐得多。
分类: 软件设计 标签:

敏捷思考0.1版

2010年1月31日 admin 1 条评论

最近“如何在让开发团队敏捷起来”的话题时常被公司的兄弟开发团队讨论起来,而且有些团队也开始进行实践,并获得了第一手的体验和经验。这两天也在不断思考如何让自己的开发团队如何敏捷,这篇文章就是用来记录相关的内容,不过自己在这方面额内容涉猎不多,所以把这次敏捷思考定位到0.1版。

变更的成本

软件变更的成本实际上是操纵这软件开发的多种方面。下面这张图描述的是瀑布模型中的变更成本曲线。

未命名

                                               图一

举例来说,如果是犯了需求错误,并在需求阶段发现它,弥补的成本不是很高,仅需要修改需求模型就可以;如果在设计阶段才发现需求的错误,不但需要修改需求模型,基于错误需求模型的相关设计也必须重新评估、设计;在编程和测试阶段发现需求的错误,导致的变更成本就更大了。所以在传统(瀑布或者迭代)开发模式(如下图)中,通过对软件开发过程进行细分,完善流程和规范,尽量保证前置阶段的输出是正确的(通过文档输出、设计评审等手段),目的就是把变更的成本降到最低。

image

但是,我们的现状是:

  • 项目流程过于死板,瀑布式开发
  • 问题暴露延后,测试压力很大
  • 各自开发,没有结对编程,造成能力壁垒
  • 需求变化带来的负面影响
  • 团队不统一认识造成的浪费
  • 项目评估不准,周期长
  • 等待造成的浪费
  • 没有安排优先级造成的浪费
  • …….

注以上内容来自公司其他团队的分享。

那大家不经要问这个是为什么?我自己的回答是以下几点:

首先,在传统模式下每个阶段的工作都由专门角色来负责,需求分析阶段-需求分析师;设计阶段-架构师或开发人员;开发阶段-开发工程师;测试阶段-测试工程师。在这种分工和流程设计的环境下,项目中的每中角色只能接触有限的上下文,每个阶段工作只有有限的人员参与,每个阶段工作的质量直接受限于主要负责人的经验、知识、能力等等。

还有,延迟的结果输出,导致最后的结果设想存在很长时间段的“幻想”期。无论是需求文档、设计文档、测试文档,只有在实际结果产出以后才能得到验证,甚至有些需求理解不符合业务方的期望的问题直到软件在进行客户体验或者上线以后才能被发现。

最后,还有就是主动或者被动地选择低效的沟通方式。人们习惯依赖最低效(至少不是最高效)和繁琐的沟通方式——文档来进行沟通。通过文档进行沟通存在很多的弊端:一、制作繁琐,不但需要文字描述,有时候还需要图文并茂;二、文档输出的质量也不够稳定,很依赖撰写者的描述能力,三、文档的理解也需要耗费时间和资源,理解过程中存在失误。

对敏捷的理解

如果敏捷是要解决传统(瀑布或者迭代)开发模式的弊端就必须解决以下问题:

一、将每个阶段的变更最小化,也就是说要使得需求分析、设计、编码和测试最大程度地正确。如何达到呢?首先,就要求每个阶段的负责人具备更高的能力,这是一个答案,但也不是一个答案,因为个人能力的提升需要一个过程。其次,就是利用“集体智慧”,无论是需求、设计、测试都要充分表达出自己的想法,例如,需求分析师要负责向开发人员和测试人员说明为什么要有这个需求;这个需求是如何实现业务方的需求的;将来业务可能的需求扩展有哪些,和现在需求的关系如何,如何应对将来的发展。开发人员和测试人员会站在各自的角度以及利用自己的专业知识给出需求设计、建模的意见和建议。一句话“三个臭皮匠顶个诸葛亮”,用“集体智慧”去解决瓶颈问题。还有,就是充分的沟通,想必大家都知道沟通的重要性这里就不在叙述了。

敏捷宣言中有若干条价值观或者原则与此相关

原则:

业务人员和开发者应该在整个项目过程中始终朝夕在一起工作。

对卓越技术与良好设计的不断追求将有助于提高敏捷性。

围绕斗志高昂的人进行软件开发,给开发者提供适宜的环境,满足他们的需要,并相信他们能够完成任务。

每隔一定时间,团队都要总结如何更有效率,然后相应地调整自己的行为。

二、减少变更的成本,也就是说当变更无法避免的时候,如何让变更成本最小化。用“运动是绝对的,静止是相对的”这句话套在这里就是“变更是绝对的,不变更是相对的”。如果图一中的变更成本曲线是指数型的话,我们就要想办法把变更成本的曲线来加以改变,下面这张图是理想的变更成本曲线图。

3

那么这种变更成本曲线如何实现呢?我们来数一数手中的武器:

需求的武器有:

  • 界面原型
  • ……,我不熟悉需求分析工作,实在想不出啥

开发的武器有:

  • 单元测试
  • 重构
  • 持续集成
  • 代码生成工具
  • ……

测试的武器有:

  • 自动化测试
  • ……,测试的工作我同样不熟悉,呵呵

但最最重要的还是那个“不是答案的答案”——即要求提高需求分析人员的概念领域建模和业务流程建模能力等等;设计师的面向对象设计能力、架构设计能力;测试人员的测试分析、设计能力:-)。我相信这些能力才是控制变更成本的最有效工具。

不断的观察我们实际的变更成本曲线,从而不断的强大我们的武器、提升我们的能力,最后目标只有一个“面对变更,我们不但无所畏惧,而且自信满满”

敏捷宣言中有若干条价值观或者原则与此相关

原则:

我们欢迎需求的变化,即使在开发后期。敏捷过程能够驾驭变化,保持客户的竞争优势。

简单——尽可能减少工作量的艺术至关重要。

最好的架构、需求和设计都源自自我组织的团队。

三、让变更提早被发现,敏捷开发中倡导的“频繁交付新的软件版本,将尽早将尽量小的可用的功能交付使用,并在整个项目周期中持续改善和增强”能在很大程度上让变更提早被发现,并将变更的成本最小化。敏捷宣言中有若干条价值观或者原则与此相关

价值观:

可以工作的软件重于求全责备的文档。

原则:

经常交付可以工作的软件,从几星期到几个月,时间尺度越短越好。

可以工作的软件是进度的主要度量标准。

对于这点想在日后的文章中再展开叙述。

四、团队间高效沟通和诚意合作。敏捷开发倡导并在某种程度上神话了某些工具,例如白板,“业务人员和开发者应该在整个项目过程中始终朝夕在一起工作”,而实际上只要我们能够了解这些工具或者环境准备都是为了减少沟通障碍、提升沟通效率和效果,就能破除对这些表面功夫的迷信。对于这点也想在日后的文章中再展开叙述。

敏捷尝试计划

主要的敏捷执行流程大致如下图所示

agile_process

下面是几个主要内容的说明:

周期0指的是进入项目流程后的一个阶段,进行的内容包括了最初的分析、建模、分析。这个阶段进行的内容涉及到高层的需求分析、需求建模、设计建模、测试分析等工作,工作内容的范围、难度存在比较大的差异,时间跨度可能有几个小时到1-2周,强烈不建议投入更多的时间,因为那样会有过度建模的危险,另外过度延长可交付软件的交付周期也会导致变更机率的加大。

周期1至n进行的是详细建模、详细设计、开发、测试等一系列工作。在一次发布的周期里,建模工作经常会是分钟级别。产品经理、需求分析师、开发、测试(我们的工作模式很难让业务方一起参与到软件开发的流程中)一起分析正在处理的需求,一起通过白板或者草稿上绘制一张草图,然后产品经理、需求分析师、开发、测试各自进行需求分析、需求建模、设计、开发、测试分析等工作。需求建模和设计建模可以采取高效的工具来进行,例如,需求分析师是可以通过Pencil之类的工具完成界面原型的设计,而开发工程师可以通过UML来描述类图和时序图,从而将主要的设计思想和内容表达出来,至于面面具到的文档可以留到后续的工作中来完善。团队在实现阶段(开发和测试)会花费大量时间。在开发中,遵循和使用TDD、重构、或者代码生成可以有效提升开发效率,而在测试阶段这样敏捷的工具和方法就为数不多了!

在周期0至周期n的过程中,将涉及的评审工作也根据迭代周期穿插进行。在完成了项目后需求、开发、测试工作人员可以根据最终的工作结果完善文档(这些文档对于我们团队在后续的开发、维护工作中还是至关重要的)。

总结

以上就是这段时间对“敏捷开发”的思考和整理,由于没有多少直接的敏捷实践经验,更多的内容要等待通过以后的实践工作来体会和总结。

参考资料

瀑布模型维基百科定义

瀑布模型是由W.W.Royce1970年最初提出的软件开发模型,在瀑布模型中,开发被认为是按照需求分析设计实现测试 (确认), 集成,和维护坚定地顺畅地进行。

在最初的文章中,Royce提倡重复地使用瀑布模型,以一种迭代的方式。但是,大多数人并不知道这一点,一些人也不相信它能够作为一种真实世界的过程使用。在实践中,过程很少能够以纯线性的方式进行。 通过回到前面的阶段或改变前一阶段的结果的迭代是非常普遍的。讽刺的是,在Royce 1970年的那篇文章中他讲述这种模型的目的是作为例子来说明这种模式是有缺陷的、不能工作的。事实上,软件开发相关文章中对这个名词的大量引用正是对这个广泛流行的软件开发做法的一种评判。

瀑布模型(Waterfall Model)最早强调系统开发应有完整之周期,且必须完整的经历周期之每一开发阶段,并系统化的考量分析与设计的技术、时间与资源之投入等,因此瀑布模型又可以称为‘系统发展生命周期’(System Development Life Cycle, SDLC)。由于该模式强调系统开发过程需有完整的规划、分析、设计、测试及文件等管理与控制,因此能有效的确保系统品质,它已经成为业界大多数软件开发的标准(Boehm, 1988)。

敏捷开发维基百科定义

敏捷软件开发又称敏捷开发,是一種從1990年代開始逐渐引起广泛关注的一些新型软件开发方法,是一种应对快速变化的需求的一种软件开发能力。它们的具体名称、理念、过程、术语都不尽相同,相对于「非敏捷」,更强调程序员团队与业务专家之间的紧密协作、面对面的沟通(认为比书面的文档更有效)、频繁交付新的软件版本、紧凑而自我组织型的团队、能够很好地适应需求变化的代码编写和团队组织方法,也更注重做为软件开发中人的作用。

分类: 敏捷 标签: ,

Daniel-Journey Weekly Dose-2010/1/31

2010年1月31日 admin 没有评论
分类: SOA, 学习 标签: ,

转载:做人、做事,做架构师——架构师能力模型解析

2010年1月31日 admin 没有评论

要想从一名普通程序员发展成为优秀的架构师,“个人特性”与“技术技能”缺一不可;而“技术专业能力”、“人际关系能力”和“业务能力”更是优秀架构师重要的三种能力。
/ 周爱民(《程序员》2008年4月刊)
引子
究竟是什么让你在同一个位置上——例如程序员或技术负责人——工作了三年、五年或者更久,而仍然得不到任何的发展空间?你觉得自己已成为技术圈中的大牛,并信心满满地去拿明天就要颁发的某某大奖,然而却仍然停留在同样的技术职位上,去年到今年涨的薪水甚至填不平物价升幅?于是,你开始对老板不满,对员工不满,对昨天升职的那个同事不满……你开始计划明天就要跑单,或者准备考虑提出加薪却又心怀忐忑。
如果技术人员有发展的轨迹,那么他要么“看透工具的本质,把关注点转移到‘团队’的圈子里去”,要么“顺着代码铺就的道路,亦步亦趋地成为良匠大师”。仅以技术方向而言,你大概可以做到架构师、总架构师甚至首席架构师;但问题是:你现在还只是一个程序员。那要如何才能踏上通往架构师之路呢?本文为你解析一个架构师的能力模型。
你能不能做一个好的架构师?
架构师不是界定一个技术高下的职位名称,而是一个职务。所谓职务,包括职——职位,务——工作。前者决定了你具备哪些资源,可以影响到怎样的范围,以及面向的机构,后者则简单地是你需要完成的工作列表。
所以我说“架构师”不是指“一个能做架构的人”。前者是把架构师当职能,后者是当工人。能做一份工作列表中的事,并不等于就成为相应职位上的人。在管理体系里面,你的个人特性决定了你在哪个位置,而技术技能只是做事实施的必需。架构师这个职务,同时要求较高的个人素质和技术能力,因此它的进取之路总结起来就是:做人、做事,做架构师。
因此“模型”由“个人特性”和“技术技能”两个方面构成,在第一张图中,我特别说明“个人特性”既包括人际关系的能力,也包括(具体)业务能力;“技术技能”也是如此。所以个人特性主要与“做人”有关,部分地也包含“做事”的要素。

dd1
                                                           图1 架构师能力模型
“有效沟通”以及“学会谈判”与做具体的事无关,是个人能力特性的公共方面。前者是过程,后者是知道如何定目标与求结果。而“风险与防备”是做事过程控制的关键,与前面两项正好构成了一个做事基本能力的完整体系。基本上,这三项个人特性都是一个“普通程序员”所不具备的,甚至在大多数情况下,普通程序员并不愿意去具备这样的个人特性,因为在许多陷于技术泥淖的开发人员看来:沟通总是会使事情变得更加麻烦,谈判则徒耗时间而无济于事。然而事实上,在整个的架构决策过程中,架构师需要不停地沟通与谈判。将“架构”变成“决策”的过程,其实就是对各个技术角色(及其思想)兼容并包的过程,你需要不断地协调需求、实现之间的各种问题,也需要面对各种投资者(时间、资金、人才等方面的决策者)进行谈判,以确定项目的规模——没有规模也就没有范围,没有范围如何展开设计呢?
一部分开发人员会认为上述过程是“项目经理”的事情,但真的如此吗?当你作为一个更高级别的架构师,以至于要影响到多个项目的决策时,你就全然不会有这种感受了。因为这种情况下,你的决策将先于项目的启动,或者说你已经不单单是一个技术角色了。
设计是架构能力的一部分,但架构师不是设计师——看清楚二者之间的不同,你才真正迈出了架构师职业生涯的第一步。
抽象是思维能力、模型化是表达能力
个人特性中另一个非常重要的方面是“抽象思维”,而这是与架构师角色直接相关的一种能力。这种能力既有职业技能特征,又是普遍性的能力。
所谓普遍性的能力,是指“抽象”在我们——作为人这种个体的——生活中无处不在。例如我们说花、草,说桌、椅……我们用语言去指称任何一个既已存在的(可以脱离我们的语言而自然存在的)事物时,就用到了抽象。说“桌子”的时候,既没有描述桌子的具体形式,也没有说明它的规格,但我们用这个名词时,所有人都知道“桌子是什么”。所以,名词概念是整个抽象逻辑系统中的主体。如果失去了这些名词定义,我们基本上不能说话,也不能描述任何东西——那便到了“只可意会不可言传”的境地。
用现有的成熟语汇去描述你的系统时,大多数人会理解你所表达的含义,例如我们说“这个系统设计为一个三层结构”。然而架构师面临的系统在许多细节上并不见得能够用成熟的语汇去描述,因此必须自已构建一个抽象系统,这就需要概念抽象能力、概念表达能力和基于概念的逻辑表达能力。
概念抽象能力是一种思维能力。简单地说,就是“把目标分解或概括清楚”:你要么概而言之“它是什么”,要么详细地说明“它包括什么”。必须使用大量的语汇来陈述这个“什么”,这不单单是表达为文字,也表达为你在思想过程中的一个完整系统。通常用的方法是“映射系统”。例如你可以用数学中的“数轴”来映射“实数域”。将目标系统形式化为一个概念化的、可讨论的结构系统后,你的抽象过程就基本结束了。
dd3
                                          图2 能力模型中的个人特性
然而这个“抽象系统”可能只构建在你的思维意识里,还必须把它描绘出来。因为不能只是你自己思考清楚,系统就能设计完成。这个“描绘”就依赖于后面两种表达能力,一种是描绘概念实体,一种是描绘实体上的逻辑——有趣的是,这似乎又回到了“程序=结构+算法”。
现在大家回过头来看看UML,或者更多种类的ML(建模语言),他们就用于表达这两个方面的东西:要么是概念实体(例如用一个框表明系统边界),要么是实体上的逻辑(例如用箭头表明逻辑时序)。
所以大家应该清楚,我们再如何称赞UML,它也只是一种对模型化系统的“表达能力”,你只能把它当一种辅助表达的工具去使用,它本身既不能帮助思考,也不见得能作为抽象过程中的或抽象思维环境中的参考。
任何一个优秀的架构师都有自己独特的思考方式,这决定了他如何抽象系统,以及如何“创造性地”设计与构画这个系统。这种“独特的思考方式”贯彻他从孩童开始的整个成长过程,直至他形成独立的社会观、人生观与世界观。他认识世界的方式和接受世界的能力决定于他如何思考,也反映了他这种思考方式的“独特性”。但这并不表明他有特立独行的行为特性(我们这里只说他的思考方式),我们不应介意他是否用某种语言(例如UML或者形式化编程语言)来表达他的思考结果。
推动:设计做大,实施做小
架构师首先是把问题的真正目标确定下来,然后变成系统设计、平台设计或架构设计。而在此之后设计输出将会有两个方向的发展,一是被忠实地贯彻下来,二是被变形地发展下去。两个方向都存在致命的危险:架构最终能否被完整实现。对前者来说,可能是架构设计过度,或设计本身出现了错误;后者则是对架构直接的伤害。
所以架构师必须参与实施的全程——尤其是在架构被映射为目标系统的前期。在这个阶段中,架构师的任务就是推动架构实施,以保证在项目全程的设计/架构/体系的一致性。除了直接跟设计师或设计团队沟通,以保证他们的设计在你可以控制的范围之内以外,架构师还必须有阶段化设计的能力。这种能力用于将一个原本规模宏大的架构设计,变成较小的、易于实施的、对开发团队来说可控的关键点。例如在体系层次的规划上,设计可能是独立、异质的、可迁移的存储框架来实现数据层,但在(前期的)实施上,这里可能被表达为本地数据库,并要求前端开发人员必须通过一个清晰的数据交互层来访问——例如一组数据存取接口,或一个独立数据服务组件。开发人员可能在这里遇到障碍:因为要通过这些中间层来访问本地数据库,纯粹是多余的。然而,正是这“多余的工作”提供了系统弹性,为并行团队开发公共存储服务争取了周期,也为将来的灵活部署与数据迁移提供了可能。
这里的关键就在于,无论原始系统设定有多大,实施时总是在“做小”。每一个局部的实施块都是可控的,并为它在整个体系空间中留下了位置和接口,这样才可能由“小的部分”做大。一个大系统的架构师可能同时在考虑许多个项目中的、不同位置的架构,并且清楚这些项目最终的总体规模。而这,就是平台架构师和体系架构师所涉的领域。
dd4
                               图3 架构师模型图中的“实现能力”
架构真的是“好不好”的问题吗?如同我对工程的理解一样,架构问题的根本,也并不在于它是否完美或漂亮,而是在于是否合用。因此架构师必须对实施架构的团队以及实施过程有充分了解,知道他们的能力缺陷,知道实现过程要消耗的资源,清楚每个环节可能的故障以及先兆。只有这样,架构师才能设计一个让这个团队能实现,而且在实现过程中能受控的架构。
要知道,你作为架构师被请来,不是画几张图纸交给项目经理,说:你们去做吧,做不出来是你们不会做。即使你可以身体力行,在这个团队中教大家、培养大家,那么公司的开销呢?风险呢?这些东西难道就不考虑了?项目的周期因为实现的复杂程度而无法控制时,项目就死掉了。那么,追根究底来说,是不是架构师的问题?是啊,你为什么会做了一份“不合用”的架构呢?——你都不知道项目如何开发、由谁实施、如何管理等等,又如何能面对这些实际环境去设计架构呢?
所以这一部分能力,是要在你的开发经验、团队经验以及用人识人的经验中去找的。参考模型图的“实现能力”下的“设计能力→了解你的主要沟通对象”和“架构推行”等分支,对你或有一些可用的提示。
局部与全局
架构是一个从全局到局部的过程,而实施正好反过来,是从局部到全局。这也正是“设计做大,实施做小”的另一个层面的含义。设计大才可以见到全局,才知道此全局对彼全局的影响;实施小才可能关注细节,才谈得上品质与控制。
事实上,大多数情况下架构是在为“当前项目之外”去考虑,这可以看成全局关注的一个组成部分。因此我们需要界定所谓“全局”的范围:超出公司或整个产品系列、产品线或规划的范围才是多余的。
所以当架构决策谈及“全局”时,其目标并不见得是“保障当前项目”,而又必须由当前项目去完成。
一个经常被用到的例子是:如果仅为当前项目考虑,那么只需要做成DLL模块;如果为产品线考虑,可能会是“管道+插件”的结构形式。而“管道+插件”的形式显然比做成DLL模块更费时,这个时间成本(以及其它成本)就变成了当前项目的无谓开销。
这种全局策略对局部计划的影响是大多数公司不能忍受的,也被很多团队所垢病。然而这却是架构师角色对体系的“近乎必然”的影响——如果你试图在体系中引用架构师这个角色的话。一些情况下,体系能够容纳这种影响,例如“技术架构师”试图推动某种插件框架,而正好开发人员对这项技术感兴趣,那就顺其自然地花点工夫去实现了。但如果不是这样,实施者或实施团队看不到“多余的部分”对他们的价值时,来自局部的抵触就产生了。
这种情况下,平衡这些抵触就成了架构推行的实务之一。在我看来,“平衡”是全局的艺术和局部的技术。也就是说,一方面架构师要学会游说,另一方面也要寻求更为简洁的、成本更小的实现技术。只有当整个体系都意识到(你所推行的)架构的重要性,而且实施成本在他们可以接受的范围之内时,他们才会积极行动起来。
所以所谓平衡,其实也是折衷的过程。构架师只有眼中见大,才知道哪些折衷可以做,而哪些不能。所谓设计评估(模型图中的实现能力->设计能力->设计评估分支)并不是去分析一个设计结果好或不好,而是从中看到原始的需求,看到体系全局的意图,然后知道在将设计变得更为“适当”时可以做哪些折衷。同样的原因,架构师也必须知道自己的决策会产生的影响,才能控制它们,以防它们变成团队的灾难。有些时候,架构师甚至需要抛弃一些特性,以使得项目能够持续下去。因为产品的阶段性产出只是整个战略中的一个环节,而不是全部。
其它
“怎么做一个架构师”这个问题得分成两个部分来看,一个是“做到”,一个是“做好”。由于架构师本身不过是一个技术职位,所以时机成熟了自然会做得到。但问题是,真有一天你被放在这个位置上了,你能做得好吗?
我浏览过几套所谓培训机构的有关架构师的教程,也翻阅过一些讲架构的书。我发现他们普遍地是将架构作为一种“职业技术”来讲,就像培养程序员或者缝纫工一样来教育。但就我的经验来说,架构并不是一件纯粹表现技术能力的工作,所以并不是翻几本书学几种方法就可以投入“实战”的。更深层的问题是,架构师其实不是“战”出来的。昨天跟同事讨论这个话题,他把我们这几年来的一些思考用了三句话来概括,非常精彩:从无到有的,是架构;从表到里的,是抽象;从粗到细的,是设计。
那么到底什么是架构呢?从上面的概括中你是看不到答案的。到底如何做架构呢?从本文中你也是看不到答案的。然而我说,“你看不到答案”的根源其实是在于你的眼光与心性——后面这个词换成现代白话,就是“思想”。真正阻碍了你成为优秀架构师的,也许正是你既有的知识与思想方法,扔掉它们,接受一些全然有别的信息,也许正是良好的开端。
或许你现在正愤愤然:这篇文章怎么空洞无物?——我甚至能想象到一些读者的表情。然而请在问题面前停下来,不要急于给出答案。正如你将“?”稍微变下形,它就成为了“!”一样,问题的本身,就是答案。
作者简介
周爱民(aimingoo),具有十余年的软件开发、项目管理和团队建设的经验,现担任盛大网络的平台架构师,著有《大道至简》、《Delphi源代码分析》等。

分类: 学习, 软件设计 标签:

Google vs Baidu

2010年1月30日 admin 没有评论

我只是一个普通的网民,在我看来Google和Baidu的差距,从下面这个小小的例子中就可以比较出来。 1

2

Google首页就是客户所在城市的电影播放场次;而百度提供内容的质量可就相差甚远了。

分类: 互联网 标签: ,

转载:WordPress数据表结构

2010年1月28日 admin 没有评论

wp_categories

用于保存分类相关信息的表。包括了5个字段,分别是:
cat_ID – 每个分类唯一的ID号,为一个bigint(20)值,且带有附加属性auto_increment。
cat_name – 某个分类的名称,为一个varchar(55)值。
category_nicename – 指定给分类的一个便于记住的名字,也就是所谓的slug,这是一个varchar(200)值。
category_description – 某个分类的详细说明,longtext型值。
category_parent – 分类的上级分类,为一个int(4)值,对应是的当前表中的cat_ID,即wp_categories.cat_ID。无上级分类时,这个值为0。

wp_comments

用于保存评论信息的表。包括了15个字段,分别为:
comment_ID – 每个评论的唯一ID号,是一个bigint(20)值。带有附加属性auto_increment。
comment_post_ID – 每个评论对应的文章的ID号,int(11)值,等同于wp_posts.ID。
comment_author – 每个评论的评论者名称,tinytext值。
comment_author_email – 每个评论的评论者电邮地址,varchar(100)值。
comment_author_url – 每个评论的评论者网址,varchar(200)值。
comment_author_IP – 每个评论的评论者的IP地址,varchar(100)值。
comment_date – 每个评论发表的时间,datetime值(是加上时区偏移量后的值)。
comment_date_gmt – 每个评论发表的时间,datetime值(是标准的格林尼治时间)。
comment_content – 每个评论的具体内容,text值。
comment_karma – 不详,int(11)值,默认为0。
comment_approved – 每个评论的当前状态,为一个枚举值enum(’0′,’1′,’spam’),0为等待审核,1为允许发布,spam为垃圾评论。默认值为1。
comment_agent – 每个评论的评论者的客户端信息,varchar(255)值,主要包括其浏览器和操作系统的类型、版本等资料。
comment_type – 不详,varchar(20)值。
comment_parent – 某一评论的上级评论,int(11)值,对应wp_comment.ID,默认为0,即无上级评论。
user_id – 某一评论对应的用户ID,只有当用户注册后才会生成,int(11)值,对应wp_users.ID。未注册的用户,即外部评论者,这个ID的值为0。

wp_linkcategories

用于保存在WP后台中添加的链接的相关信息的表。包括13个字段:
cat_id – 每个链接分类的唯一ID,bigint(20)值,为一个自增量auto_increment。
cat_name – 每个链接分类的名字,tinytext值。
auto_toggle -这个字段所包含的是一个比较特别的属性。如果为Y,则当该分类中加入了新链接时,其它的链接会变为不可见。它是一个枚举型的值enum(’Y’,’N’),默认为N。
show_images – 该字段也是枚举值enum(’Y’,’N’),默认为Y。用户指定是否允许在该链接分类显示图片链接。
show_description – 该字段指定相应的链接分类下的链接,是否再专门[换行]显示它们的说明,这是一个枚举型值enum(’Y’,’N’),默认为N,即不显示说明(但会通过title属性中显示说明)。
show_rating – 显示该分类下链接的等级。它也是一个枚举值enum(’Y’,’N’),默认为Y。此时,你可以用链接等级的方式来对该链接分类下的链接进行排序。
show_updated – 指定该链接分类有更新是,是否进行显示,枚举值enum(’Y’,’N’),默认为Y。
sort_order – 指定该链接分类中链接的排序依据,varchar(64)值。一般用链接的名字(name,即wp_links.link_name)或ID(id,即wp_links.link_id)。
sort_desc – 指定链接分类的排序方式,枚举值enum(’Y’,’N’),默认为N,即用降序。
text_before_link – 该链接分类下每个链接的前置html文本,varchar(128)值,默认是’列表开始标签’。
text_after_link – 该链接分类下每个链接的中,链接与说明文字(wp_links.link_description)之间的html文本,varchar(128)值,默认是’换行标签’。
text_after_all – 该链接分类下每个链接的后置html文本,varchar(128)值,默认是’列表结束标签’。
list_limit – 用于规定某一链接分类中显示的(可设定的?)链接的个数,int(11)值,默认为-1,即对链接分类下链接的个数无限制。

wp_links

用于保存用户输入到Wordpress中的链接(通过Link Manager)的表。共14个字段:
link_id – 每个链接的唯一ID号,bigint(20)值,附加属性为auto_increment。
link_url – 每个链接的URL地址,varchar(255)值,形式为http://开头的地址。
link_name – 单个链接的名字,varchar(255)值。
link_image – 链接可以被定义为使用图片链接,这个字段用于保存该图片的地址,为varchar(255)值。
link_target – 链接打开的方式,有三种,_blank为以新窗口打开,_top为就在本窗口中打开并在最上一级,none为不选择,会在本窗口中打开。这个字段是varchar(25)值。
link_category – 某个链接对应的链接分类,为int(11)值。相当于wp_linkcategories.cat_id。
link_description – 链接的说明文字。用户可以选择显示在链接下方还是显示在title属性中。varchar(255)值。
link_visible – 该链接是否可以,枚举enum(’Y’,’N’)值,默认为Y,即可见。
link_owner – 某个链接的创建人,为一int(11)值,默认是1。(应该对应的就是wp_users.ID)
link_rating – 链接的等级,int(11)值。默认为0。
link_updated – 链接被定义、修改的时间,datetime值。
link_rel – 链接与定义者的关系,由XFN Creator设置,varchar(255)值。
link_notes – 链接的详细说明,mediumtext值。
link_rss – 该链接的RSS地址,varchar(255)值。

wp_options

用于保存Wordpress相关设置、参数的表,共11个字段。最重要是的option_value字段,里面包括了大量的重要信息。
option_id – 选项的ID,bigint(20)值,附加auto_increment属性。
blog_id – 不详。或许用在单在用户的WP版本上并不重要吧,或许是针对不同用户的Blog来设置的一个值。int(11)值,默认为0,即当前blog。
option_name – 选项名称,varchar(64)值。
option_can_override – 该选项是否可被重写、更新,枚举enum(’Y’,’N’)值,默认为Y,即可被重写、更新。
option_type – 选项的类型,作用不详,int(11)值,默认为1。
option_value – 选项的值,longtext值,这个字段的内容比较重要。Wordpress初始化时就会设定好约70个默认的值,这里暂不介绍。
option_width – 选项的宽(?),作用不详。int(11)值,默认为20。
option_height – 选项的高(?),作用不详。int(11)值,默认为8。
option_description – 针对某个选项的说明,tinytext值。
option_admin_level – 设定某个选项可被操纵的用户等级(详情见我的相关文章),int(11)值,默认为1。
autoload – 选项是否每次都被自动加载,枚举enum(’yes’,’no’)值,默认为yes。

wp_post2cat

用于保存文章(posts)与分类(categories)之间的关系的表,只有三个字段:
rel_id – 关联ID,bigint(20)值,是个有auto_increment属性的自增量。
post_id – 文章的ID,bigint(20)值,相当于wp_posts.ID。
category_id – 分类的ID,也是bigint(20)值,相当于wp_categories.ID。
文章与分类的关系的形成是这样的:rel_id是一个不断增加的自增量,它用于识别每不同的post。post_id可以重复(当它对应多个分类时),因为它可被rel_id识别,所以不会出现混乱。每个post_id可对应多个category_id时,一个rel_id + post_id组合,可以识别某一个分类,因此每个文章的分类可以是不同的。通过这张表,可以非常快速、高效地找出某篇文章(post)对应了哪些分类 (category),反之亦然。

wp_postmeta

用于保存文章的元信息(meta)的表,四个字段:
meta_id – 元信息ID,bigint(20)值,附加属性为auto_increment。
post_id – 文章ID,bigint(20)值,相当于wp_posts.ID。
meta_key – 元信息的关键字,varchar(255)值。
meta_value – 元信息的值,text值。
这些内容主要是在文章及页面编辑页(Write Post, Write Page)的”Add a new custom field to this post(page):”下进行设定的。meta_key就对应名为”key”的下拉列表中的项,而值由用户自己填上(某些时候,wp也会自动加入,如文章中有的音频媒体)。

wp_posts

用于保存你所有的文章(posts)的相关信息的表,非常的重要。一般来讲,它存储的数据是最多的。一共包括了21个字段。
ID – 每篇文章的唯一ID,bigint(20)值,附加属性auto_increment。
post_author – 每篇文章的作者的编号,int(4)值,应该对应的是wp_users.ID。
post_date – 每篇文章发表的时间,datetime值。它是GMT时间加上时区偏移量的结果。
post_date_gmt – 每篇文章发表时的GMT(格林威治)时间,datetime值。
post_content – 每篇文章的具体内容,longtext值。你在后台文章编辑页面中写入的所有内容都放在这里。
post_title – 文章的标题,text值。
post_category – 文章所属分类,int(4)值。
post_excerpt – 文章摘要,text值。
post_status – 文章当前的状态,枚举enum(’publish’,’draft’,’private’,’static’,’object’)值,publish为已发表,draft为草稿,private为私人内容(不会被公开) ,static(不详),object(不详)。默认为publish。
comment_status – 评论设置的状态,也是枚举enum(’open’,’closed’,’registered_only’)值,open为允许评论,closed为不允许评论,registered_only为只有注册用户方可评论。默认为open,即人人都可以评论。
ping_status – ping状态,枚举enum(’open’,’closed’)值,open指打开pingback功能,closed为关闭。默认值是open。
post_password – 文章密码,varchar(20)值。文章编辑才可为文章设定一个密码,凭这个密码才能对文章进行重新强加或修改。
post_name – 文章名,varchar(200)值。这通常是用在生成permalink时,标识某篇文章的一段文本或数字,也即post slug。
to_ping – 强制该文章去ping某个URI。text值。
pinged – 该文章被pingback的历史记录,text值,为一个个的URI。
post_modified – 文章最后修改的时间,datetime值,它是GMT时间加上时区偏移量的结果。
post_modified_gmt – 文章最后修改的GMT时间,datetime值。
post_content_filtered – 不详,text值。post_parent – 文章的上级文章的ID,int(11)值,对应的是wp_posts.ID。默认为0,即没有上级文章。
guid – 这是每篇文章的一个地址,varchar(255)值。默认是这样的形式: http://your.blog.site/?p=1,如果你形成permalink功能,则通常会是: 你的Wordpress站点地址+文章名。
menu_order – 不详,int(11)值,默认为0。
post_type – 文章类型,具体不详,varchar(100)值。默认为0。
post_mime_type – 不详。varchar(100)值。
comment_count – 评论计数,具体用途不详,bigint(20)值。


wp_usermeta

用于保存用户元信息(meta)的表,共4个字段:
umeta_id – 元信息ID,bigint(20)值,附加属性auto_increment。
user_id – 元信息对应的用户ID,bigint(20)值,相当于wp_users.ID。
meta_key – 元信息关键字,varchar(255)值。
meta_value – 元信息的详细值,longtext值。
这是在Wordpress 2.0中才新加入的表。


wp_users

用于保存Wordpress使用者的相关信息的表。WP官方对2.0.2版本中该表的情况的说明有些矛盾(称有22个字段,但详细的列表中只有11个),所以这里只能列出11个字段进行说明:
ID – 用户唯一ID,bigint(20)值,带附加属性auto_increment。
user_login – 用户的注册名称,varchar(60)值。
user_pass – 用户密码,varchar(64)值,这是经过加密的结果。好象用的是不可逆的MD5算法。
user_nicename – 用户昵称,varchar(50)值。
user_email – 用户电邮地址,varchar(100)值。
user_url – 用户网址,varchar(100)值。
user_registered – 用户注册时间,datetime值。
user_level – 用于等级,int(2)值,可以是0-10之间的数字,不同等级有不同的对WP的操作权限。
user_activation_key – 用户激活码,不详。varchar(60)值。
user_status – 用户状态,int(11)值,默认为0。
display_name – 来前台显示出来的用户名字,varchar(250)值。

分类: 网站, 软件设计 标签:

疯狂的sql查询,随时可能引发性能问题

2010年1月26日 admin 没有评论

今天review了群发sms的一段代码,差点没吓死我。 代码如下

for (MtnPlanTosendlist mtnPlanTosendlist:tempList){
           int memberSendTodayCount = getToDayLimit(defaultBo,getMemberSentDal(mtnPlanTosendlist));
           int memberSendMonthCount = getMonthLimit(defaultBo,getMemberSentDal(mtnPlanTosendlist));
           if ((memberSendTodayCount < smsTodayLismitMember) && memberSendMonthCount < smsMonthLimitMember){
              insertList.add(mtnPlanTosendlist);
           }
}

public static int getToDayLimit(BaseBo defaultBo, MtnSmsLog mtnSmsLog) {
       int count = (Integer) defaultBo.get(mtnSmsLog, COUNT_TODAY_EXT)
              .getDefaultModel();
       return count;
}

public static int getMonthLimit(BaseBo defaultBo, MtnSmsLog mtnSmsLog) {
       int count = (Integer) defaultBo.get(mtnSmsLog, COUNT_MONTH_EXT)
              .getDefaultModel();
       return count;
}

这段代码看的出问题吗? For 循环类名套了2个count 查询。如果前面的那个for循环有100个的话, 执行完这个代码就需要200行的sql(远程调用),悲惨呀!

开发人员切莫要把数据库操作当做local方法一样的使用。一则,db操作本质上也是远程访问,远程调用很浪费时间,特别有大量的远程访问的时候;二则,数据库资源有限,大量的数据库访问会导致数据库load的升高,从而影响程序的性能。所以。劲量要减少对数据库的访问,例如通过batch进行操作,或者batch的load到内存中,进行处理。另外,如果count的数量数据行太多的话就需要考虑中间结果,例如做一张中间表来记录当前月、当天的数量,这样也可以有效的减少数据库的访问。

分类: 软件设计 标签: