架构师修炼之道

原文地址: http://www.infoq.com/cn/articles/architect-way#view_49895

架构师是一个神秘而又神圣的名词,作为软件开发领域的设计师,架构师承载着太多的责任和挑战。对于一个程序员或者工程师来说,架构师就像是一个目标,一条道路,抑或是一座山峰。如何能够成为一名合格的架构师?架构师应该具备何种素质?而架构师又是如何做到持续不断的成长和提高的呢?带着这些问题,我们请到了五位InfoQ中文站的编辑,同时也是各领域出色的架构师或者咨询师,来谈谈他们心中的“架构师修炼之道”。他们是:

  • 宋玮:InfoQ中文站Java社区首席编辑
  • 王瑜珩:InfoQ中文站.NET社区编辑,ThoughtWorks咨询师
  • 赵劼:InfoQ中文站.NET社区编辑,微软最有价值专家,现任某创业团队架构师
  • 张龙:InfoQ中文站Java社区编辑
  • 李明:InfoQ中文站Ruby社区首席编辑,现任某通信公司架构师

1)在你的心目中,架构师意味着什么?

张龙:架构师是一个项目组的灵魂人物,他决定着整个系统的技术选型、整体架构以及模块划分,同时还可能担当与领导层的沟通角色,从某种意义上来说,架构师在很大程度上决定着项目的成败与否,正所谓火车跑得快,全靠车头带。

王瑜珩:对我来说,架构师一直是一个很迷惑人的词,似乎每个人的理解都多少有些不一样。我认为架构师更像是一个投资家,需要权衡各方面的利益和风险,反复思量,最后给出一个现实可行的方案,争取用最小的风险获得最大的利益。

李明:我觉得,架构师不仅仅是一个头衔,更是一份责任。所谓“在其位,谋其政”,我倒是觉得架构师更像是父母,而系统和项目则如同子女一般,需要架构师耐心的呵护和培养。完成一个项目,绝不是架构师工作的全部。通过代码重构和架构改造,让这个项目如同有了生命一般逐渐成长起来,这才是架构师最终的目标。

2)架构师应该具备何种技能或者素质?

宋玮:架构师应该具备一定的业务知识和业务分析能力,能够准确地把握需求。要有较强的学习能力,对于新出现的技术、框架和工具,能够快速掌握。扎实的基本功,能够把握住技术方向。良好的沟通能力,能够清楚地表达自己的意图和想法。

李明:代码能力绝对是很必要的。我见过太多只懂得画图的架构师了,“识大体不拘小节”这个说法,在架构师身上并不适用。作为一名架构师,在系统的性能和可扩展性上,要有足够的敏感性,既要充分利用现有资源,又要为长远做好打算。另外,对业务的理解是很多技术架构师所忽视的地方,只要彻底了解业务需求,技术才能派得上用场。

赵劼:在我看来,一个合格的架构师需要具备开放的眼光,各种平台、系统、项目随手拈来皆可组合,唯一的目标则是针对合适的环境选择合适的做法,这显然需要在成本和质量之间进行权衡。作为一个架构师,应该具有很好的“弹性”,在真正的环境中,很少会遇见与过去一模一样的情况,因此也需要架构师能够大胆尝试,灵活应对,使用踏实而严谨的做法来进行推测。一个架构师也必须有着足够的沟通和交流能力,把自己的想法使用合适的方式告诉别人,并且根据别人的反馈进行不断调整自己的观点。没有东西是永远正确的,但是一个人往往会倾向于自己的结论,而作为一个合格的架构师,需要有能力认识到自己存在的缺陷,使用各种方式进行弥补。

王瑜珩:架构师需要高瞻远瞩着眼未来,从外部功能与内部架构两方面来考虑可能面临的变化。诚如周爱民所说,架构师要在开发1.0版的时候就想到2.0、3.0,甚至更远。然而在考虑未来的同时,也不能脱离现在,不能由于对未来的设想而大幅提高现在的开发成本,万一未来并没有到来,所有对未来的投资都将毫无意义。因此架构师需要平衡投资与风险之间的关系,以适当的风险来获得最大的利益。架构师需要有良好的沟通能力,才能将自己的想法展示给开发团队中的每个人,确保整个团队对系统架构的理解是一致的。架构师不能脱离实际,设计一个无法实现或成本很高的架构。同时对于一个实际的团队来说,也需要了解团队中成员的能力,知道何种架构可为,何种架构不可为。

张龙:很多优秀的架构师都是从一个优秀的开发人员转变过来的,但优秀的开发人员未见得都能成为合格的架构师。与架构师相比,开发人员所需担当的任务相对狭隘的多,其最大的目标就是编写出精良的代码、做好充分的测试以及撰写高质量的文档等;而架构师所要面对的则相对宽泛得多,除了过硬的技术之外,还需要有良好的表达能力,同时还要有宏观的驾驭整个系统的能力。

3)架构师需要不断修炼和提高的是什么?

宋玮:扩充知识面,学习了解众多技术及框架的特点和适用范围。了解非功能特性的相关技术和方法,包括可用性、容错性、可扩展性、可伸缩性等等;了解系统安全性方面的技术和框架以及系统性能和状态监测方面的知识及工具。除了技术方面,还架构师还应扩展自身的业务知识,不断提高业务分析能力。想要做到持续不断的学习,保持对各种技术、框架、产品的浓厚兴趣是必不可少的,另外还要掌握他们各自的优缺点及相应的适用场景。学习途径和方式则是多种多样的,但是有一点是可以肯定的,架构师们相互间经常交流对成长是非常有益的。InfoQ的《架构师》就提供了一个很好的交流平台,通过大家的广泛参与,相信《架构师》能够在分享经验、促进交流方面起到积极的作用。

李明:我觉得这个问题可以从两个方面去谈。一方面,架构师要紧跟技术潮流,了解技术的发展和趋势,利用新技术、新方法来提升团队的生产力,将技术转化为收益。这就要求了架构师平时要多关注所在领域或社区最新的新闻和报道,最简单有效的方式莫过于每天都看看InfoQ中文站了。而另一方面,架构师要培养自己的专业领域。虽然从技术的层面上说,很多解决方案放之四海而皆准。但是,从业务的角度来说,很多行业的解决方案放到另外一个行业中,未必行得通。这就要求了架构师必须对所属行业的业务十分了解才行,这也是一个平日里需要修炼的地方。

赵劼:架构师的学习过程是痛苦也是美好的,一个合格的架构师应该可以从学习过程中找到,至少是追求“架构之美”,把架构当作一种“艺术”来对待,并且可以把这种美给传播出去,带领技术团队把这种美变成产品,让更多人体会得到。

张龙:架构师之路是崎岖的,充满了荆棘与挑战,但这却是无数开发者的梦想。架构师是多项技能与素质的综合体,每一位以此为目标的开发者都需要在平日的工作中不断提升自己,在这里我衷心的祝愿架构师这个梦想能照进每一位有心人的现实。

对于合格的架构师应该具备的素质和技能方面,张龙还给出的详细的列表:

有人曾说过,20几岁的编程天才好找,但30多岁的优秀架构师难寻。架构师何其难?除了敏锐的洞察力之外,我认为一个好的架构师必须具备如下几方面的素质:

  • 过硬的技术能力:有人说架构师就不需要编写代码,只需设计整体架构就行了。但我认为这是很片面的,试想一个人如果长时间不写代码,他还能具备持续的技术敏感度么?当然了,这里所说的写代码并非一般开发人员的行为,而是让自己保持住对代码的感觉。还有人说架构师不一定是技术高手,这一点我很同意,但他一定是个优秀的开发者。
  • 良好的沟通能力:这一点尤为重要,因为架构师需要与项目组的开发人员以及领导层不断交换意见,向对方传递自己的设计意图与思想,没有良好的表达与沟通能力是很容易出现问题的。这一点在沟通方式并非母语的企业中尤为明显。
  • 良好的软件工程素质:虽说架构师不是项目经理,但我认为他需要对软件开发过程有清晰明确的认识,这里的开发过程是个泛指,也许是RUP,也许是XP,是什么无所谓,但这种工程素质是每个优秀架构师必备的品格之一。
  • 宽广的知识领域:架构师的眼界一定要开阔,绝对不能局限于眼前的小范围事务,否则极易出现“鼠目寸光”的后果。这就需要架构师不断学习,这里的学习既包括技术上的,同时也包括业务上的以及沟通上的。
  • 领域知识:架构师务必对自己所从事的业务领域有深刻的认识,他未必要成为业务专家,但他一定要对业务知识有深刻的理解。很难想象经常从事金融领域项目的架构师能轻松设计好电信领域的项目架构。知识需要积累,业务也是这样的。
  • 处理系统非功能性需求的本领:架构师尤其需要对系统的性能、容错、并发等非功能性需求方面有独到的认识与解决办法。一个项目到了后期,往往都是这些问题成为整个项目的瓶颈,这时架构师就要发挥其优势了。

通过上面诸位的发言,我们可以看出,架构师得是一个“全才”,不但在技术上和业务上要做到“两手抓,两手都要硬”,更是得需要持续不断的修炼和学习,才能成为一名合格的架构师。虽然这是一条充满挑战的道路,但也同样充满了乐趣与收获,正所谓“无限风光在险峰”,读者朋友们,你们做好准备了吗?

看完后我想说:  要成长为一个架构师, 不仅仅需要技术功底, 沟通,洞察, 新技术,责任感, 这些都是成为一个真正意义上的架构师所必须的..

pack/unpack 实现简单的文件数据库

dbhandler) {
            return $this->dbhandler;
        }
        $this->dbhandler = fopen($this->dbfile, "ab+");
        flock($this->dbhandler, LOCK_EX);
        if (!$this->dbhandler) {
            trigger_error("Connot open file {$file}", E_USER_ERROR);
        }
        return $this->dbhandler;
    }

    /**
     * 写入数据
     *
     * @access  public
     * @param   string $str    数据已空格( )分割自断
     * @return  integer
     */
    public function write($str)
    {
        if (!$this->dbhandler) {
            trigger_error('Not open the database', E_USER_ERROR);
        }
        $data  = explode(' ', $str);
        $name  = pack('a8', $data['0']); //a这里用a是为0保证 不管数据多长或多短都格式化为一个长度为8的字符串
        $age   = pack('S', $data['1']); //16位无符合短整数, 总是16位
        $site  = pack('a30', $data['2']); //同理
        return fwrite($this->dbhandler, $name . $age . $site);
    }

    /**
     * 读取数据
     *
     * @access  public
     * @param   integer $row    读取行数 -1为全部读取
     * @return  array
     */
    public function read($row = 0)
    {
        if (!$this->dbhandler) {
            trigger_error('Not open the database', E_USER_ERROR);
        }
        rewind($this->dbhandler);
        if ($row == -1) { /* 读取所有 */
            $res = array();
            fseek($this->dbhandler, 0, SEEK_END);
            $len = ftell($this->dbhandler);
            $len = $len / 40;
            for ($i = 0; $i < $len;$i++) {
                $res[] = $this->read($i);
            }
            return $res;
        } else {
            /* 读取一行 */
            fseek($this->dbhandler, 40 * $row);
            $res = array();
            $res[] = array_shift(unpack('a8', fread($this->dbhandler, 8)));
            $res[] = array_shift(unpack('S', fread($this->dbhandler, 2)));
            $res[] = array_shift(unpack('a30', fread($this->dbhandler, 30)));
            return $res;
        }
    }

    /**
     * 删除记录
     *
     * @access  public
     * @param   integer $row    删除的行数
     * @return  boolean
     */
    public function remove($row)
    {
        $res    = $this->read(-1);
        $status = false;
        if (isset($res[$row])) {
            unset($res[$row]);
            $status = true;
        }
        $len = count($res);
        $this->truncate(); //清空数据库
        for ($i = 0; $i < $len; $i++) {
            isset($res[$i]) && $this->write(join(' ', $res[$i])); //重新写入数据
        }
        return $status;
    }

    /**
     * 清空数据库
     *
     * @access  public
     * @return  void
     */
    public function truncate()
    {
        $this->close();
        unlink($this->dbfile);
        $this->open();
    }

    /**
     * 关闭数据库
     *
     * @access  public
     * @return  boolean
     */
    public function close()
    {
        if (!$this->dbhandler) {
            trigger_error('Not open the database', E_USER_ERROR);
        }
        return fclose($this->dbhandler);
    }
}

$db = new DataBase();
$db->open(); //打开数据库
$db->write('xiaokai 18 www.youyuge.com'); //写入数据
$db->write('likai 18 www.youyuge.com');
$db->read(0); //读取第一条数据
$res = $db->read(-1); //读取所有数据
$db->remove(0); //删除第一条数据
$db->truncate(); //清空数据库
$db->close(); //关闭数据库

为了更了解pack/unpack这两个函数, 仿照别人的例子, 自己添加了些功能…

PHP pack/unpack 的格式字符详细

手册上解释的不是很清楚, 所以网上找了下, 记录下来, 用得着..

string pack ( string $format [, mixed $args [, mixed $...]] )

  • a 一个填充空的字节串
  • A 一个填充空格的字节串
  • b 一个位串,在每个字节里位的顺序都是升序
  • B 一个位串,在每个字节里位的顺序都是降序
  • c 一个有符号 char(8位整数)值
  • C 一个无符号 char(8位整数)值;关于 Unicode 参阅 U
  • d 本机格式的双精度浮点数
  • f 本机格式的单精度浮点数
  • h 一个十六进制串,低四位在前
  • H 一个十六进制串,高四位在前
  • i 一个有符号整数值,本机格式
  • I 一个无符号整数值,本机格式
  • l 一个有符号长整形,总是 32 位
  • L 一个无符号长整形,总是 32 位
  • n 一个 16位短整形,“网络”字节序(大头在前)
  • N 一个 32 位短整形,“网络”字节序(大头在前)
  • p 一个指向空结尾的字串的指针
  • P 一个指向定长字串的指针
  • q 一个有符号四倍(64位整数)值
  • Q 一个无符号四倍(64位整数)值
  • s 一个有符号短整数值,总是 16 位
  • S 一个无符号短整数值,总是 16 位,字节序跟机器芯片有关
  • u 一个无编码的字串
  • U 一个 Unicode 字符数字
  • v 一个“VAX”字节序(小头在前)的 16 位短整数
  • V 一个“VAX”字节序(小头在前)的 32 位短整数
  • w 一个 BER 压缩的整数
  • x 一个空字节(向前忽略一个字节)
  • X 备份一个字节
  • Z 一个空结束的(和空填充的)字节串
  • @ 用空字节填充绝对位置

一些规则:

1.每个字母后面都可以跟着一个数字,表示 count(计数),如果 count 是一个 * 表示剩下的所有东西。
2.如果你提供的参数比 $format 要求的少,pack 假设缺的都是空值。如果你提供的参数比 $format 要求的多,那么多余的参数被忽略。

echo pack('c', 65); //A
echo pack('c', 65, 97); //A 但是会报错, 因为多了一个参数
echo pack('c2', 65, 97);// Aa
echo pack('c*', 65, 97, 59, 97, 65); // Aa;aA *就是来多少填充多少..

软件架构师应该具备的素质

软件/企业架构师是一项很重要的工作。架构师的职责很多,要胜任的话,需要具备特定的领导、沟通、技术技能。

Gabriel Morgan在最近的一篇帖子里从Daniel Goleman的情感智能(EI)——自我意识、自我管理、社会意识和关系管理——切入,谈论了企业软件架构师应该具备的素质

自我意识

  • 情绪自我觉察
  • 准确的自我评估

自我管理

  • 自控
  • 透明度
  • 适应性
  • 成就
  • 主动
  • 乐观

社会意识

  • 同理心
  • 组织意识
  • 服务

关系管理

  • 感召力
  • 影响力
  • 发展他人
  • 变革催化剂
  • 冲突管理
  • 团队精神与合作

卡内基·梅隆大学软件工程研究所从不同软件工程师那里收集了很多他们对软件架构师的职责、技能及知识所持的观点。对于架构师必备的技能,一部分观点如下:

David Cornish(英国伦敦摩根大通公司的技术架构师):

跟技术团队和商务团队都有良好的沟通

丰富的设计经验和技术知识

分析思维和整合思维

冲突解决

Theo Gantos(美国密歇根弗林特TEKA公司的咨询师):

架构师是一位博学多才的人。在各种方法学领域都要有咨询、交际、组织、概念化、抽象思维、逻辑推理、数据建模的能力,自我检讨的能力,快速适应,演讲和沟通技巧,编程知识,写作技巧,销售技巧,个人魅力,金融和投资回报率计算技能,对付难弄、安于现状的人,有幽默感。

Venkatesh Krishnamurthy(印度班加罗尔市Valtech印度公司的技术架构师):

  • 有创造力
  • 艺术家
  • 政治家
  • 强有力的意志
  • 优秀的沟通技巧
  • 出色的演讲技巧
  • 有人缘
  • 成熟
  • 表达能力强
  • 勇于决策,并能坚持
  • 挑战者
  • 好的观察者
  • 协商者

Victor Alejandro Baez Puente(墨西哥墨西哥城Grupo Nacional Provincial公司的CTO):

  • 对带有财务审计、合同管理、企业工作流、业务流程整合、资产管理组件的企业应用,有设计经验。
  • 有SOA相关经验。
  • 作为首席架构师参与过J2EE项目成立到交付的整个过程。
  • 有在高可用、集群化环境部署J2EE(富)Web客户端应用的经验。
  • 专长于针对软件系统工件构建和文档化的UML。
  • 宽泛的IT知识(应用开发、测试、部署、操作、文档、标准、最佳实践、安全、硬件、网络、操作系统、数据库管理系统、中间件等)。
  • 擅长轻量级、快速开发、敏捷方法学,并有相关经验。
  • 有估算、度量项目速度的经验。
  • 有处理遗留系统和分阶段应用集成的经验。
  • 对细节有敏锐的注意力。
  • 书面、口头、图示沟通的技巧。

例子有很多。有些人把重点放在领导/沟通技巧上,而另一些人则重视具体的技术技能。亲爱的InfoQ读者,你认为软件/企业架构师应该必须具备哪些技能?

来源于:  http://www.infoq.com/cn/news/2009/01/Architect-Qualities

构架师自我培养过程

构架师自我培养过程

构架师不是通过理论学习可以搞出来的,不过不学习相关知识那肯定是不行的。总结构架师自我培养过程大致如下,仅供参考。

1、构架师胚胎(程序员)
学习的知识是语言基础、设计基础、通信基础等,应该在大学完成,内容包括java、c、c++、uml、RUP、XML、socket通信(通信协议)——学习搭建应用系统所必须的原材料。

2、构架师萌芽(高级程序员)
学习分布式系统、组建等内容,可以在大学或第一年工作时间接触,包括分布式系统原理、ejb、corba、com/com+、webservice(研究生可以研究网络计算机、高性能并发处理等内容)

3、构架师幼苗(设计师)
应该在掌握上述基础之上,结合实际项目经验,透彻领会应用设计模式,内容包括设计模式(c++版本、java版本)、ejb设计模式、J2EE构架、UDDI、软件设计模式等。在此期间,最好能够了解软件工程在实际项目中的应用以及小组开发、团队管理。

4、软件构架师的正是成型在于机遇、个人努力和天赋软件构架师其实是一种职位,但一个程序员在充分掌握软构架师所需的基本技能后,如何得到这样的机会、如何利用所掌握的技能进行应用的合理构架、如何不断的抽象和归纳自己的构架模式、如何深入行业成为能够胜任分析、构架为一体的精英人才这可不是每个人都能够遇上的馅饼……

要走的路还有很长…

chrome飞信插件[原创]

更新至1.2, 增加以下功能:

1.常用短语设置/选择
2.设置默认接口来源
3.常用联系人设置/选择

新功能使用说明:

常用短语, 在插件设置中进行设置, 每一条短语为一行.
然后在填写短信内容时, 双击文本框即可

常用联系人设置同上, 使用只要在接收手机中输入数字.
会在文本框下方出现一个选择的列表单击某个号码即可.

———————————————————————————-

更新至1.1, 增加以下功能:

1.设置默认登录手机,
2.设置登录密码
3.接收手机.

可在插件选项中设置

下一版本计划加入的功能:

1.常用短语选择功能
2.常用接受者选择功能

chrome飞信插件

冻结和解冻的PHP对象

之前无意间看到了 Freezing and Thawing PHP Objects 这篇文章翻译过来就是 冻结和解冻的PHP对象 感觉挺新鲜的, 然后花了点时间研究了下。

代码如下:

getProperties() as $attr) {

            $attr->setAccessible(true); //设置属性为访问级别public
            //ReflectionProperty::getName() 获取属性名
            //ReflectionProperty::getValue() 获取属性的值
            $state[$attr->getName()] = $attr->getValue($object) + 1;
        }
        return array('className' => get_class($object), 'state' => $state);
    }

    //解冻
    public static function thaw(array $frozenObject) {
        if(!class_exists($frozenObject['className'])) {
            throw new RuntimeException(sprintf('Class "%s could not be found"', $frozenObject['className']));
        }

        $object = unserialize(sprintf('O:%d:"%s":0:{}', strlen($frozenObject['className']), $frozenObject['className']));
        $reflector = new ReflectionObject($object);

        foreach ($frozenObject['state'] as $name => $value) {
            $attr = $reflector->getProperty($name);
            $attr->setAccessible(true);
            $attr->setValue($object, $value);
        }
        return $object;
    }
}

class Foo {

    public $a;
    protected $b;
    private $c;

    public function __construct($a, $b, $c) {
        $this->a = $a;
        $this->b = $b;
        $this->c = $c;
    }
}
$object = new Foo(1, 2, 3);
var_dump($object);
/* 输出结果
object(Foo)[1]
  public 'a' => int 1
  protected 'b' => int 2
  private 'c' => int 3
*/

$frozenObject =  ObjectFreezer::freeze($object);
var_dump($frozenObject);
/* 输出结果
array
  'className' => string 'Foo' (length=3)
  'state' =>
    array
      'a' => int 2
      'b' => int 3
      'c' => int 4
*/

$object = ObjectFreezer::thaw($frozenObject);
var_dump($object);
/* 输出结果
object(Foo)[5]
  public 'a' => int 2
  protected 'b' => int 3
  private 'c' => int 4
*/
?>

第一次就是输出了 $object 的所有字段信息

第二次经过调用 ObjectFreezer::freeze($object); 也就是冻结 $object 对象返回了一个数组

className没啥说的 $object 的类名

state是经过冻结后的 $object 对象的属性这里给他每个值加1

第三次通过 ObjectFreezer::thaw($frozenObject); 也就是解冻,返回了一个对象

可以看到这个对象中的属性值已经改变了.

这就是所谓的冻结与解冻php对象. 但是具体用到哪, 暂时还我也不清楚, 相信以后总有地方会用到.. ^_^

对了setAccessible是5.3才有的哦..

在看完 Freezing and Thawing PHP Objects 萌生了个想法, 使用php自带的serialize/unserialize这两个函数也许也能实现这样的功能啊..

然后动手试了下, 果然如此.

a = $a;
        $this->b = $b;
        $this->c = $c;
    }

    function show() {
        echo sprintf('$a=%d, $b=%d, $c=%d', $this->a, $this->b, $this->c);
    }

}
?>

注意一下字段的修饰符

show();
$string = serialize($foo);
$foo    = unserialize(str_replace(2, 20, $string)); //这里吧 $foo->b的值替换为20
//这里因为序列化后 protected和private字段 的表示方法不一样, 所以就好用替换了.. - -
$foo->show();
?>

输出结果
$a=1, $b=2, $c=3
$a=1, $b=20, $c=3

很明显, 这里也修改成功了..

PHP还提供了实现类似映射的一些函数

class_ exists
get_ called_ class
get_ class_ methods
get_ class_ vars
get_ class
get_ declared_ classes
get_ declared_ interfaces
get_ object_ vars
get_ parent_ class
interface_ exists
method_ exists
property_ exists

感叹下PHP真TMD强大..