文档章节

再次吐槽红薯的J2Cache

悠悠然然
 悠悠然然
发布于 2017/12/21 11:25
字数 1780
阅读 8031
收藏 21

序言

以前写过两篇吐槽@红薯 的文章,吐槽一下J2Cache扒掉红薯的内裤-深入剖析J2Cache,应该说受到了广大Oscer们的一致认同,作为一个站长不好好的搞网站非要搞程序,说什么要做站长里面代码写得最好的,写代码里面网站办的最好的。好吧,这些我都忍了,但是,居然赤果果的点名叫嚣:

作为一个程序员,作为一个连续扒过两次红薯内裤的喷子,为了维护程序员的尊严,为了广大OSCER们不要掉到红薯的坑里,为了世界和平,必须狠狠的砍他。

正文

槽点一:目录结构不规范

上眼首先来找test目录想看看这么测试和使用的,居然找不到,再仔细看居然有个Java类叫

CacheTester

再看resource和src居然不在main目录下,是我已经out了吗?

修改方式,完全按照Java&Maven的开发和代码组织规范老老实实的执行。

槽点二:测试方式不规范

下面就是所谓的测试代码了

/**
 * 
 */
package net.oschina.j2cache;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * 缓存测试入口
 * @author Winter Lau
 */
public class CacheTester {

   public static void main(String[] args) {
      
      System.setProperty("java.net.preferIPv4Stack", "true"); //Disable IPv6 in JVM
      
      CacheChannel cache = J2Cache.getChannel();
      BufferedReader in=new BufferedReader(new InputStreamReader(System.in));

       do{
           try {
               System.out.print("> "); 
               System.out.flush();
               
               String line=in.readLine().trim();
               if(line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("exit"))
                   break;

               String[] cmds = line.split(" ");
               if("get".equalsIgnoreCase(cmds[0])){
                  CacheObject obj = cache.get(cmds[1], cmds[2]);
                  System.out.printf("[%s,%s,L%d]=>%s\n", obj.getRegion(), obj.getKey(), obj.getLevel(), obj.getValue());
               }
               else
               if("set".equalsIgnoreCase(cmds[0])){
                  cache.set(cmds[1], cmds[2],cmds[3]);
                  System.out.printf("[%s,%s]<=%s\n",cmds[1], cmds[2], cmds[3]);
               }
               else
               if("evict".equalsIgnoreCase(cmds[0])){
                  cache.evict(cmds[1], cmds[2]);
                  System.out.printf("[%s,%s]=>null\n",cmds[1], cmds[2]);
               }
               else
               if("clear".equalsIgnoreCase(cmds[0])){
                  cache.clear(cmds[1]);
                  System.out.printf("Cache [%s] clear.\n" , cmds[1]);
               }
               else
               if("help".equalsIgnoreCase(cmds[0])){
                  printHelp();
               }
               else{
                  System.out.println("Unknown command.");
                  printHelp();
               }
           }
           catch(ArrayIndexOutOfBoundsException e) {
               System.out.println("Wrong arguments.");
              printHelp();
           }
           catch(Exception e) {
              e.printStackTrace();
           }
       }while(true);
       
       cache.close();
       
       System.exit(0);
   }
   
   private static void printHelp() {
      System.out.println("Usage: [cmd] region key [value]");
      System.out.println("cmd: get/set/evict/quit/exit/help");
   }

}

为什么不用JUnit,TestNG等单元测试框架,居然还用main?

我们想象一下,每次红薯修改完代码,都得认真输入各种命令来验证是不是正确是不是引入了新的BUG?

槽点三:程序结构组织不合理

按照红薯的设计,提供了2级代理:1级是Ehcache,2级是Redis。

那如果我想把Ehcache换成另外一个比如MemCache的话怎么办?

红薯兄冷笑一声,回答:“你的想法我早就想到了,你只要扩充一个新MemcacheCacheProvider”,然后修改j2cache.properties文件中的配置就可以了

说的确实很有道理,但是,你这里依赖进来的Ehcache相关的包怎么办?去一个一个排除吗?

实际上比较好的办法是:

J2Cache工程制定接口标准和框架的实现类,Ehcache和Redis以及其他的缓存实现各自作为独立工程,用的时候依赖进来即可,这样也可以提供不同版本的缓存实现,而不是都在框架底层依赖死。

槽点四:拒绝接受新鲜事物

对于增加程序的灵活性方面,一个是通过依赖注入的方式,一个是通过配置的方式。

当然红薯同学是不屑于引入Spring等依赖注入框架的,也懒得增加配置文件的,所以就导致一个结果,如果你接受,那么就全盘接受我的方案要不就滚犊子你不是我的菜。但是作为一个通用的框架来说这么做应该是远远不够的,这也大大限制了框架的通用型,或者就只能Clone下代码衍生出各种版本来。这个和红薯同学开源的初始目的完全是背离的。

小节

通过上面的分析,由于代码规范性和设计方面的问题,其实已经没有看代码的必要了,但是回想起红薯叫嚣的样子,不行,还得举起大刀继续深深的砍下去:)

代码评审

Main方法

在许多代码里面都有main方法的存在,

在许多安全扫描程序看来,main方法是存在安全问题的,必须加以说明解释或剔除。如果只是用来做一下测试,还是用Unit test case的方式进行比较好,这样每次install deploy release都可以进行测试为你的代码保驾护航,而放在main里面,我敢保证绝大多数的情况下都是不运行的。

从这个角度来说,开发过程管理是存在问题的。

 

解决思路:有些时间看起来是花的多的,比如JUnit测试用例;有些时间看起来是节省的,比如main方法。

实例初始化

private final static CacheProvider getProviderInstance(String value) throws Exception {
   if("ehcache".equalsIgnoreCase(value))
      return new EhCacheProvider();
   if("redis".equalsIgnoreCase(value))
      return new RedisCacheProvider();
   if("none".equalsIgnoreCase(value))
      return new NullCacheProvider();
   return (CacheProvider)Class.forName(value).newInstance();
}

value这个变量名明显有点词不达意,叫cacheType,cacheProviderType是不是好一点?当然其实叫什么不重要,我觉得这里参数用Class<CacheProider> cacheProvider 更好一点,这样一来清晰,而来代码也清晰的多,类似如下:

return cacheProvider.newInstance();

原因如下:第一让使用者记这些魔鬼字符串是不合适的;第二如果扩充新的类型,都要修改核心代码,这里有依赖倒置的问题;第三,你一会儿是类型一会儿是类的名字,你的注释又没有说明,你是准备让使用你的框架的人都必须熟读里面的每一行代码的意思吗?

扩展性的考虑

当我看到红薯提供了配置文件来修改1、2级缓存的实现的时候,说实际我是比较开心,终于有进步了啊,不容易。

不过看到这里的时候:

String cache_broadcast = props.getProperty("j2cache.broadcast");
if ("redis".equalsIgnoreCase(cache_broadcast)) {
   String channel = props.getProperty("redis.channel");
   policy = ClusterPolicyFactory.redis(channel, CacheProviderHolder.getRedisClient());//.getInstance();
}
else if ("jgroups".equalsIgnoreCase(cache_broadcast)) {
   String channel_name = props.getProperty("jgroups.channel.name");
   policy = ClusterPolicyFactory.jgroups(channel_name);//
}
else
   throw new CacheException("Cache Channel not defined. name = " + cache_broadcast);

我才知道,那只是一种错觉,为什么不能完全解耦,透明切换?

修改建议:从Cache核心代码里面忘记Redis&Ehchche,完全不要出现任意一种具体的缓存的名字和相关类。

结论

看到这里的时候,基本上感觉距离成熟还有一段距离,继续努力!

纳尼,居然要夸两句?!好吧,还是要夸的,那就夸几句:

1、感觉红薯还是发挥稳定的,灰常稳定,几年以来代码质量水平非常稳定!!

2、对新的JDK特性了解非常好,充分使用了在接口中实现通用method的方法

3、成功的从V1进化到V2,版本上有巨大越变

4、一如既往的帅,这方面我望尘莫及啊

备注:由于时间和水平的关系,槽点数量和质量肯定有遗漏和不足之处,希望其他Oscer们补充。

本人开源的tinyscript已经成熟,感兴趣的同学请移步查看

 

© 著作权归作者所有

共有 人打赏支持
悠悠然然

悠悠然然

粉丝 2407
博文 184
码字总数 360373
作品 14
杭州
架构师
私信 提问
加载中

评论(70)

Hello_Maybe
Hello_Maybe
好用就行
雷兽

引用来自“雷兽”的评论

红薯的测试命令类 没毛病 这是运维命令 单元测试那是程序员角度思想

看悠然的文章内容 就是码农 高级点的。。。嘿嘿嘿 好像 不是架构、项目运营级别的思想哦 嘿嘿嘿

j2cache是基础运维组件 不是业务代码库 由少数人开发 测试 发布 本来就不一定要坚守业务开发那种项目框架结构吧 哈哈哈哈

引用来自“悠悠然然”的评论

哈哈,一下就被你猜中了,厉害~~~果然高级,一看就是CEO级别。
btw,测试命令类你以为我看不懂啊?问题是你每次都靠这东东来验证正确性吗?
你怎么保证别人提交pr的时候是OK的?每次都是执行这个命令类吗?
所以红薯写这个类是没有毛病的,但是测试用例在哪里?!
凡是没有测试用例的框架都是耍流氓。
我没具体看代码 我只是想说 可能那是运维测试工具

你在说的是红薯没有放测试用例

关我啥事。。。。。。

这根本就是两件事情 你吐槽不着我
悠悠然然
悠悠然然

引用来自“乌龟壳”的评论

引用来自“悠悠然然”的评论

引用来自“黑狗”的评论

除了main方法胡乱点评意外 其他都在理!

回复@黑狗 : 当你做过外资银行的项目你就知道了,你以为没有道理是因为你碰到得事情还不够多
想听你说下单元测试放在main函数里有什么问题?你的这篇博客里写得太简单,没交代原因只是旁敲侧击说明了下。

回复@乌龟壳 : 其实我已经说得很清楚了。
乌龟壳
乌龟壳

引用来自“悠悠然然”的评论

引用来自“黑狗”的评论

除了main方法胡乱点评意外 其他都在理!

回复@黑狗 : 当你做过外资银行的项目你就知道了,你以为没有道理是因为你碰到得事情还不够多
想听你说下单元测试放在main函数里有什么问题?你的这篇博客里写得太简单,没交代原因只是旁敲侧击说明了下。
蓝风970655147
蓝风970655147
哦哟, mark 下, 周末看看这个版本
悠悠然然
悠悠然然

引用来自“开源中国首席卡牌中单”的评论

引用来自“悠悠然然”的评论

引用来自“雷兽”的评论

红薯的测试命令类 没毛病 这是运维命令 单元测试那是程序员角度思想

看悠然的文章内容 就是码农 高级点的。。。嘿嘿嘿 好像 不是架构、项目运营级别的思想哦 嘿嘿嘿

j2cache是基础运维组件 不是业务代码库 由少数人开发 测试 发布 本来就不一定要坚守业务开发那种项目框架结构吧 哈哈哈哈
哈哈,一下就被你猜中了,厉害~~~果然高级,一看就是CEO级别。
btw,测试命令类你以为我看不懂啊?问题是你每次都靠这东东来验证正确性吗?
你怎么保证别人提交pr的时候是OK的?每次都是执行这个命令类吗?
所以红薯写这个类是没有毛病的,但是测试用例在哪里?!
凡是没有测试用例的框架都是耍流氓。

回复@悠悠然然 : 你们每次修改都建立分支的吗?

回复@开源中国首席卡牌中单 : Release版BUG修订需要建分支,正在开发期的不用
开源中国首席罗纳尔多
开源中国首席罗纳尔多

引用来自“悠悠然然”的评论

引用来自“雷兽”的评论

红薯的测试命令类 没毛病 这是运维命令 单元测试那是程序员角度思想

看悠然的文章内容 就是码农 高级点的。。。嘿嘿嘿 好像 不是架构、项目运营级别的思想哦 嘿嘿嘿

j2cache是基础运维组件 不是业务代码库 由少数人开发 测试 发布 本来就不一定要坚守业务开发那种项目框架结构吧 哈哈哈哈
哈哈,一下就被你猜中了,厉害~~~果然高级,一看就是CEO级别。
btw,测试命令类你以为我看不懂啊?问题是你每次都靠这东东来验证正确性吗?
你怎么保证别人提交pr的时候是OK的?每次都是执行这个命令类吗?
所以红薯写这个类是没有毛病的,但是测试用例在哪里?!
凡是没有测试用例的框架都是耍流氓。

回复@悠悠然然 : 你们每次修改都建立分支的吗?
悠悠然然
悠悠然然

引用来自“雷兽”的评论

红薯的测试命令类 没毛病 这是运维命令 单元测试那是程序员角度思想

看悠然的文章内容 就是码农 高级点的。。。嘿嘿嘿 好像 不是架构、项目运营级别的思想哦 嘿嘿嘿

j2cache是基础运维组件 不是业务代码库 由少数人开发 测试 发布 本来就不一定要坚守业务开发那种项目框架结构吧 哈哈哈哈
哈哈,一下就被你猜中了,厉害~~~果然高级,一看就是CEO级别。
btw,测试命令类你以为我看不懂啊?问题是你每次都靠这东东来验证正确性吗?
你怎么保证别人提交pr的时候是OK的?每次都是执行这个命令类吗?
所以红薯写这个类是没有毛病的,但是测试用例在哪里?!
凡是没有测试用例的框架都是耍流氓。
雷兽
红薯的测试命令类 没毛病 这是运维命令 单元测试那是程序员角度思想

看悠然的文章内容 就是码农 高级点的。。。嘿嘿嘿 好像 不是架构、项目运营级别的思想哦 嘿嘿嘿

j2cache是基础运维组件 不是业务代码库 由少数人开发 测试 发布 本来就不一定要坚守业务开发那种项目框架结构吧 哈哈哈哈
zzuqiang
zzuqiang
这次内裤没扒的那么彻底
J2Cache 2.3.8 发布,红薯你还是好好过年去吧

不让人好好过年,红薯的新闻绝对是凑数的! 临放假前来一炮 —— J2Cache 2.3.8 可能会是狗年春节前的最后一个版本,可是谁知道呢? 一天发三个版本的红薯大家又不是没见过! 新版本包含的改...

周其
02/07
2.7K
47
在多系统间使用j2cache。

红薯大神,你好。假设我现在有系统A和系统B。系统A能够修改数据,而系统B只能读取数据。此时如果我们系统A更新了数据就需要系统B去更新自己的缓存。根据j2cache的原理,这就要求系统A必须链接...

vomou
2017/09/01
85
1
EhCache磁盘建立在内存中?

刚刚看了 @红薯 的J2Cache介绍文档,感觉挺好的。 不过在J2Cache使用技巧章节中 @红薯 说:EhCache的磁盘存储建立在内存中 看到这个我很不理解,一直没有用过磁盘存储,有知道的朋友麻烦解释...

_金角大王_
2015/01/10
678
2
J2Cache 2.3.19 性能提升 30%,这不是 Bugfix 版本

这个版本你们没有槽点可喷了吧,因为没有 Bug 了!!! J2Cache 2.3.19 带来了部分性能的提升达 30% ,而且进一步降低对 Redis 请求的压力。 纳尼?你说我吹牛逼?下面说说详情! 假设有 10...

红薯
05/23
2.5K
65
沉寂多时,J2Cache 2.0 首个 Beta 测试版发布

J2Cache 已经有很长时间没有更新了,一年?一年多?还是更长?反正已经很久了。因为实在是太忙了,在这里先感谢一下参与 J2Cache 贡献的开发者,他们是:https://gitee.com/ld/J2Cache/cont...

红薯
2017/12/22
2.8K
18

没有更多内容

加载失败,请刷新页面

加载更多

CentOS配置Tomcat监听80端口,虚拟主机

Tomcat更改默认端口为80 更改的配置文件是: /usr/local/tomcat/conf/server.xml [root@test-a ~]# vim /usr/local/tomcat/conf/server.xml # 找到 Connector port="8080" protocol="HTTP/1......

野雪球
今天
5
0
《稻盛和夫经营学》读后感心得体会3180字范文

《稻盛和夫经营学》读后感心得体会3180字范文: 一代日本经营之圣稻盛和夫凭借刻苦勤奋的精神以及深植于佛教的商业道德准则,成为了“佛系”企业家的代表人物。在《稻盛和夫经营学》“领导人...

原创小博客
今天
3
0
java框架学习日志-5(常见的依赖注入)

依赖注入(dependency injection) 之前提到控制反转(Inversion of Control)也叫依赖注入,它们其实是一个东西,只是看的角度不同,这章详细说一下依赖注入。 依赖——指bean对象创建依赖于...

白话
今天
4
0
红外接收器驱动开发

背景:使用系统的红外遥控软件没有反应,然后以为自己接线错误,反复测试,结果烧坏了一个红外接收器,信号主板没有问题。所以自己开发了一个红外接收器的python驱动。接线参见https://my.os...

mbzhong
今天
2
0
ActiveMQ消息传送机制以及ACK机制详解

AcitveMQ是作为一种消息存储和分发组件,涉及到client与broker端数据交互的方方面面,它不仅要担保消息的存储安全性,还要提供额外的手段来确保消息的分发是可靠的。 一. ActiveMQ消息传送机...

watermelon11
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部