关于 RESTful 不足的思考

在 Amazon 的时候,公司内有大量的组来维护不计其数的 service,而 service 之间的通用通讯方式是公司内部的一个框架,协议是自定的,客户端也是内部的;现在到了 Oracle,我看到这个变成了 RESTful,也就是说,协议本身变成了最常见和适用的一种。我看到有太多论述 RESTful 优点的文章了,而实际工作中也确实有所体会,比如接口和报文的可读性好,不需要特制的客户端,上手和调试都比较容易等等。但是,如果看到某个东西被冠以过多正面的评价,就要当心了。我也慢慢地体会到了一些问题。不过,在谈谈我的思考之前,我想先明确一下我对 REST 的认识,而这点,鉴于历史原因,也是我不太愿意花时间争辩的内容。我 [……]阅读全文

追求纯粹

pure

偶然想到的这个话题,工程师做工程是一方面,而作为单纯的程序员,总是充满对于纯粹的追求。

最近又负责了一个使用 Angular 的项目,我们知道最近 Angular 很火,其中一个重要原因就是它给前端开发带来的变革,第一次发现可以让以前如此恼人的变量绑定消失掉。以往变量绑定的语句放在附属于页面的一个 js 片段(文件)里面,颇有些无奈的意思,如果把它视为展现层面的东西,显得很不直观(声明式编程才是最直观的方式),而且让这一层变得啰嗦;而如果把它视为下面一层的东西,这又让逻辑代码变得不纯粹——凭什么要让逻辑代码去了解哪个 dom 叫什么 id?于是 Angular 来了,引入了 $Scope 这代表上下文的东西,变量绑定

[……]阅读全文

重新发明轮子

wheels

“ 不要重新发明轮子” 是总是可以听到的话,在评判一个设计的时候,总是听到这样的话。但是凡是不绝对,而对于这句话来说,很多情况下,都是错误的。我甚至都不能说出“ 大多数情况下不要重新发明轮子” 这样的话,因为具体问题,实在没法用大多数还是少部分来概括。重用轮子有什么好处?省代码;轮子已经经过千锤百炼,质量有保障;轮子功能在逐步更新中,可以看到未来的获益。但是,也有一些情况让我无法重用轮子。

第一种情况,我只需要一点沙土,我不需要整座大山。

比如,我只需要一个 StringUtil.isEmpty 这样的方法,判断字符串是否为空串或者 null,如果引入

[……]阅读全文

模板引擎随谈

template engine

模板引擎是为了解耦而产生的,从编程范型的角度来说,写模板属于 “声明式(Imperative)编程”。JSP 大概是最早接触也是最基础的模板引擎,本来写 Servlet 嘛,一大堆一大堆的 print,实在是没有任何结构性可言,然后 JSP 出现,先被处理成实质为 Servlet 的 Java 文件,编译以后变成 class,接着一样执行。所以本质是编译型的模板引擎,当然模板引擎也有解释型或者二者混合的。通常说来编译型的执行效率要高得多。只要是和显示相关的编程语言,都会发展出一套或者 N 套模板引擎,用得多了觉得很多情况下都大同小异。

几年前我在工作中折腾过一段时间的服务端模板引擎,最早遗留系统使用的 Vel[……]阅读全文

关于 if (someobject != null) 的问题

NPE

以下内容来自于在 StackOverflow 上的有一个有趣的讨论,说的话题很小,就是对于这样的对象为空的检查:

if (someobject != null) {
    someobject.doCalc();
}

为了避免空指针异常,看起来也没什么不妥。不过代码里面一片一片的对象是否为空的判断,实在难看。

对象是否为空的契约

通常我们在定义 API 的时候,是遵循一些规矩的,这些规矩可以叫做规约,比如这样的接口:

public Set<String> getCollections();

通常情况下,或者说没有特殊说明的情况下,返回的 set 是不能为 null 的,如果没有元素,应当是一个

[……]阅读全文

过多 if-else 分支的优化

if-else 我想谈一谈这个话题是因为我的上一篇博客在 ITEye 上有一些朋友回复,说 if-else 过多的分支可以使用 switch 或者责任链模式等等方式来优化。确实,这是一个小问题,不过我们还是可以整理一下这个小问题的重构方式。

为什么要优化?

你没有看错。这是要放在第一条谈论的。

有许多人会说,叠起来一堆 if-else 分支,代码就不优雅了。可是,怎样去定义 “优雅” 的概念呢?再退一步说,即便不 “优雅”,又有什么问题?

对于这样一段再普通不过的代码:

int code;
if("Name".equals(str))
	code = 0;
else if("Age".equals(str))
	code = 1;
[……]阅读全文

代码洁癖症的表现

cleanliness 有下列情形之一的,你患上了代码洁癖症。症状程度可轻可重,轻者帮助写出优雅整洁的代码,重者走火入魔,万劫不复。

  1. 多余的空行、分号,没有使用的变量,见一个删一个。
  2. tab 或者空格没有对齐的必须纠正过来,除了缩进用,不允许看到代码内连续两个空格。
  3. 看到一个类某个方法没有注释,不由自主地加上,不管有没有意义。
  4. 错误的拼写,无论是在命名还是注释必须纠正过来;不一致的大小写,必须要纠正过来;标点符号的遗漏,必须补上。
  5. 看到 if(a==0) 这样的代码必须改成 if(0==a) 这样的形式。
  6. 所有 IDE 对代码的告警必须消除,无论采取的方式是否有实际意义。
  7. 看到赤裸的数字,必须定义成常量,即便数字表意很直观,还
[……]阅读全文

史上最烂的代码

shit 其实本没有什么代码是 “史上最烂” 的,要有也只有 “史上更烂” 的,我想随便说说这个话题,也是源自豆瓣的一个讨论。事实上,系统复杂了被骂代码烂是一件司空见惯的事情。当然,也有一些短小的代码片段,就足以看出代码作者是个不怎么样的人。

布尔类型的使用是很容易变成最烂代码的:

if (isTrue()) 
    if (isTrue()) 
        doSomething();
if(boolVal == true) { 
    ..... 
}

有一些毫无意义的注释:

return 1; // 返回 1
//如果标志为真,就返回 true
if(flag)
    return true;

更无意义

[……]阅读全文

编程的未来

1 最近在看一本书,加来道雄(Michio Kaku)的《物理学的未来》,第一、第二章是程序员更加关心的,对于下一个 100 年计算机和人工智能未来的预测。想想计算机发展短暂的历史,这些发生了的翻天覆地的变化,似乎都在弹指一挥间。谁的大胆预测可以那么准确?无论如何,书中对其这样几个猜想令我记忆深刻:

  • 因特网眼镜和隐形镜片
  • 无人驾驶汽车
  • 摩尔定律结束
  • 通用翻译器
  • 全息摄影和三维影像
  • 意识识别
  • 有意识情感的机器人
  • 模拟大脑

这是物理学家眼中的世界(另外推荐他的另一本书《平行宇宙》),激动人心;另一方面,我回想起小时候无比痴迷的机器猫,小小四维空间袋,寄托了孩子多少纯真的梦想,有多少神奇的

[……]阅读全文

分页的那些事儿

1 最近同事在讨论一个关于分页的话题,我在此简单整理一下对于分页的认识。

首先,分页是什么层面上的事儿?是数据访问层面、业务层面还是展示层面?

对于数据访问层来说,具体说,对于查询接口,需要一个“from” 参数和一个“to” 参数,就可以做到获取查询结果集中特定的记录了,它不应该知道任何关于第几页和每页有几条数据这样的信息,这种信息应该是在上层的展示层面所关心的。

举例来说,有这样的接口调用(这只是其中一种接口形式,关于 DAO 接口的形式可以参见这篇文章的讨论):

map.put("age", 18);
map.put(&
[……]阅读全文

对象转换的问题

image 有句话叫做 “计算机科学领域任何问题,都可以间接的通过添加一个中间层来解决”,但是唯一解决不了的问题,是层次本身过多的问题。每一层内都会维护自己在乎的数据对象模型。层与层之间数据的传递,就不可避免地遇到对象类型转换的问题。

这个话题也和最近的项目有关。我们在重构一个老旧的系统,所做的第一件事情,就是要把数据访问层从原有系统中剥离出来,我们精心设计了这一层的模型和结构,但是要让原有系统平缓地从原有数据访问方式上移植到新的数据访问层上,就涉及到上层(Service)的原有数据对象和数据访问层(DAS)之间的数据传递,而二者模型并不相同,而且原有 Service 的模型并不纯粹,既不是充血模型,mode

[……]阅读全文

看透面向对象的复用技术

1 本文翻译自这篇文章,这篇文章写于 1998 年,作者是 Scott Ambler,真的挺久远了。看看上个世纪末的时候,程序员的视角和观点。

想从面向对象复用技术中真正获益,你就必须理解不同种类的复用,并且自如地在不同场合下使用它们。

  • 可复用资源
  • 业务对象根源

复用性是面向对象技术带来的很棒的潜在好处之一。遗憾的是,很多情况下这个好处并不能真正兑现。原因在于复用并不是毫无代价的,它并不是你使用面向对象开发工具的时候就能轻而易举得到的。相反,它是你为了成功而努力工作得来的。首先要知道的是,这个世界上有比代码复用多得多的可复用的东西。代码复用只不过是最基本的一种形式而已。当然,你不要

[……]阅读全文

设计之美

到处都在谈论 UI 的美感,仿佛 “美” 在软件工程中的定义就要落到界面上面。实际美的存在是广义的,包括架构设计,包括代码建设,包括接口定义,不妨在更多的场合引入对美的评审。软件本身就是一种艺术品,而程序员,应当是被赋予创造力的艺术工作者。

 

仅看这两张图,你觉得哪一张会更美一些?

我相信大多数人会选择第一张,因为后面那张图显得头重脚轻,事实上,后者也确实是一个短命的版本,只存活了不到半年的时间。这两张图,正出自淘宝发展的一个阶段(来自淘宝赵超的博客)。而且,进一步观察发现,对于许多设计图来说,狭窄的汇聚点往往成为性能的瓶颈。

另一个设计上典型的丑陋是混乱,如下面的设计图:

我不相信看到

[……]阅读全文

再议单例模式和静态类

tool 单例模式还是静态类,这是一个老话题了,从我刚开始接触 Java 的时候就看到这样的讨论。在这里我总结一下,也添加一点点新东西。

首先要澄清和区别一些概念,“静态类” 和 “所有方法皆为静态方法的类”。

严格说来,Java 中的静态类,指的是 “static class” 这样修饰的类定义,语法上的要求,使得这样的类一定是内部类,换言之,“静态内部类” 是对它的完整定义。静态内部类最大的好处在于可以隐藏自己(只让自己被所在外层的类用到),同时又可以访问到所在外层类的属性。和 “非静态” 的内部类相比,它可以放置一些静态的成员变量和方法定义,而非静态类不可以;而且,静态内部类不能访问外层类非静态的属性。

但是,通常

[……]阅读全文

画圆画方的故事

1 这个故事最初是来自和发哥的一次聊天,他说了一些面向对象设计方面挺有意思的事情,包括 Double Dispatch(下面会提到),我根据我自己的体会和思考,把这些零散的片段重新整理成一个小故事,欢迎感兴趣的同学一起讨论。

有一个苦逼的程序员,叫做小 P。

有一天,老板给他传达了这样一个需求,根据用户不同的图像绘制事件,画出一个圆或者是画出一个方块来。

老板传达的图像绘制事件是这样的:

interface DrawEvent {  
}  
  
class RoundDrawEvent implements DrawEvent {  
}  
  
class RectangleDrawEvent
[……]阅读全文

关于接口设计,还有 Fluent Interface,这种有趣的接口设计风格

1 这个故事我早就想说了,可能是在好多个月前,只是一直不知道怎么说才能说合适,现在我重新整理了一下,讲述给大家。

这个故事是从下面这样一个对外暴露接口的调用开始的。

QueryUserEvent event = new QueryUserEvent();  
event.setName(name);  
event.setAge(18);  
event.setType(QueryUserEvent.TYPE_NORMAL);  
event.setSex(QueryUserEvent.SEX_MALE);  
……  
List<User> userList = userServic
[……]阅读全文

贫血模型和充血模型

这两个概念是早些时候 Martin Fowler 总结出来的两种常见模型设计类型,没有说谁好谁不好,为不同的模型类别选择合适的场景是设计者的工作。没有工具本身的问题,只有工具使用者的问题。

 

 

贫血模型是指领域对象里只有 get 和 set 方法(POJO),所有的业务逻辑都不包含在内而是放在 Business Logic 层。

 image

 

优点是系统的层次结构清楚,各层之间单向依赖,Client->(Business Facade)->Business Logic->Data Access Object。可见,领域对象几乎只作传输介质之用,不会影响

[……]阅读全文

如何思考面向对象

Robert Martin 在学习了面向对象的语言,比如 Java、Python 和 Ruby 之后,看起来每个人都觉得自己在进行面向对象的编码。但是如果你仔细审视一下代码,你就会发现还是无意识地使用了很多过程语句。

静态方法

静态方法是最天然的过程方法,它和面向对象没有一点关系。好吧,我已经听见质疑的尖叫了,那么,我就来给你解释一下为什么。首先我们可以达成一个共识,全局变量和全局状态是魔鬼。如果你觉得前面说的静态方法的话会没什么可争论的,那好,我认为静态方法就应该返回一个常量,因为没有全局状态量(时间和随机数,这些都是全局状态量,所以不能算进去的,对象必须有不同的实例,但是对象图的连线是一致的)。

这就意味着静态方法要做什么

[……]阅读全文

back to top