做好一个开源项目有多难

背景

最近在尝试将项目内的动态化方案独立成一个Module,其实这个项目已经在GitHub完成了开源,即 RapidView ,那为什么还要去做这件事呢?这还要从当初的一个失误开始说起,当初作者开源时并没有立即把这个能力独立成一个库(or Module),而是从项目代码里面选择核心代码修改了一份作为开源项目。这个选择可以说是埋下了不少坑,笔者在最近几周内感受颇深,于是做一记录。

梳理

业务代码耦合问题

GitHub上的代码是滞后的,因为主工程(应用宝主工程代码)里的代码和开源出来的很多地方不一样,所以很多修改都不能及时同步出去。鉴于此,本次改造的基础代码就是工程里面的代码(而不是GitHub上的旧代码)。

由于长期缺乏规范和约束,导致RapidView和主工程代码有很多耦合,如

  • 使用主工程的日志开关和日志类,还有其他各种主工程的工具类

  • 基础控件和依赖于主工程扩展的控件没有区分

  • 逻辑里面耦合了主工程的统计上报逻辑、网络请求逻辑等不通用的逻辑

  • .....

诸如此类的问题,需要参考开源项目代码确定解决办法,基本原则是不通用的删掉,依赖的独立到Module里面。

这里不得不吐槽一下,之前主工程里面的代码一半是 Photon (原始的命名方式) 前缀命名,一半是 Rapid(因为以公司名义开源, Photon 不能使用) 命名,既然独立出来那就统一使用 Rapid ,这个问题才算是统一了。

感悟开源第一难:如何在主工程的快速迭代中保证 Module 部分足够独立,不受业务入侵(放在主工程里的时候,总有人会去做不合理修改,防不胜防),又能保持同步更新的节奏。

细节决定成败

总有人问我 “你觉得光子怎么样?”,我都会说“核心框架和设计思路很值得学习,就是很多细节做的不好。”

注:光子,就是我们的动态化方案, Photon的原意。因为开源关系,统一改成了 RapidView。所以这几个词说的都是同一个意思。

怎么说呢。下面是自己修改过程中遇到的一些典型Case:

  1. 单例写成这样,虽然大概率是手误,但是作为开源项目大概率是会让人觉得缺乏质量保证的(记得之前某团队开源前端项目就因为目录结构被知乎喷了)。

...
	public RapidAssetsLoader(){}
	public static synchronized RapidAssetsLoader getInstance(){
		if(sInstance == null){
			sInstance = new RapidAssetsLoader();
		}
		return sInstance;
	}
...
  1. 基本的风格问题,这个 update 方法是要提供给开发者经常使用的,但是传入参数的接口,有的是 view 在前,有的是 data 在前,还和数据类型(LuaTable)有关系,使用方踩坑概率目测80%+。

@Override
public  void  updateData(String view,  Map<String, Var> data)  {
	mAdapter.updateData(view, data);
}

@Override
public  void  updateData(String view,  LuaTable data,  Boolean clear)  {
	mAdapter.updateData(view, data, clear);
}

@Override
public  void  updateData(List<Map<String, Var>> dataList,  List<String> viewList)  {
	mAdapter.updateData(dataList, viewList,  false);
}

@Override
public  void  updateData(List<Map<String, Var>> dataList,  List<String> viewList,  Boolean clear)  {
	mAdapter.updateData(dataList, viewList, clear);
}
// 注意,参数突然变成先传viewList,上一个是dataList
@Override
public  void  updateData(LuaTable viewList,  LuaTable dataList,  Boolean clear)  {
	mAdapter.updateData(viewList, dataList, clear);
}

@Override
public  void  updateData(LuaTable viewList,  LuaTable dataList)  {
	mAdapter.updateData(viewList, dataList);
}

以上是个人选取的两个比较比较容易理解且典型的不足之处(由于已经开源,所以代码都是脱敏的)。

感悟开源第二难:如何把控好代码质量。

文档支持

之前在讨论为什么RapidView没有足够被开源界使用的时候,我就觉得缺少一个合格的文档。RapidView的文档对于一个完全不了解的人来说,可能不是那么容易上手,文档也缺乏层次:哪些是必须要知道的,哪些是作为进阶的,哪些是可以作为附录全部枚举出来的,哪些是隐藏规则需要补充说明的。

笔者也曾经思考过如何写好一份文档,发现还是很 难 的。在改造过程中,笔者也尝试补上了一个文档,当然由于时间紧张也不是十分完美。主要做了两件事:

  1. 自定义注解,从代码生成文档,降低了写文档和维护更新的成本:

@RapidTag(type = RapidTag.Type.action, description = "改变Binder中某一数据的值")
public class DataAction extends ActionObject {
    static final String DATAACTION = "dataaction";

    @RapidAttribution(description = "Binder里面的Key")
    private static final String KEY = "key";
    @RapidAttribution(description = "修改后的值")
    private static final String VALUE = "value";
......

生成的文档: 

2.使用GitBook等工具,重新组织排版,对读者更友好:

这里吐槽一下,原来代码的常量都是直接使用的,现在要一个个去提取出来,十几个还可以用快捷键,50个的直接暴走了

感悟开源第三难:如何提供文档、开发工具等周边支持。

网络部分

以光子的一个网络请求为例:

public class RapidRuntimeEngine {
	private IListener mListener = null;
	public interface IListener{
		void onfinish(boolean succeed, String md5, String url, int limitLevel);
	}
	public synchronized int sendRequest(String rapidID, IListener listener){
		return -1;
	}

	protected void onRequestFailed(final int seq, final int errorCode) {
		XLog.d(RapidConfig.RAPID_ERROR_TAG, "实时视图数据协议请求失败,errorcode:" + 			Integer.toString(errorCode));
		if( mListener == null ){
			return;
		}
		mListener.onfinish(false, null, null, -1);
	}

	protected synchronized void onRequestSuccessed(int seq, Object resp) {
		XLog.d(RapidConfig.RAPID_NORMAL_TAG, "实时视图数据协议请求成功");
		if( mListener == null ){
			return;
		}
		//mListener.onfinish(true, resp.zipMd5, resp.zipUrl, resp.limitLevel);
	}
}

为什么返回的数据面要带 zipMd5 、zipUrl 这些信息,limitLevel 是什么意思,都是很重要的(如果真的要用起来),但是这里直接一个注释pass掉了。这其实代表了一类典型问题, 当把一个能力独立出来的时候,如何把那些业务相关的部分做足够的封装,让使用者既能够知道怎么接入,又不迷失在细节里 ,抑或是根本没看到细节。

感悟开源第四难:如何屏蔽内部细节,让接入方/使用者完成闭环。

感悟

总的来说,瑕不掩瑜,RapidView还是有很多值得学习的地方,也有很多值得反思的案例,在此稍作梳理,以告来者,以醒后人。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值