在回忆昨天在和同事们讨论一个需求的情景,总结了以下几点:

  1. 要理性地说服别人,切忌带有情绪沟通,保持冷静
  2. 用通俗易懂的例子告诉对方那样做有什么样的好处和坏处
  3. 不要试图通过展示自己的经验、资历来使别人认同自己
  4. 给出你认为更好的建议
  5. 做任何一件事情之前,首先考虑做这个事情是否有价值,是否有其他更简单的思路来获得客户的认可。

可参见dreamhead的这篇文章

Scala实现的各种排序算法

收到TW的offer已经一周了,已经跟现在的公司提离职了,于是整个人都松弛下来了,闲来无事,把自己在学习scala期间写的几个排序的小例子拿出来分享一下:

Insertion Sort:

def isort(xs: List[Int]): List[Int] = {
  xs match {
    case List() => List()
    case x :: xs1 => insert(x, isort(xs1))
  }
}
def insert(x: Int, xs: List[Int]): List[Int] = {
  xs match {
    case List() => List(x)
    case y :: ys => if (x <= y) x :: xs else y :: insert(x, ys)
  }
}

测试代码:

def main(args: Array[String])
{
  val xs = List(4, 6, 7, 3, 223, 999999, 6)
  print(isort(xs))
}

Quick sort:

def quicksort[T](less: (T, T) => Boolean)(xs: List[T]):List[T]= xs match
{
  case List() => List()
  case y::ys => 
    quicksort(less)(ys.filter( a => less(a, y)))::: List(y) ::: quicksort(less)(ys.filter( b => !less(b, y)))
}

测试代码:

def main(args : Array[String])
{
  val xs = List(4, 5, 8, 1, 10);
  val sorted = quicksort((x: Int, y: Int) => x > y)(xs);
  print (sorted)
}

不知各位看完后是什么感觉?想想用C、Java语言实现一个insertion sort、 quick sort 的代码量吧,再看看这个scala实现,无需关注变量状态,只需要告诉编译器,先做什么,再做什么,其余的事情就由编译器自己实现了, 现在应该了解到函数式语言的威力了吧。个人感觉函数式语言更加接近人类的思维模式,想当年刚开始学习C++的时候,写个冒泡排序都把我憋出大红脸出来,后来接触到函数式语言才发现,原来编程是可以这么有趣,这么爽! 迷途的人们啊,赶快投入到函数式语言的怀抱中来吧 :)

看了陈金洲写的≪架构腐化之谜≫,深有感触,这篇文章几乎精确地描绘了国内软件行业大多数公司的现状,我对于目前所在的一个项目从效率方面进行了分析,主要发现有以下几点问题:

1 架构失控。

到处充斥着代码泥团。

        2 功能杂糅。

为了应对各种多变的需求,新增各式各样的开关配置项,代码中增加对这些配置项的判断逻辑,增加了代码的复杂度。

3 build, deploy 时间过长。

目前我们构建一个发布包需要30分钟。

4 启动时间过长。

我测试了一下,在一台 CPU 为core dual 2.0GHz、 4G 内存的机器上,启动UT容器需要40~50秒,启动web容器需要4~5分钟。容器启动越慢,那么开发人员得到的反馈周期也越长,试想在一个几十个开发人员的项目组里出现这种情况,这是多大的浪费!

对于上面四个问题,我有些自己的想法想跟大家分享下:

1 实施code review。

开发过程中必须进行 code review,如果条件允许,可以尝试pair programming, 面对面的交流永远是知识传承的最佳方式。

通过新老员工之间的code review 或者pair programming, 新员工可以以最快的速度了解项目内部一些约定:如,展示层的公共逻辑应该放在ViewCommon工程里;除了工具类,应该尽量避免静态方法调用;也可以尽快了解他应该写什么样的代码,写什么样的代码会挨批。

只有所有人都去维护这个架构,遵守约定,那这个架构才能发展下去。好的架构不是设计出来的,而是演进出来的。

         2 有必要做这么大吗?

对于第二个问题,我有个疑问:我们做了那么多功能,客户现在用到了多少?做了功能然后又关掉,然后等后面客户要的时候再开启,那么在这个功能已经实现到这个功能被开启正式商用这段时间,这些代码的维护成本谁来承担?这些是不是浪费?

即使客户的需求真的有这么多,他的商用计划是什么?是不是所有特性在这个版本发布时会全部上线?等考虑完这些问题,那么这些所谓的开关项,以及由这些开关项所控制的功能组合而成的大项目(这里的大指的是在物理部署上大)存在的必要性就值得怀疑了。我们不妨换个思路:把产生这个大项目的大需求划分开来,把大项目分解为几个可以独立部署、运行的小项目,然后分阶段实现这些项目,逐步提供给客户,这样的客户感知就是系统主页上不断新增的链接或者tab,而实际上这每个链接或者tab后面都是一个新部署上线的子系统。而这些子系统的开发、维护成本都肯定低于一群人在一个大项目里捣鼓。

         3 精简build 脚本。

把构建任务中的每一步都独立成一个单独的target, 即能达到脚本重用的目的,又能让开发人员灵活选择自己想要运行的target ,另,目前我们的项目还是存在循环依赖的情形,这个问题必须解决。

 4 这个问题有多种解决方案:

 1)给开发人员换更好的机器

 2)写UT来验证功能的正确性,而不是

“修改代码->重启容器->刷新页面->查看结果” 这样一个反馈周期超长的流程。

 3)写UT用例尽量不要启动spring容器,实际上绝大多数应用逻辑不需要启动容器就可以进行测试。

     什么?你问我们那些公共能力怎么办?比如数据字典,比如配置项列表?我建议你用stub吧,这个可以节省很多时间,写个桩是值得的。

回家

现在是2011年1月30日,阴历二零一零年腊月二十七,明天晚上这个时候应该已经在回家的火车上了,又一次要体验这史上最大规模的人类迁徙活动了,祝我一路顺风,有个愉快的旅途,谢谢那些帮我通过各种手段搞票的亲戚、朋友、同事、同学们,为了能回趟家,麻烦你们了,谢谢你们,祝你们都过个好年,开心每一天。

Main Idea of functional language

最近开始了解一种新的函数式+对象式语言scala,以后我会分篇在这里记下自己的心得。 本文主要内容摘自《Programing in scala 2nd Edition》。

Functional programming is guided by two main ideas: The first idea isthat functions are first-class values.

In a functional language, You can

  • pass functionsas arguments to other functions
  • return them as results from functions
  • store them in variables
  • define a function inside anotherfunction

functions that are first-class values provide a convenient means for abstractingover operations and creating new control structures.

The second main idea of functional programming is that the operationsof a program should map input values to output values rather than change data in place.

In other words, methods should not have any side effects.They should communicate with their environment only by taking arguments and returning results.

A method without any side effects are called referentially transparent. Functional languages encourage immutable data structures and referentiallytransparent methods.