如何写好技术文档
Posted 会说话的皮卡丘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何写好技术文档相关的知识,希望对你有一定的参考价值。
简单介绍一下为什么要写这篇文章吧,入职接近一年了,越来越感觉技术文档是非常重要的,当然也和需求文档有关,需求文档清晰完整会大大降低后端RD整理技术文档的成本,但是一个合格的技术不仅仅应该能够应对这种简单的情况,即使是在相关资源缺失的情况下也应该能够cover好自己的工作并且拿到好的结果,当然了这些不是必选项,但是我个人理解是优势,想要走的更远,就必须具备在恶劣环境下拿结果的能力,在简单的情况下拿结果对能力的要求相对较低,在复杂的情况下拿结果才能在任何时候都能保质保量的交付产品。
这次的技术文档框架均建立在PM不合格的情况下的,技术Owner向前走一步,承担起PM的责任并且主导整个流程的假设下,并且由于我自己的工作年限也只有一年,经验不是很丰富,只能尽我所能的梳理一些我能想到的模块,如果有更好的建议欢迎在评论区提出
1.需求文档
一个良好的技术文档一定是建立在良好的需求文档上的,身为技术人员,在发现PM的需求文档有问题的时候应该第一时间发现,并且意识到存在哪些问题
个人认为一个好的文档应该包含包含背景,收益,用户交互图,技术指标,项目交付时间等模块,其中可以使用5W1H方法进行分析
当我们需要解决一个复杂的问题时,"5W1H"框架可以帮助我们全面了解和分析问题,下面是一个例子:
假设我们要解决一个公司的销售下滑问题,我们可以使用"5W1H"框架来分析和解决这个问题:
What(什么):我们需要了解下滑的销售指的是哪个产品或服务的销售额在下降,是某个地区的还是整个公司的销售额下降等。
Who(谁):我们需要了解哪些人或者团队参与到销售流程中,包括销售团队、客户服务团队、市场营销团队等。
Where(哪里):我们需要了解下降的销售发生在哪个市场或地区,是否有一些地区销售依然不错等。
When(何时):我们需要了解销售下滑的时间范围和趋势,是否是季节性的变化还是持续下降等。
Why(为什么):我们需要了解为什么销售会下降,可能的原因包括市场竞争加剧、产品质量下降、价格竞争加剧等。
How(如何):我们需要制定具体的解决方案和实施计划,例如加强市场调研、改进销售流程、提高产品质量、制定更合理的价格策略等。
通过以上"5W1H"的分析,我们可以更全面地了解销售下滑的问题,找到问题的根源,并制定相应的解决方案和实施计划。
当我们发现pm的交付的需求文档不达标时,可以记录下todo让其修改,同时如果信息缺失太多,应该将需求文档打回。
个人认为需求评审的过程中,研发最主要的事情有两个,梳理清楚pm要做什么,以及判断能不能做,其实我之前还喜欢评估这个需求有没有价值,但是后来逐渐分清了rd和pm的职责
在需求评审的过程中,研发团队可以就需求的技术实现难度和风险等方面提出自己的看法和建议,但是研发团队并不是收益的最终决策者,因此不应该独自判断需求的收益。
产品的收益和用户价值需要综合考虑,需要通过市场调研、用户调查等方式了解用户需求和反馈,同时也需要考虑市场竞争、产品定位等因素,最终由产品经理来做出综合判断和决策。
因此,后来我会从研发的视角提出这个需求某个模块(我认为收益和投入不成正比的部分)的实现复杂度以及我所认为的收益,然后给pm提出合理的建议,如果pm执意坚持,我会同意他的观点并在会后和老板讨论这个问题,由老板来做最终的决策,我认为这是一个完整的流程。
上面梳理完了需求评审我应该做的事情,下面说一下技术评审我需要做的事情
2.技术评审
技术评审一般由后端RD发起,技术评审是为了保证需求的技术实现方案的合理性、可行性和高效性,从而确保产品的稳定性、安全性和可维护性,保障项目的进度和质量。技术评审也是一个团队合作的过程,需要各个团队成员共同协作,确保产品开发的成功实现。
一般来讲,就我个人而言,我认为一个好的技术方案应该是具备可行性、可扩展性、安全性、高效性和成本效益的,并且具有可读性、可维护性和可测试性等特点,能够全面满足需求和业务要求,并且能够提高团队的开发效率和协同能力。
另外最重要的一点,技术方案一定要让人看懂
从我自己来说,我自己整理了一套技术方案的框架
业务需求
首先是背景和收益,你要让参加你技术评审的人知道你要做什么(what),为什么要做这件事(why)
需求分析
然后是本次技术方案要实现的功能
概要设计
(如果涉及到一些特殊名词最好做一些详细解释)
需求的架构图
需求的时序图
详细设计
前后端的接口文档,
模块依赖关系以及开发量,
具体实现
相关同学的排期(前端,后端,qa,数仓同学的排期),
回滚预案
会议纪要(todo list)
最后要附上相关的参考文档,比如需求文档,前端同学的技术文档等等
除此之外,会议纪要也是非常重要的一部分,这个单纯看个人,因为我自己的记忆力比较差,除此之外由于团队的一些问题相对混乱,因此每次开会我都会把各个同学要做的事情记在最后(落实到人,具体时间,给到相应结果)并且会后在群内抛出,并约定相应时间定期review进度,如果有风险可以提前报漏
如何写好 DevOps 的文档
每个DevOps都一个百宝箱,里面放着各种命令行脚本,可以用来自动化各式任务。但若文档不全,即便是脚本的作者,时间一久也不敢随便乱用,毕竟运维的大部分工作是管理生产环境,要是出了错,不是轻描淡写就可以蒙混过关的。写好 DevOps 的文档其实也是一门技术活儿,这里给大家分享一些组织运维脚本及其文档的经验。
Fabric的任务管理与文档
在以前的文章中,我们曾经介绍过Glow使用了fabric来执行各种日常管理的任务。Fabric提供了非常好用的任务组织以及查阅任务文档的功能。
Fabric的主文件一般命名为fabfile.py,但任务多了,都写在一个文件里显然很难维护。Fabric有一个很实用的特性,就是当fabfile.py里导入其他模块时,会自动发现里面的fabric任务。利用这个特性,可以把各种任务分类写在不同的模块中,然后在fabfile.py中统一导入。比如 Glow 的 DevOps 代码库的结构大概长这个样子:
$ tree
├── __init__.py
├── fabfile.py
├── fab_scripts
│ ├── __init__.py
│ ├── monitors.py
│ ├── mysql.py
│ ├── nginx.py
│ ├── redis.py
│ ├── scaling.py
│ ├── services.py
在fabfile.py里除了一些最核心的任务脚本外,主要就是一些import语句
# fabfile.pyfrom fab_scripts import monitors
from fab_scripts import mysql
from fab_scripts import nginx
from fab_scripts import redis
from fab_scripts import scaling
from fab_scripts import services
这样我们就把散落在多个文件里的任务聚集到了一起,我们可以用fab -l来列出所有可执行的任务及其描述,其中任务描述来自于对应任务的第一行docstring。例如,
$ fab -lAvailable commands: monitors.get Get YAML definition of monitors monitors.list List names of all monitors monitors.mute Mute specific groups of monitors monitors.mute_all Mute all monitors globally monitors.unmute Unmute specific groups of monitors monitors.unmute_all Unmute all monitors globally mysql.connection_list Show number of DB connections group by host mysql.connection_sources Show number of DB connections group by process nginx.turn_off_maintenance Turn off site maintenance mode. nginx.turn_on_maintenance Turn on site maintenance mode. Return 503. redis.auto_save Update saving settings for redis instances redis.start_slave Set master and start replication. redis.stop_slave Stop replication and set its master to none. scaling.add_servers Launch more instances in specific server group scaling.create_image Create an image for provisioning new instances scaling.get_latest_tag Get latest tag of deployed code services.cycle Restart application services. services.start Start application services. services.stop Stop application services.
这里可以看到,将任务分写在不同的模块,模块名就起到了Namespace的作用。在显示命令列表时,在同一个Namespace下的命令被聚集到了一起,很好地起到了任务分类的作用。使用fab -d [task_name]可以显示该任务完整的docstring。规整的docstring可以让执行任务的用户清楚地理解其作用及参数用法。我们在写fabric任务的docstring时,一般分为三个部分
任务的简单介绍
任务的参数
具体用例
最后一点由为重要,有些任务参数众多,即使读了参数说明,仍会让人有些云里雾里。但几个典型的实际用例,对于用户了解任务的用法会起到至关重要的作用。在下面的例子中,我们展示了deploy任务(代码部署)的说明文档
$ fab -d deploy
Displaying detailed information for task 'deploy':
Deploy code to targeted server_group.
You need put ansible vault password at ~/.ansible_vault_passwd directory,
otherwise you would be prompt to enter vault password.
Args:
server_group: Possible values include prod, stage
release_tags: A list of release tags to be pushed
Examples: # Deploy to stage
fab deploy:stage,glow_stage_1446102452 # Deploy to production
fab deploy:prod,glow_prod_1446102452 # Deploy multiple repo at once
fab deploy:prod,glow_prod_1446102452,nurture_prod_1445102467
动态Docstring
在Python中,docstring其实就是函数的__doc__的属性,所以我们可以像修改普通变量那样动态修改docstring,这给我们生成动态文档或是重用公共的文档提供了可能。例如,我们的services模块下有cycle,start,stop三个任务,分别用来重启,开始,停止我们的microservice。我们当然希望在用fab -d来查看任务的文档说明时,同时可以显示所有可用的microservice。但hard-coded现有的microservice是一个愚蠢的做法,这样我们不但需要把同一段文档复制三份,并且每次新增一个microservice时还要记得来更新文档。这里我们用Python的decorator来动态地把可用服务的信息添加到docstring中。比如cycle任务的定义是这样的:
@task@services_docdef cycle(*services, **kwargs):
"""Restart application services.
Args:
services: list of services need cycle (separate by comma)
Examples:
fab services.cycle:glow-www,glow-forum
"""
注意到这里用了@service_doc这个decorator,它的定义如下:
def services_doc(func):
services = get_available_services()
doc = """
Possible values for services:
{}
""".format(" ".join(" " * 8 + x for x in services))
func.__doc__ += doc return func
我们通过get_available_services来动态取得当前环境下可用的microservice(这里我们不关心get_available_service是如何实现的),并将其添加到函数的docstring之后。这样,当我们查看cycle的方法时,所有可用的microservice也会显示出来。
$ fab -d services.cycle Displaying detailed information for task 'services.cycle': Restart application services Args: services: list of services need cycle (separate by comma) Examples: fab services.cycle:glow-www,glow-forum Possible values for services: glow-www glow-user glow-forum ...
动态外部文档
除了docstring,我们也经常需要写独立的外部文档。在Glow,这些文档绝大部分都是用Markdown来写的。例如,我们需要写一个介绍生产环境架构的文档,其中肯定会加入生产环境中有哪些服务器,每个服务器的功能描述以及它们的hostname。我们可以用手动的方式来写,但每当为生产环境添加新服务器时,我们必须记得更新这份文档。
而实际情况是,我们从来不在AWS的控制台手动创建服务器,所有的服务器都是由Ansible来创建与维护的。也就是说,所有的服务器配置信息及其功能描述都已经存在于Ansible的playbook中。当我们写外部文档时,应该去引用Ansible中的信息,而不是重写手写一遍。
所以在我们的生产环境文档中会利用HTML注释来指定需要外部引用的部分,然后通过执行脚本将这些引用的内容填充至文档里。例如,在我们的生产环境文档中有这样一段:
## EC2 servers<!-- BEGIN EC2-SERVER-LIST --> | Server group | Instance type | Count | Description |
|:-------------|:--------------|------:|:----------------------|
| bastion | t2.small | 1 | Bastion/Jumper server |
| www | c3.large | 4 | Web servers |
...<!-- END EC2-SERVER-LIST -->
这里<!-- BEGIN EC2-SERVER-LIST -->和<!-- END EC2-SERVER-LIST -->之间的表格就是一个外部引用,每次Ansible更新服务器配置时,会执行一个脚本,它会自动在文档中查找这对标签,并更新其中的内容。这是一个很简单的技术,但对于保持文档与实际环境同步很有帮助。
小结
几乎所有人都承认文档的重要性,但真正愿意在文档上花费精力的团队却十分有限。写这篇文章是希望大家能意识到,文档其实也是代码的一部分,也应该遵循DRY原则,也可以通过编程的手段来动态生成与自动更新。
好消息!第一批研发运营一体化(DevOps)能力成熟度模型 第3部分:持续交付评估火热报名中!
一、评估项目
研发运营一体化(DevOps)能力成熟度模型 第3部分:持续交付评估
二、参考标准
《研发运营一体化(DevOps)能力成熟度模型 第3部分:持续交付》
三、报名截止时间
2018年9月1日
四、报名步骤
五、评估咨询
联系人:牛晓玲
联系方式:010-62300559
邮箱:niuxiaoling@caict.ac.cn
六、培训咨询
联系人:杨文惠
联系方式:13021086339
邮箱:yangwenhui@greatops.net
以上是关于如何写好技术文档的主要内容,如果未能解决你的问题,请参考以下文章