如何写出一份“有理有据使人信服”的 Android 项目设计文档
设计文档的结构
一个好的项目设计文档,其实有一定的模板可以参考的,不过不管模板怎么变,大致都需要有以下几个大框架
项目背景
项目术语
技术挑战
完成要求
4.1. App 性能要求 (可选)
4.2. App Size 要求 (可选)
现有架构(可选)
建议架构
6.1. 引入的第三方框架/SDK 的简介 (可选)
开发时间线
其他可选架构(可选)
参考文献
咱先从项目背景开始聊
项目背景
如果大家面试次数够多,应该会有听过一个叫 STAR 原则的东西,就是介绍自己项目的时候要遵循 Situation(背景)->Target(目标)->Action(行动/做法)->Result(结果)这样的顺序,尽量做到简洁。
同样的,项目背景的介绍就是对应了这个 STAR 原则的 S,也可以说是项目的动机,为什么要做这个项目。
这个背景和动机可以是一个产品产生的动机。比如说抖鹰
的产品经理发现竞品快脚
发提供了一个新的视频滤镜,而且这个滤镜在竞品快脚
中迅速攀升到用户热度的第一位了,基于我们在产品的数据分析中 blalala。。。于是我们也要做这个滤镜。这就是一个简洁明了的项目背景。当然这个背景也可以是一个纯技术方面的问题,比如架构的升级等等,当然如果是架构的升级,那需要在背景里面简单的介绍现有架构的大概的一些局限性(我们下文会提到)。
本人阅读过的一些经典反例就是,背景介绍的第一句话上来就开始直接飙产品/公司内部的一些黑话,比如某个 sqlite 的 database 的某一个 col 有问题啊,或者是公司内部的一个 SDK 的限制等等。这些都是技术细节,不是项目大背景。提前把这些细节说出来是没法在第一段就抓住读者的眼
球的,这会让读者失去仔细观看全文的热情,导致最后你的设计文档可能收不到任何有意义的反馈。
项目术语
这一部分就更重要了。项目术语这个部分必须要尽可能的把设计中涉及到的:
新引用的 SDK/框架
项目之前没用过的语言
项目/公司内部工具,服务
产品本身的组件 Component.
都过一遍,尤其是对一些刚刚进组的朋友,这对他们会有很大的帮助。很多刚刚入职的朋友初来乍到,可能也不太敢在研讨会上问问题,阅读没有项目术语的文档对他们可以说是直接劝退的。作为一个往高级工程师方向努力的朋友们,扩大自己在组内影响力也是一个至关重要的点,如果你的设计文档可以对初级工程师/刚刚进组的朋友更友好,那么你已经成功了一半了。很多在组里面待了很久的老鸟会懒得在产品本身的组件Component
解释太多,因为他们想当然的会觉得这是一个他自己每天都接触的组件没有必要解释。这其实是不太好的,因为你的文档不是给自己看的,而是给其他组员,甚至老板(老板很多情况下是不了解产品的技术细节的)。
比如你在新的项目中打算使用 GraphQL 这个查询语言和相应的框架。那么最好的做法是先在术语环节介绍一下:
GraphQL -> 是一种针对图状数据进行查询特别有优势的查询语言
GraphQL Query-> 一种类似于 HTTP GET 的 GraphQL 请求,用来查询后端数据
GraphQL Mutation-> 一种类似于 HTTP POST 的 GraphQL 请求,用来修改后端数据
GraphQL Subscription-> 一种建立在客户端和后端之间的长链接,用来监听后端数据变化请求,大部分 GraphQL 框架用 websocket 来实现
有了这上面的介绍,相信你在接下来设计细节说到 Query/Mutation 的时候就不会有人懵逼了。
技术挑战
这个环节就比较简单了,把该项目的技术难点都列举出来,但是有一个问题要切记:
不要贴源码!不要贴源码!不要贴源码!
很多朋友,包括在写博客的时候都是一言不合直接复制粘贴源码,这样的做法是非常让人讨厌的,说白了就是偷懒,连精炼一下源码,哪怕做一份伪代码加 comment 的功夫都不肯下。还是那句话,文档是写给别人看的,不是写给自己的。
这里我用 KunMinX [juejin.im/user/108157…](
) 大哥的博客里面的伪代码做正面 例子,大家如果看到这一份安卓事件分发的源代码 (KunMinX 大哥如果你看到了觉得不想自己的例子被放进我的文章,请联系我,会及时删掉并替换,在这里先感谢你):
@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onTouchEvent(ev, 1);}// If the event targets the accessibility focused view and this is it, start// normal event dispatch. Maybe a descendant is what will handle the click.if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {ev.setTargetAccessibilityFocus(false);}boolean handled = false;if (onFilterTouchEventForSecurity(ev)) {final int action = ev.getAction();final int actionMasked = action & MotionEvent.ACTION_MASK;// Handle an initial down.if (actionMasked == MotionEvent.ACTION_DOWN) {// Throw away all previous state when starting a new touch gesture.// The framework may have dropped the up or cancel event for the previous gesture// due to an app switch, ANR, or some other state change.cancelAndClearTouchTargets(ev);resetTouchState();}// Check for interception.final boolean intercepted;if (actionMasked == MotionEvent.ACTION_DOWN|| mFirstTouchTarget != null) {final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;if (!disallowIntercept) {intercepted = onInterceptTouchEvent(ev);ev.setAction(action); // restore action in case it was changed} else {intercepted = false;}} else {// There are no touch targets and this action is not an initial down// so this view group continues to intercept touches.intercepted = true;}// If intercepted, start normal event dispatch. Also if there is already// a view that is handling the gesture, do normal event dispatch.if (intercepted || mFirstTouchTarget != null) {ev.setTargetAccessibilityFocus(false);}
是不是瞬间没有任何兴趣了?请注意我还没有全部都复制上来,就只是一小段而已。
再看 KunMinX 大哥的精简版伪代码:
[juejin.im/post/684490…](
)
是不是瞬间就豁然开朗了。
写文档也是这样,如果我是审查者看到上来就贴项目内部的源代码的设计文档,对不起,我会直接打零分,贴源代码的设计文档,像极了初中的时候为了凑八百字而生硬的加排比句的作文一样,看起来很丰满,其实都是骨头没有肉。当你自己想钻研技术的时候,一行行的研究源码是没毛病的,但是如果你是要分享给他人的时候,千万别直接复制粘贴。
完成要求
这个环节也不多做介绍,这是和公司/产品内部的需求有关系。比如你做结构的修改,做完之后是否会影响到原有的开发流程,如果有,是否会严重的影响,这些都是需要列出来的。
现有架构和建议架构
一提到架构,很多人都会觉得很虚,感觉无从下手。其实在这方面,流程图和组件通信图都是很好的帮手。有时候可能自己会觉得无从写起,但是其实只要把流程图/组件通信图一画,其实就豁然开朗了。
评论