30

雕虫晓技(一) 组件化

 6 years ago
source link: http://mp.weixin.qq.com/s/A2yd7DO1NvT0CEmzh_VwsQ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

雕虫晓技(一) 组件化

GcsSloop GcsSloop 2017-11-06 01:00 Posted on

本文是我工作这段时间的部分经验总结,仅从个人的角度谈一下对工作中编程的看法。

今年毕业出来工作,前期需要学习和实践的东西有很多,生活的节奏也在进行调节,因此就没有太多的精力去写文章了,从而导致我的“Android自定义View”系列文章一直处于停更状态。

其实并非没有时间,而是没有太多的精力投入到这上面,对于技术文章来说,如果想要写的通俗易懂,不误导读者,不仅需要对其中运用到的各个技术细节都进行考证,而且要花费大量的精力去梳理文章的脉络,并不是把所有知识点都罗列一遍就可以了,因此即便是一篇简单的文章,想要做好,也需要耗费不少的精力。

如果只是单纯的翻译或者总结一些前人的经验,写出来一篇文章是很容易的,但是我认为这样的文章是没有太大价值的,而且容易传播一些错误的观点,如果因为乱写误导了别人,反而不如不写。

由于出来工作了一段时间,参与的两个项目也都基本结束了,所以特地水一篇文章,来讲一下自己工作的感受,顺便总结一下这段时间收获的经验。

自己学习编程和工作中编程虽然基本是类似的,但也有很多的不同。

自己学的时候可以瞎胡搞,看到什么新东西都拿来玩玩,有大量的时间可以浪费,所以大部分的时间处于偏创造性的方向,总喜欢挑战一些自己没做过的东西,以保持新鲜感和对编程的热情。

但工作就不同了,工作中所需要开发的功能都很确定,因此大部分时间都是在写“比较枯燥”的业务代码,称为搬砖也不为过。因为从本质上来讲,写业务就是把一些现成的代码搬过来,再按照一定的顺序堆叠起来,最终完成这个业务。

尽管工作中大部分时间是在写业务,但写业务也是有不同的,如何在相同的实力下释放出更高的战斗力,让自己负责的业务更加坚固耐用,还是有些小技巧的。今天就和大家分享一个如何四两拨千金的方法。

普通开发流程

下面用一个小故事来引出本文主题(故事纯属虚构)。

小明参与开发了一个项目A,在项目A中有一个功能需要对视频中的音频进行处理,允许实时设置音频的均衡器,小明于是花了三天时间在项目A中开发出了一个模块A,用于处理音频均衡器。

项目A开发了一段时间之后,又来了一个项目B,同样有这个需求,于是小明把之前项目A中的模块复制到项目B中继续开发。

项目B开发了一段时间后发现模块A存在一个Bug,于是在项目B中对这个Bug进行了修复,等项目B告一段落,继续进行项目A开发时,想到了之前模块A中还存在这样一个问题,于是对照着项目B对项目A中对模块进行了修复。

整个流程像下面这样:

Image

由于两个项目都由小明负责,这个问题还是不大的,但是假如项目是多人合作的呢?小明在开发项目B时,项目A交给小刚负责继续开发,小刚也发现了模块A的Bug,也进行了修复,这样当小明继续回到项目A开发时,想要去修复模块A,发现模块A已经被修改了,经过检查对比后发现,小刚使用的修复方案稍有不同,但也管用,于是决定不对A项目进行修改了。

流程变成了下面这样子:

Image

于是,模块A在两个项目中就产生了一点点的不同,随着开发的继续,这些不同会逐渐的放大,项目A中和项目B中的模块会变的完全不同,发现Bug后,手动修复的成本也会大大的增加。最终,对于项目A中发现的问题,在项目A中进行修复后,无法将同样的方案应用于项目B,项目B中发现的Bug修复方案同样也无法应用于项目A,也就是说虽然两个项目中的模块同样用于处理音频均衡器,却拥有着不同的逻辑,无法兼容,并且逐渐变的难以维护。

维护两个相似但不兼容的模块是十分痛苦的,尤其是两个项目需要交替进行维护和开发的时候,很容易将两个模块弄混的,一不小心就可能会引发一些不必要的混乱。

既然如此,那么我们规定一下,谁的模块谁进行负责行吗?由谁进行负责就负责到底,别人不允许随便修改,不就能解决这个问题了吗?

答案是不行的,首先项目有自己的周期,有些项目可能会停滞非常长的时间才继续开发,谁又能记得住修改了哪些东西,其次,公司人员是流动的,可能会有人加入和离开,靠人员来保证自然是不靠谱的。

那么我们这样规定,修改任何一个模块的时候,需要不同项目中相同的模块都进行修改。

这个也是不靠谱的,首先,可能存在新来的同事对以前的项目不熟悉这一情况,其次,可能修改后的模块和之前不兼容,例如修改了某些调用方法,对所有项目都进行更新显然不靠谱,工作量太大了。

组件化开发流程

那么是否有更好的方案呢?

当然是有的,如果在开发项目A的时候就意识到该模块可以被复用,那么在开发之初就应当将模块当作一个组件独立出来,单独进行开发,之后在项目A中引用这个库即可,如果之前没有意识到,在开发项目B的时候意识到了,那么应该立即对项目A中该模块进行重构,将其独立出来,之后让两个项目同时引用同一个库,这样就避免了同时维护两个不兼容库的尴尬境地。

例如下面这样:

Image

其实这个流程相对于之前的流程来说,只不过是将其中的模块独立出来了而已,但是却能带来更多的好处。

1. 避免了不兼容问题: 两个项目同时引用同一个库,自然不会出现分化出两个不兼容版本,难以维护的问题。

2. 修复Bug方便: 如果在其中一个项目中发现了Bug,只需要到库中修复该问题,重新释放一个版本,之后到另一个项目中只需要修改一下版本号即可完成修复,而不是复制代码,手动合并。

3. 更稳定: 假如我想在模块中做一些优化,但是我并不能很确定这些优化不会引发Bug,我可以先释放一个测试版,在项目中进行测试,如果优化导致了一些问题的产生,我只用花几秒钟时间修改版本号就可以退回到稳定版,而不是到版本管理工具中去退回某个提交记录。

4. 节省时间: 相比于手动维护两个版本来说,这样显然更加节省开发时间,例如我因为一个项目的需要,在库中添加了新特性,当另一个项目也需要这些特性时,只需要修改一下版本号即可接入。

5. 快速更新: 即便是一个搁置了很久旧项目,在需要更新的时候,也可以查询一下组件更新记录,快速更新到最稳定的一个兼容版。

不仅如此,随着项目发展,这个库将会变的越来越完善,越来越稳定,后续的项目如果需要这些功能,花费几秒钟添加一下依赖,就能使用一个稳定的库。

组件使用版本号进行控制,通常是分三段 x.y.z (如:1.0.0),我一般是这样规定的:

  • 内容和接口没有变动,只是修复了Bug,或者内部状态,修改最后一位(如:1.0.1)。

  • 如果调用接口增加了,或者细微调整,修改中间位(如:1.1.0)。

  • 如果进行了大面积重构,接口完全不同了,修改第一位(如:2.0.0)。

下面是我自己的例子,在项目中引用自己的代码库。

Image

当然了,看到这里有不少小伙伴都会比较疑惑,作为公司的代码,有很多内容都是涉及到机密的,拿来开源总是不行的吧,你这样用不会出问题?

首先,能拿来独立作为库的代码一般都是一些通用代码,这部分代码通常是不会设计到具体业务逻辑的,自然也就不存在什么涉密了。
其次,这些代码并没有在公共的开源库上托管,而是隶属于内部私有服务器,出了公司就无法访问到了,而且它拥有完整的权限管理,如果不给权限,就算公司内部也看不了。

如果想要知道这些是如何做到的,可以Google搜索 “nexus maven 私服 搭建”,当然,百度也可以,限于篇幅和搭建方式比较容易,网上又有很多教程,我这里就不过多叙述了。

如果你的团队只有自己一个开发,可以直接将仓库部署到自己的电脑上,如果是多人合作型的,可以部署在内网服务器上。实在没有条件,不喜欢折腾的,也可以将独立仓库打包成aar格式的文件,之后在项目中使用这些文件,尽管用起来稍微麻烦一点,但也是选择之一。

花费一点时间搭建一个私服,所能节省的开发时间是超乎想象的,当然,如果想将项目中部分模块作为组件进行开发,一定要注意做好文档管理,记录好每次更新的内容,方便后期管理。例如我负责的一些模块,不仅在仓库上对文档源码进行了管理,本地也对每个版本的源码做了备份,例如我前段时间开源的 pager-layoutmanager,在本地是这样的:

Image

如果尝试组件化开发一段时间,积累了大量的基础组件,那么再开始新项目的时候就能更快速的去实现具体的需求,而不用在基础的组件上费功夫了。

关于组件化暂时就说到这里,当然了具体到现实的业务中,还有很多细节和技巧需要注意,不过这些东西还是自己去体会更好,听别人说的再多,终究不如自己实践一下记忆更深刻。

GcsSloop,一名 2.5 次元魔法师

Image

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK