文档章节

再次吐槽红薯的J2Cache

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

序言

以前写过两篇吐槽@红薯 的文章,吐槽一下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已经成熟,感兴趣的同学请移步查看

 

© 著作权归作者所有

共有 人打赏支持
悠悠然然

悠悠然然

粉丝 2381
博文 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.19 性能提升 30%,这不是 Bugfix 版本

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

红薯
05/23
0
44
关于J2cache ...

刚刚开始接触红薯大大的J2cache,在此感谢! 请教大家关于j2cache的一些问题: 1. j2cache的优缺点是什么呢? 2.它适用于什么场景,该怎样去用它? 在此拜谢诸位英雄好汉!谢谢!!...

磁爆步兵001
06/01
0
0
J2Cache 新增 Mybatis 支持模块,代码少到没 Bug

花了点时间撸了个 MyBatis 的 J2Cache 支持模块,含注释共八十多行代码 (J2CacheAdapter.java),再有 Bug 我就真的要退役了。 使用方法很简单,请看 https://gitee.com/ld/J2Cache/tree/mast...

红薯
05/15
0
30
J2Cache 2.3.17 发布,有 Bug 吐槽,不更新也吐槽

用 J2Cache 的开发者太多了,以至于 Bug 都被第一时间给你挑出来,所以直接导致每次发布完新版本紧接着又要发一个补丁版本。这就是人气啊! J2Cache 最新 bugfix 版本又来了,咋地,你还能打...

红薯
05/18
0
6
j2cache居然不支持集群的redis?

@红薯 是不是j2cache不支持集群模式的reids,我的redis是集群部署的,然后我看j2cache客户端好像用的是jedisclient,报异常redis.clients.jedis.exceptions.JedisMovedDataException : MOVED ...

潘meallon
07/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

74.expect脚本同步文件以及指定host同步文件 构建分发系统文件和命令

20.31 expect脚本同步文件: 在expect脚本中去实现在一台机器上把文件同步到另外一台机器上去。核心命令用的是rsync ~1.自动同步文件 #!/usr/bin/expect set passwd "123456" spawn rsync -a...

王鑫linux
24分钟前
0
0
TypeScript项目引用(project references)

转发 TypeScript项目引用(project references) TypeScript新特性之项目引用(project references) 项目引用是TypeScript 3.0中的一项新功能,允许您将TypeScript程序构建为更小的部分。 通过这...

durban
29分钟前
0
0
爬虫入门

导读 网络爬虫(Web crawler),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本,它们被广泛用于互联网搜索引擎或其他类似网站,可以自动采集所有其能够访问到的页面内容,以获取...

问题终结者
29分钟前
0
0
ppwjs之bootstrap文字排版:无序列表项不换行

<!DOCTYPT html><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>ppwjs欢迎您</title><link rel="icon" href="/favicon.ico" ......

ppwjs
36分钟前
0
0
SpringBoot 学习一

本文将从以下几个方面介绍: 前言 HelloWorld 读取配置文件 例子(CURD) 前言 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架...

tsmyk0715
36分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部