No choice is a good choice

  愚蠢的实现各有各的蠢法,好的代码有相似的气质。比如说吧,在一个既有的函数里增加一个分支,写法包括

1. 敲一颗钉子进去

foo()
{
    ……
    if(condition)
          {statements;}
    else
        {other statements;}
    ……
}

2. 稍微优雅的敲一颗钉子,封装个函数

foo()
{
……
    if(condition)
          func1();
    else
        func2();
……
}

3. 分离条件和行为

foo()
{
    funcs[] = {func1, func2};
    ……
    funcs[toFuncIdx(condition)]();
    ……
}

4.  策略模式

//init.c
init()
{
    ……
    func = selector()
    ……
}
foo()
{
    ……
    func();
    ……
}

5. 设计一种DSL 语法描述它比如

def bhvname prototype {condition_i implement_i};
foo()
{
    ……
    bhvname();
    ……
}

方法5的好处是,隐藏了策略模式的实现细节。还可以再改进,设计更完整的语法体系,只描述这个特定领域的业务本质,将实现细节尽可能的隐藏。

讲起道理来,大部分人至少在口头承认不应该做霰弹式的改动,应该封装,应该做一些设计。但具体coding的时候,方式1超级简单啊。日积月累函数就长大了;有时候自己也看不过去了,抽取一个函数局部改造一下;团队别的同学稍微有点追求,对某些改动采用方法3或4来实现。总之,怎么做的都有,就一个具体的改动而言,程序员总能找到一个理由说明自己为何以这种方式实现而非其它。代码长得千奇百怪。

大型项目,这样的问题后果尤为严重。

分析这个过程,核心问题是将决策点遗留到了最后一步。coding的时候程序员才最终决策行为要怎么拆分,数据要怎么设计怎么封装,已经最终采用的实现方式如何。架构设计,业务分析(BA)的原则和意图没办法有效的传递下来。最终coding的那个同学,能力,眼界和职责都不足以让他做出长期看最佳的设计和实现。他只关心这个需求尽快交付,如何希望能对代码演进做出合适的判断呢?

一个解是通过某种机制,让coding的人最终没有选择,只能以某种(比较好的)方式来实现代码,且并不需要大量知识和经验来做判断和选择。

架构师(组)应该对系统做顶层设计,划分业务边界和抽取系统核心复杂度。在软件设计方面的工作内容包括定义

1. 系统的框架结构(不是业务框架,而是分层结构和核心元素);

2. 行为和数据的种类,拆分的原则和必须标明的属性,

3. 根据这种拆分应选择的实现形式;

4. 定义DSL和设计转换器,将1-3的内容固化;

5. 抽取系统特有的基础设施层。

6. 定义业务分析和开发的边界和工作方式;

业务分析,将系统有效的分解,并定义开发所需要完成的元素。他们描述业务本质,一般并不关心最终代码实现的形式。

架构组的工作在项目的早期和中期会非常繁重,架构师输出的并非文档或PPT,而是非常具体的语法,转换器,demo。可以定义和约束后续的业务分析和开发。

我们谈到资源前移时,往往担心前移了,未必会带来收益。对于注定长期运行的大型项目,一方面要坚定资源前移的信念,反正一二十人投到故障解决中,恐怕浩瀚的bug海上连一点涟漪都激不起来,不如放到前期设计和探索上去,倒可能产生价值;另一方面,总要给一套具体前移的方法,画个饼说清楚如何更细致的做好设计。注意这个饼必须要能迭代交付。目标宏大,梦想着上市敲钟,却拉不来一点投资,再报怨资本有眼无珠。投资要一轮一轮来,一方面看疗效,另一方面资本被裹挟进来了,花的越多,资本自然会帮你一起想办法,往往事就成了。

你可能感兴趣的:(No choice is a good choice)