文档章节

悠然乱弹:从一段代码讲开去

悠悠然然
 悠悠然然
发布于 2014/11/06 21:54
字数 2243
阅读 5774
收藏 92
点赞 4
评论 50

序言

今天偶然看到一框架,在框架的里面有一段这样的描述:

xxx并不愿意其他人来直接修改YYY框架的代码,因为XXX致力于将它打造为完美的作品,其他人写的代码,实在没有加入进来的意义。
但是您可以当小白鼠,提意见,提bug,好的idea我还是愿意接受的。

这里解释一下,其中xxx是作者名字,YYY是框架名称,这么OSC上牛人众多,牛到这个程度的还是第一次见到,于是就想去速度学习一下。其实框架好不好,看例子代码就可以看出一二,去找了找,果然找到了示例代码,我摘了两个方法:

/**
   * 发布文章
   *
   * @return
   */
  public Object add(){
    Request r = Context.get(Statics.REQUEST);
    String title = r.get("title");
    String desc = r.get("desc");
    String content = r.get("content");
    String cats = r.get("cats");
    String pic = r.get("pic");
    String keywords = r.get("keywords");
    List<String> l = new ArrayList<String>();
    String[] cs = cats.split(",");
    for(String s:cs){
      s = s.trim();
      if(!s.equals("")){
        l.add(s);
      }
    }
    Validator.check(title,new RuleNotEmpty("标题"));
    HttpSession session = r.find(WebExecute.TAG_SESSION);
    User user = (User)session.getAttribute(Global.SESSION_USER);
    ITrans t = TransFactory.getTrans();
    String id = ID.next()+"";
    IInserter ins = t.getInserter().table("T_ARTICLE");
    ins.set("C_ID",id);
    ins.set("C_TITLE",title);
    ins.set("C_DESC",desc);
    ins.set("C_USER_ID",user.getId());
    ins.set("C_CONTENT",content);
    ins.set("C_TIME",Dater.ymdhms(Dater.now()));
    ins.set("C_DAY",Dater.ymd(Dater.now()));
    ins.set("C_PIC",pic);
    ins.set("C_KEYWORDS",keywords);
    ins.insert();
    if(l.size()>0){
      for(String cat:l){
        t.getInserter().table("T_ARTICLE_CAT").set("C_ID",ID.next()).set("C_ARTICLE_ID",id).set("C_CAT_ID",cat).insert();
      }
    }else{
      t.getInserter().table("T_ARTICLE_CAT").set("C_ID",ID.next()).set("C_ARTICLE_ID",id).set("C_CAT_ID",1).insert();
    }
    t.commit();
    t.close();
    return new Tip("发布成功");
  }

  /**
   * 修改文章
   *
   * @return
   */
  public Object modify(){
    Request r = Context.get(Statics.REQUEST);
    long id = r.getLong("id");
    String title = r.get("title");
    String desc = r.get("desc");
    String content = r.get("content");
    String cats = r.get("cats");
    String pic = r.get("pic");
    String keywords = r.get("keywords");
    List<String> l = new ArrayList<String>();
    String[] cs = cats.split(",");
    for(String s:cs){
      s = s.trim();
      if(!s.equals("")){
        l.add(s);
      }
    }
    Validator.check(title,new RuleNotEmpty("标题"));
    HttpSession session = r.find(WebExecute.TAG_SESSION);
    User user = (User)session.getAttribute(Global.SESSION_USER);
    Logger.getLog().info(desc);
    ITrans t = TransFactory.getTrans();
    IUpdater iup = t.getUpdater().table("T_ARTICLE");
    iup.where("C_ID",id);
    iup.set("C_TITLE",title);
    iup.set("C_DESC",desc);
    iup.set("C_USER_ID",user.getId());
    iup.set("C_CONTENT",content);
    iup.set("C_PIC",pic);
    iup.set("C_KEYWORDS",keywords);
    iup.update();
    t.getDeleter().table("T_ARTICLE_CAT").where("C_ARTICLE_ID",id).delete();
    if(l.size()>0){
      for(String cat:l){
        t.getInserter().table("T_ARTICLE_CAT").set("C_ID",ID.next()).set("C_ARTICLE_ID",id).set("C_CAT_ID",cat).insert();
      }
    }else{
      t.getInserter().table("T_ARTICLE_CAT").set("C_ID",ID.next()).set("C_ARTICLE_ID",id).set("C_CAT_ID",1).insert();
    }
    t.commit();
    t.close();
    return new Tip("修改成功");
  }
今天在某著名群里贴了一个方法,结果下面有同学说:“不是挺清楚的?我觉得就不错。”

当时正在忙,没有时间详细介绍,于是决定晚上抽个时间给分析讲解一下,不能保证全部是对的,也不能保证全部能够被人接受,但是一定可以促进大家思考一些框架开发中的问题:

  1. 什么是框架?
  2. 到底设计的时候应该考虑哪些问题?
  3. 怎样才是一个及格的框架?

问题的解答

上面提出了三个问题,这三个问题说复杂也非常复杂,三天两天说不清楚;说简单也简单,一句话就说清楚了。

什么是框架?这个问题实际上许多“做框架”的人也不明白。

框架和库的本质不同在于:

  • 框架考虑的是机制的复用,而库主要考虑的是代码的复用
  • 框架考虑的是在机制不变的情况下进行扩展,而库则基本不考虑扩展方面的问题
  • 框架本身是不完整的,在大多数的情况下它自己是干不了啥事情的,而库自身是完整的,可以解决某个领域的问题。
  • 框架是活的,通过不断的扩展与衍生,它就更加强大,而库而是死的,发布时是怎样,就是怎样。

当然,关于这两货之间的比较,还有许多个角度,但我个人觉得本质是我上面举的这些。

设计的时候应该考虑哪些问题?这个问题的答案,如果用一句话来解符号,那答案就是:要仔细考虑使用这个框架的人感受,要考虑如何让使用者感觉爽的问题。当然如果是三天两天说不清楚的方式,那就得从方法论,问题领域,设计原则等待进行阐述了。

怎样才是一个及格的框架?这个问题,用一句话解释,就是在满足上一个问题的情况下不违背基本设计原则,那么就可以算是一个及格的框架。如果用三天两天说明,那就要把所有的基本设计原则拿出来,一个个讲讲清楚,一个个说说明白。 

如果满足了第一个条件,使用者是满意的,从使用来说是不错的;如果满足了第二个条件来说,从设计及实现来说是不错的。如果两个都满足了那说明,最起码是可用的及格的框架,当然也可能得分更多。

代码分析

好的,上面大致讲了一个框架设计过程中要考虑的一些问题,下面就实质性的考虑一下上面的代码,我承认,我没有看里面“框架中具体的实现”,下面的全部“结论”其实都是我的一种判断或猜测,如有不对,欢迎指正:

  1. 这两个方法看起来是那么那么的相像,怎么看都不太协调
  2. Context看起来是个静态类,说明他一定有个ThreadLocal之类的东西在进行一些数据的存储,如果使用的是ThreadLocal其实还是有许多要注意的内容的,个人一般不太推荐采用这种方式进行数据传输。
  3. 数据获取:居然是通过request对象来直接读取值的,当然看得出来这个request作者已经进行了一些封装,但是显然,开发人员会对这个极度反感的。
  4. 事务处理:所有的处理都是自己在代码中写的,好吧,如果所有的业务都在一个方法中编写,那么是OK的,如果不是的话,就麻烦大了。
  5. 数据校验:也是在这个方法内部创建校验对象进行校验的,所以看到在两个方法中都有同样的代码来做同样的事情。
  6. 异常处理:没有看到异常处理方面的内容,因此不知道如果要操作的表不存时发生异常的时候,前台看到一个什么结果,是一大堆异常栈么?
  7. 函数声明:从函数的声明处是看不到传入和传出参数的,因此就决定了所有的处理都是要从上下文中获取Request,Session啥的自己把数据搞出来的。它的返回值是Object,这说明啥意思呢?说明在Jsp展现里应该是进行类型强转的。
  8. 代码重复:由于事务都是写在方法里的,也就说明这些方法不能重用,许多代码都要重复编写。
  9. 处理能力扩展:由于数据库处理与业务展现放在一起,说明是一个典型的B/S架构,也就是说处理能力是非常容易估算的,而且进行水平扩展的能力也比较有限。也说明 系统的安全性比较弱(数据库与应用服务器在同一层上,如果攻破了应用服务器,就会有倒库行为的发生)
  10. 事务对象:有一个疑问:t.commit中为什么还要执行一个t.close?如果commit的时候发生一个异常,到底是close上没有?如果没有close上,外面异常处理怎么处理?

再来分析一下它里面违反一些常见现象对象设计原则的点:

单一原则:在一个方法里做了太多的事情,这种代码以后改的时候有多累呀

抽象原则:没有独立的Dao及Pojo,没有把Dao层,业务层进行剥离,从而导致数据的验证要重复的进行,这块的处理也不能进行复用。可以想想,如果想让这两方法提供的添加和修改功能通过Json或WebService对外提供服务,程序员唯一可行的办法就是再写两方法。

DRY原则:不要做重复的工作,代码中的重复实在太多了,这一点有可能是笔都只是为了说明意思或者随意了。

自动原则:如果能程序化自动完成的,不要让程序员手动完成。

总结

只看这两段代码总结出来的内容不一定全部正确,如果有不正确的地方,欢迎海涵并批评指正。

其实之所以对这两段代码进行分析,是经过作者同意的,一来这两段代码比较典型,可遇而不可求,另外也希望代码作者能够高调做事,低调做人,扎扎实实做出一个别人无法进行再优化改良的框架来。

© 著作权归作者所有

共有 人打赏支持
悠悠然然

悠悠然然

粉丝 2365
博文 173
码字总数 360373
作品 14
杭州
架构师
加载中

评论(50)

悠悠然然
悠悠然然

引用来自“王仁辉(java)”的评论

我写代码习惯就不好,但是写的时候感觉不到怎么办,我自己也写了框架 https://github.com/Dreampie/resty 恳求帮助优化
呵呵,谢谢支持,踩@红薯 这种事情风险大,产出多。因此才死拼着踩一把,平时时间比较紧,因此非常抱歉。 不过如果你要是参与Tiny的一些工作,倒可以获得一些经验。
Dreampie
Dreampie
我写代码习惯就不好,但是写的时候感觉不到怎么办,我自己也写了框架 https://github.com/Dreampie/resty 恳求帮助优化
Jenkin
Jenkin
分析得很好,<a href="http://www.padady.com">电影</a>
xiaofang19
xiaofang19
个人觉得还是要分析源码!这只是调用示例,不是程序源码设计,示例体现不出抽象、复用,可能跟调用者程序设计有关,不是吗?很多调用Hibernate也有类似的写法!
xiaofang19
xiaofang19
个人觉得还是要分析源码!这只是调用示例,不是程序源码设计,示例体现不出抽象、复用,可能跟调用者程序设计有关,不是吗?很多调用Hibernate也有类似的写法!
xiaofang19
xiaofang19
个人觉得还是要分析源码!这只是调用示例,不是程序源码设计,示例体现不出抽象、复用,可能跟调用者程序设计有关,不是吗?很多调用Hibernate也有类似的写法!
xiaofang19
xiaofang19
个人觉得还是要分析源码!这只是调用示例,不是程序源码设计,示例体现不出抽象、复用,可能跟调用者程序设计有关,不是吗?很多调用Hibernate也有类似的写法!
悠悠然然
悠悠然然

引用来自“少年KK”的评论

呵呵,真有意思,凭什么教育别人“高调做事,低调做人"。这篇文章看起来是分析什么代码,本质上就是看XXX不爽。还XXX,YYY,评价代码还偷偷摸摸的。

呵呵,用代号,是不想变成针对人。
少年KK
少年KK
呵呵,真有意思,凭什么教育别人“高调做事,低调做人"。这篇文章看起来是分析什么代码,本质上就是看XXX不爽。还XXX,YYY,评价代码还偷偷摸摸的。
吐槽一下J2Cache

槽点一:集成方式采用ANT 工程还是传统的工程,集成还在用的ant,当然ant来做没有什么不可以,但是作为OSC这么高大上的作者拿出的作品能不能槽点高一些?已经采用了Maven了,用Maven无法独立...

悠悠然然 ⋅ 2015/03/23 ⋅ 128

OSChina 技术周刊第八期 —— 10 大常见的 web 开发错误

每周技术抢先看,总有你想要的! 移动开发 【翻译】实现 iOS 上的井字游戏 前端开发 【软件】Twemoji —— Twitter 开源其完整的 Emoji 表情 【软件】LokiJS —— 高性能的 JavaScript 数据库...

OSC编辑部 ⋅ 2014/11/09 ⋅ 5

悠然乱弹:我的架构观

既然是乱弹,当然就不能全用正理推断,因此文中有文不对题的,思维混乱的都属正常范畴,大家谅解则个。 架构,是一个神秘也是一个普通的词汇。 曾几何时,君不见现在架构师就像雨后春笋似的,...

悠悠然然 ⋅ 2014/04/30 ⋅ 15

悠然乱弹:从几个方法的重构讲开去--性能大优化

上一篇讲到经过上面两篇的优化与重构,整体来说,前面提到的问题,除了性能问题之外,其它问题都已经顺利的解决了。 现在还存在多次扫描处理的问题,也就是说虽然代码结构性重构是成功的,但...

悠悠然然 ⋅ 2014/02/26 ⋅ 11

悠然乱弹:软件开发杂谈

杂谈之一:技术只是成功的一点点基础条件,真正还是得靠做人 话说,有位lianzi同学,水平不错,思想超前,签约阿里现在在百度实习,以前因为喷我的贴又没有啥理由,因此告诉他离我远一点,但...

悠悠然然 ⋅ 2014/11/10 ⋅ 11

悠然乱弹:借船下海还是造船下海

1.借船与借力 三国时期,曹操率大军想要征服东吴,孙权、刘备联合抗曹,“草船借箭”即来源于此,意即运用智谋,凭借他人的人力或财力来实现自己的目标。我们来看看这个故事的几个关键环节。...

悠悠然然 ⋅ 2015/06/17 ⋅ 16

悠然乱弹:螺旋矩阵和蛇型矩阵的悠然版实现

螺旋矩阵和蛇型矩阵,是两个比较有趣的矩阵,有许多的公司面试题中有出现,这两个题的答案也有许多种,简单问一下度娘,就各自有N种实现,来源也非常丰富,比如CSDN、ITEYE、等等,当然也包括...

悠悠然然 ⋅ 2015/04/04 ⋅ 17

悠然乱弹:有问题还是没有问题

宾馆没有无线,幸好自己带了一个无线路由器,接上网线之后,居然无法访问外网。登录管理台一看,是没有申请到IP地址,于是打电话上网管来处理。这斯拿个小米1连上我的路由,在那里扒拉来扒拉...

悠悠然然 ⋅ 2015/10/21 ⋅ 5

Velocity宏定义的坑与解决办法

使用Velocity,当然就免不了要使用宏,或者说使用Velocity而不使用其宏,就相当于废了Velocity一半以上的武功,非常可惜的。 怎么使用Velocity的宏呢,才最大程度的发挥其作用但是又避免掉入...

悠悠然然 ⋅ 2014/04/14 ⋅ 2

Tiny软件开发过程管理暂时不再开源

SDPM1.0暂时不再开源,有需要源码的同学,请加入群228977971获取 SDPM2.0已经开工,敬请期待~ 悠然一直想做一个我不是级的TINY示例,但是这个东东工作量巨大,不是3下5除2可以搞得定的,于是...

悠悠然然 ⋅ 2015/12/08 ⋅ 112

没有更多内容

加载失败,请刷新页面

加载更多

下一页

volatile和synchronized的区别

volatile和synchronized的区别 在讲这个之前需要先了解下JMM(Java memory Model :java内存模型):并发过程中如何处理可见性、原子性、有序性的问题--建立JMM模型 详情请看:https://baike.b...

MarinJ_Shao ⋅ 29分钟前 ⋅ 0

深入分析Kubernetes Critical Pod(一)

Author: xidianwangtao@gmail.com 摘要:大家在部署Kubernetes集群AddOn组件的时候,经常会看到Annotation scheduler.alpha.kubernetes.io/critical-pod"="",以表示这是一个关键服务,那你知...

WaltonWang ⋅ 36分钟前 ⋅ 0

原子性 - synchronized关键词

原子性概念 原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。 原子性的实现方式 在jdk中,原子性的实现方式主要分为: synchronized:关键词,它依赖于JVM,保证了同...

dotleo ⋅ 43分钟前 ⋅ 0

【2018.06.22学习笔记】【linux高级知识 14.4-15.3】

14.4 exportfs命令 14.5 NFS客户端问题 15.1 FTP介绍 15.2/15.3 使用vsftpd搭建ftp

lgsxp ⋅ 53分钟前 ⋅ 0

JeeSite 4.0 功能权限管理基础(Shiro)

Shiro是Apache的一个开源框架,是一个权限管理的框架,实现用户认证、用户授权等。 只要有用户参与一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户...

ThinkGem ⋅ 昨天 ⋅ 0

python f-string 字符串格式化

主要内容 从Python 3.6开始,f-string是格式化字符串的一种很好的新方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快! 在本文的最后,您将了解如何以及为什么今...

阿豪boy ⋅ 昨天 ⋅ 0

Python实现自动登录站点

如果我们想要实现自动登录,那么我们就需要能够驱动浏览器(比如谷歌浏览器)来实现操作,ChromeDriver 刚好能够帮助我们这一点(非谷歌浏览器的驱动有所不同)。 一、确认软件版本 首先我们...

blackfoxya ⋅ 昨天 ⋅ 0

线性回归原理和实现基本认识

一:介绍 定义:线性回归在假设特证满足线性关系,根据给定的训练数据训练一个模型,并用此模型进行预测。为了了解这个定义,我们先举个简单的例子;我们假设一个线性方程 Y=2x+1, x变量为商...

wangxuwei ⋅ 昨天 ⋅ 0

容器之查看minikue的environment——minikube的环境信息

执行如下命令 mjduan@mjduandeMacBook-Pro:~/Docker % minikube docker-envexport DOCKER_TLS_VERIFY="1"export DOCKER_HOST="tcp://192.168.99.100:2376"export DOCKER_CERT_PATH="/U......

汉斯-冯-拉特 ⋅ 昨天 ⋅ 0

mysql远程连接不上

设置了root所有hosts远程登录,可是远程登录还是失败,原因可能如下: 登录本地数据库 mysql -uroot -p123456 查询用户表 mysql> select user,host,password from mysql.user; 删除密码为空的...

冰公子 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部