一年前,我开始在彭博社全职工作。 然后我决定写这篇文章。 我以为我会充满想法,可以在时机成熟时抛在纸上。 但是一个月之内,我意识到一切都不会那么简单:我已经开始忘记自己学到的东西。 要么获得的知识如此之好,以至于我的头脑使我相信自己一直都知道,或者它们只是从我脑海中飞了出来。
1个这就是我开始写日记的原因之一。 每天,我进入有趣的情况,对它们进行描述。 还要感谢我坐在领先的程序员旁边的事实。 我可以仔细观察他的工作,并发现它与我的工作有何不同。 我们一起编写了很多程序,这使我的观察变得更加容易。 而且,我们的团队不谴责“监视”编写代码的人。 当我觉得正在发生一些有趣的事情时,我转身看了看。 由于不断上升,我一直都知道发生了什么。
我在领先的程序员旁边呆了一年。 这是我学到的。
目录内容
代码编写
如何在代码中命名事物
我的首要任务之一是在React UI上工作。 我们有一个包含所有其他组件的主要组件。 我喜欢在代码中添加一些幽默感,并且想命名
GodComponent
的主要组件。 现在是审查代码的时候了,我明白了为什么这么难给名字起名字。
我命名的每一段代码都有一个隐含的目的。
GodComponent
? 这是得到所有我不想放在正确位置的垃圾的组件。 它包含了一切。 将其命名为
LayoutComponent
,将来我会决定该组件分配一个布局。 它不包含状态。
我学到的另一个重要经验教训是,如果某个东西看起来太大了,例如带有一堆业务逻辑的
LayoutComponent
,那么是时候对其进行重构了,因为这里不应该有业务逻辑。 对于名称为
GodComponent
情况,业务逻辑
GodComponent
存在将无关紧要。
需要命名集群吗? 在它们上运行的服务之后调用它们是一个好主意,直到您在这些集群上运行其他东西为止。 我们给他们起了一个名字,以纪念我们的团队。
同样的事情也适用于功能。
doEverything()
是一个可怕的名称,具有许多后果。 如果函数执行所有操作,将很难测试其各个部分。 不管这个功能有多大,对您来说它永远不会太陌生,因为它应该做的一切。 因此更改名称。 反驳。
一个有意义的名字有一个缺点。 突然间,这个名称将变得太有意义了,并且隐藏了某种细微差别? 例如,当在SQLAlchemy中调用
session.close()
时,
关闭会话不会关闭数据库连接。 我应该已经阅读了文档并防止了该错误,有关
自行车问题的更多信息,请参见。
从这个角度来看,将函数命名为
x
,
y
,
z
而不是
count()
,
close()
,
insertIntoDB()
不允许我们赋予某些含义,并且让我仔细监视这些函数的作用。
2我从没想过要写多于一行文本的命名原则。
继承的代码和下一个开发人员
您是否看过代码,对您来说似乎很奇怪? 你为什么写那个? 这没有道理。
我有机会使用继承的代码库。 您知道这点,并带有“当穆罕默德了解情况时取消注释代码”之类的注释。 你在这做什么 谁是穆罕默德?
我可以切换角色并考虑将要得到我代码的那个人,他觉得这很奇怪吗? 对您的代码进行部分审查有助于同事审查您的代码。 这使我想到了上下文:我需要记住团队工作的上下文。
如果我忘记了此代码,请稍后返回并无法恢复上下文,我会说:“他们到底在做什么? 这很愚蠢……啊,等等,我做到了。”
代码中的文档和注释在这里起作用。
代码中的文档和注释
它们有助于保持环境并传达知识。 正如Lee在“
如何构建好的软件”中所说:
软件的主要价值不在于所创建的代码,而在于其创建者所积累的知识
您有一个似乎没有人使用过的开放客户端API端点。 是否只需要删除? 一般来说,这是一项技术义务。 如果我告诉你,在一个国家中,有10位记者每年将他们的报告发送到该端点一次? 如何检查? 如果(在文档中)未提及,则无法对其进行检查。 我们尚未检查。 他们将其删除,几个月后,这一年非常重要。 十个新闻记者无法发送他们的重要报告,因为终点不再存在。 具有产品知识的人员已经离开团队。 当然,现在在代码中有注释解释了为什么这样做是必要的。
据我所知,每个团队都在努力处理文档。 有了文档,不仅通过代码,而且还通过与之相关的流程。
我们尚未提出完美的解决方案。 就个人而言,我喜欢Antirez将代码中的注释
分成不同类型的值的方式 。
原子提交
如果您需要回滚(并且需要它。请参见“
测试”一章),那么作为单个模块进行此提交是否有意义?
如何自信地删除糟糕的代码
我非常不高兴删除糟糕或过时的代码。 在我看来,几个世纪以前写的一切都是神圣的。 我想:“当他们这样写的时候,他们会想到一些东西。” 一方面,这是传统与文化之间的对抗,另一方面是“基本原理”风格的思考。 这与删除年度端点相同。 我上了一堂特别的课。
3我将尝试绕过代码,而领先的开发人员将尝试通过它。 删除它。 如果无法访问if表达式? 是的,我们擦除。 我做了什么 我只是在上面写了我的函数。 我没有减少技术债务。 无论如何,我只是增加了代码的复杂性和转发。 下一个人将图片拼凑起来将更加困难。
根据经验,我得出的结论是:有些代码您不理解,但是绝对不会与您联系。 删除您不联系的代码,并小心不了解的代码。
代码审查
代码审查是一个很好的自我教育工具。 这是一个外部反馈循环,显示了他们将如何编写代码以及如何编写代码。 有什么区别? 一种方法比另一种更好? 我在每次评论时都问自己:“他们为什么这么写?” 如果他找不到合适的答案,他就去问。
第一个月之后,我开始发现同事代码中的错误(就像我在我的同事中发现的那样)。 这是某种疯狂。 这篇评论对我来说变得更加有趣,它变成了我所缺少的游戏,并且改善了我的“代码意识”。
以我的经验,在我了解代码的工作方式之前,您无需批准代码。
我的github统计信息。测试中
我爱上了测试,以至于没有测试就无法在代码库中编写代码。
如果您的应用程序只做一件事(就像我所有的学校项目一样),那么您仍然可以手动进行测试。
4这正是我所做的。 但是,如果应用程序执行100个不同的任务会怎样? 我不想花半个小时进行测试,有时我看不到某些东西。 一场噩梦。
测试和测试自动化在这里有帮助。
我将测试视为文档。 这是我关于代码的想法的文档。 测试告诉我(或我之前的其他人)如何想象代码的工作以及预期的错误之处。
今天,当我编写测试时,我尝试:
- 展示如何使用测试类,函数或系统。
- 显示我认为可能出问题的地方。
结果,我经常测试行为,而不测试实现(
这是我在Google休息期间选择的
一个示例 )。
在第2段中,我没有提及错误的来源。
当我发现错误时,请确保该修复程序具有适当的测试(称为回归测试)来记录信息。 这是可能出问题的另一个原因。
5当然,代码质量的提高不是因为我编写测试,而是因为我编写了代码。 但是阅读测试有助于我更好地了解情况并编写更好的代码。
这是测试的一般情况。
但这不是我应用的唯一测试。 我说的是部署环境。 您可能有理想的单元测试,但是如果没有系统测试,可能会发生以下情况:

这也适用于经过良好测试的代码:如果您的计算机上没有必需的库,则所有内容都会崩溃。
- 您正在开发机器(所有模因的来源,例如“它在我的计算机上工作过!”)。
- 有些机器正在测试(可能与之前的机器一致)。
- 最后,有些机器要在其上进行部署(它们不应与您所开发的机器相吻合)。
如果测试和部署环境在计算机上不匹配,则将出现问题。 部署环境将有助于避免这种情况。
我们正在计算机上的Docker中进行本地开发。
我们有一个开发环境,这些计算机配备了一组库(和开发工具),在这里我们安装了书面代码。 在这里可以使用所有必要的系统进行测试。 我们还有一个Beta /登台环境,可以完全重复操作环境。 最后,我们有一个操作环境-可以为客户执行代码的机器。
这个想法是要捕获在单元和系统测试期间尚未出现的错误。 例如,请求系统和响应系统之间的API差异。 我认为对于个人项目或小型公司,情况可能会完全不同。 并非每个人都有机会创建自己的基础架构。 但是,您可以求助于AWS和Azure等云服务。
您可以配置单个集群以进行开发和操作。 AWS ECS使用Docker映像进行部署,因此不同环境中的流程将相对一致。 不同的AWS服务之间的集成存在细微差别。 您是否在正确的环境中调用正确的端点?
您甚至可以走得更远:下载其他AWS服务的替代容器映像,并设置一个基于Docker-Compose的本地功能齐全的本地环境。 这加快了反馈循环。
6也许当我创建并启动我的副项目时,我会获得更多经验。
降低风险
您可以采取哪些步骤来减少灾难风险? 如果我们正在谈论新的根本性变化,那么如果出现问题,我们如何验证最小的停机时间? “由于所有这些新更改,我们不需要完全部署系统。” 到底是什么 我为什么不考虑呢!
建筑学
为什么在编写代码和测试后谈论架构? 它可以放在第一位,但是如果我没有在所使用的环境中进行编程和测试,则可能无法成功创建一个考虑该环境特征的体系结构。
7
创建架构时,您需要考虑很多。
- 数字将如何使用?
- 会有多少用户? 它们的数量可以增加多少(数据库中的行数取决于此)?
- 哪些礁石可以相遇?
我需要将其转换为一个名为“声明收集”的清单。 目前我经验不足,明年尝试在彭博社做。 这个过程在很大程度上与敏捷相反:在进行实施之前,您可以设计多少架构? 一切都与平衡有关,您需要选择何时以及要做什么。 什么时候向前冲有意义,什么时候-向后退? 当然,收集要求并不等于考虑所有问题。 我认为,如果我们将开发过程包括在设计中,那将会有所收获。 例如:
- 当地发展将如何进行?
- 我们将如何打包和部署?
- 我们将如何进行端到端测试?
- 我们将如何对新服务进行压力测试?
- 我们将如何保守秘密?
- CI / CD集成?
我们最近为
BNEF开发了一个新的搜索引擎。 进行这项工作真是太棒了,我组织了一次本地开发,并了解了DPG(软件包及其部署),并秘密进行了部署。
谁会想到将秘密部署到产品上可能如此简单:
- 无法将它们放置在代码中,因为有人可以注意到它们
- 要将其存储为环境变量,因为规范提供了12个应用因素? 这不是一个坏主意,但是如何将它们放置在那里? (每次开车时都要去产品上填写环境变量,这很痛苦)
- 将它们部署为文件? 但是它们将来自何处以及如何填充它们?
我们不想手动做所有事情。
结果,我们进入了具有基于角色的访问控制的数据库(只有我们和我们的计算机可以与数据库通信)。 我们的代码在启动时会从数据库接收秘密。 在开发,登台和操作环境的框架内可以很好地复制此方法;机密存储在适当的数据库中。
同样,对于像AWS这样的云服务,情况可能完全不同。 您无需以某种方式照顾秘密。 为您的角色获得一个帐户,在界面中输入机密,然后您的代码将在需要时找到它们。 这极大地简化了一切,但是我很高兴获得了经验,因此我很欣赏这种简单性。
我们创建架构,而不忘记维护
系统设计令人鼓舞。 和护送? 不会太多 我在伴游世界中的旅程使我想到一个问题:系统为何以及如何退化? 答案的第一部分与所有已过时的退役无关,而只是增加了一个新的。 倾向于添加而不是删除(与任何事物都不相似吗?)。 第二部分是在设计时牢记最终目标。 随着时间的流逝,系统开始执行原本不希望的工作的系统,不一定会像最初为相同任务设计的系统那样工作。 这是一种后退式的方法,而不是技巧。
我至少知道三种降低降解速率的方法。
- 独立的业务逻辑和基础架构:基础架构通常会退化-负载增加,框架变得过时,出现零日漏洞等。
- 创建流程以获得将来的支持。 对旧位和新位应用相同的更新。 这样可以防止新旧代码之间的差异,并使所有代码保持在“现代”状态。
- 确保丢弃所有不必要的和过时的东西。
部署方式
我会打包功能还是一次部署一个? 根据当前的过程,如果将它们打包在一起,请等待故障。 问自己为什么要打包功能?
无论是什么原因,都需要纠正这种情况。 我至少知道两个与包装有关的问题:
- 如果其中一个功能有问题,您自己可以阻止所有功能。
- 您增加了问题的风险。
无论选择哪种部署过程,您始终希望您的汽车像牲畜,而不像宠物。 它们不是唯一的。 您确切地知道每台计算机上执行了什么,如何在死机时重新创建它们。 如果有任何一辆汽车死了,您不会感到沮丧,您只需接一辆新车。 你放牧他们,而不是成长。
当出现问题时
万一出了问题,而且确实如此,那么就有一条黄金法则:将对客户的影响降至最低。 万一发生故障,我的第一个愿望就是修复它。 这似乎不是最佳解决方案。 即使可以一行完成,也不需要固定,而是需要先回滚。 返回到先前的操作状态。 这是使客户恢复工作版本的最快方法。 只有这样,我才能找出问题所在并加以解决。
这同样适用于群集中的“损坏”计算机:在找出发生了什么事之前将其关闭,将其标记为不可访问。 我感到奇怪的是,我的天生欲望和本能与最佳解决方案相抵触。
我认为这种本能还导致我更长时间地修复错误。 有时候,我意识到有些事情是行不通的,因为我编写的代码某种程度上是错误的,于是我疯狂地看着每一行。 类似于“先深入”搜索。 事实证明问题是由于配置更改引起的,也就是说,我没有首先检查它,这种情况使我感到不安。 我浪费了很多时间寻找错误。
从那时起,我学会了搜索“广度优先”,因此已经“深度优先”以排除高层原因。 我可以用当前资源确切地确认什么?
- 汽车行吗?
- 代码是否正确安装?
- 有配置吗?
- <特定于代码的配置>,例如,路由拼写是否正确?
- 架构版本是否正确?
- 然后,我投入到代码中。
我们认为nginx的安装不正确,但事实证明只是配置被禁用
当然,我不需要每次都这样做。 有时仅是一条错误消息就足以立即了解代码。 当我无法确定原因时,我尝试最小化代码更改的数量以找到原因。 变化越少,我就能更快地找到问题的真正根源。 另外,现在我有一个关于错误的备忘录,这使我节省了一个多小时的时间来思考“我错过了什么?” 有时我忘了最简单的检查,例如配置路由,匹配模式和服务版本等。 这是我使用的技术堆栈开发的又一步,您只有从经验中获得的经验就是凭直觉来确定到底什么不起作用。
单车
没有故事,这篇文章是不完整的。 , . SQLAlchemy. BNEF , . . SQLAlchemy, , Solr. - .
«MYSQL server has gone away.» . , , . , . , . , ?
, ? , , . , ,
__exit__()
session.close()
.
, , . . . . .
Session.close()
MySQL- SQLAlchemy , NullPool. . , , . : StackOverflow (, !) , , SQL- . , . , , (), .
«» , 1 8. , , — .
, .
, . , , . , .
, , , . , . , . «
?! , ? ».
, : , . , , . , , . , . — ? , , . . , -, , , , , .. .
. , , ? (, AWS CloudWatch Grafana). .
. , , 50 %, — . ? . , — (, ?).
. , , , , ? ? , ?
, . , . — - .
结论
. , , , . , - !
. , !
, . , — How to Build Good Software .
. : ! , .
- ?
- ? , ? , ?
- . , ? ?
- (utils) (, , , ) , « »?
- ?
- , , - ?
- — API , ?
- ? , .
- , , . , , .
- PR: « , , 52 , , , , , ». ?
- . ?
- ?
- ?
- . , ? - ? , ?
- ,
x()
, y()
z(),
x()
, y()
z()
. , WYSIATI .
- .
- . , ?
- , - , , . , .
- , , Docker- AWS.
- .