整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

数据驱动营销:14条运用数据的经验法则

数据驱动营销:14条运用数据的经验法则

99IT数据中心微信账户:i199IT

编译:房ny_nicole

大数据发展至今已被推上了时代的风口浪尖,社会对其的评价褒贬不一。虽然它给我们带来了很多好处,但也有人会发出这样的声音:“ 大数据的人快离开我的地盘! ”

即便如此 ,Scott Brinker仍相信,若大数据被正确运用,它将会在现代市场营销领域产生无可估量的积极影响。在数字化时代,单纯依靠直觉和经验而做出的营销决策往往是不可信的。因此,企业若希望占据市场有利地位,就要在客观数据分析和人类直觉判断中找到均衡点。

Gord Hotchkiss,一名市场营销专栏作家,他近期写了一篇文章 《在中间地带的市场营销》( Marketing in the Middle ) ,表明他也支持该论点——在中间地带找均衡点。

“市场营销没有所谓的绝对。我们需要那些有大构想、执行力强、敢于坚持的人去锲而不舍地去实施我们的构想,将我们的营销手段发挥到极致。但我们也需要那些善于变通的、有许多奇思妙想的人去引导我们穿过那些灰暗的中间地带。实际上,我在市场营销领域中钻研的时间越长,我对中间地带的理解越明了——我们所有动作实际上都是在中间地带发生的,无论是质量和数量的抉择,策略和大数据的选择,品牌创意和直接营销的取舍,甚至是科学和艺术之间的权衡。”

那么,我们怎么做才能将数据有效地利用起来呢?在此,Scott将为大家提供一些14条使用数据的经验法则,让大家开始学会用数据驱动营销,同时也避免沦为数据主义或使用不实数据进行营销。

1. 用户驱动优于数据驱动

数据驱动营销固然是好事。但是我们要牢记在心,营销的目的是获取并保有用户,因此“用户驱动”更有利于达到营销目的。话虽如此,“数据驱动”和“用户驱动”并非相互排斥。相反,二者为过程与结果的关系,前者为过程而后者为结果。该条法则意在提醒我们,在运用数据的时候,记得思考:“该举措是否有利于为公司赢得用户?”

2. 引用准确和相关的数据

当我们在讨论一个绝对真理的时候,引用数据是说服他人的最佳手段。然而,在大数据时代,各种数据应有尽有,任何一方都可以搜集相应数据,并“合理”地运用该数据去说服对方。在这种情况下,数据的相关性和准确性显得尤为重要。因此,人们往往以为大数据可以让市场营销人员更好地去了解用户,然而真相是,其实他们也许对用户一无所知。因此,我们不仅要引用数据,还要引用最为精确及相关的数据。

3. 数据只能体现过去发生的事实

毫无争议地,数据能够体现过去发生的事实,然而其对未来发展是否意义则有待考究。诚然,我们可以从过去的数据中推断出未来趋势(有时候甚至非常精确)。然而,现今社会是瞬息万变的,过去是过去,它不一定能够告诉我们未来的日子将会发生什么变化,有时候我们的预测会出现与预期完全相反的结果,正如历史上数次发生的 黑天鹅事件 ,往往具有意外性,且无法被人为预测和解释。

4. 数据总是不完整的

在某个特定集合内的数据是完整的,如过去三年每个季度的销售额。然而并非所有事物都可以归纳到一个特定的集合内的,因此,每当我们在做决策的时候,会发现仅引用已有数据是远远不够的,我们还需要引用更多的数据,因为它们都和我们要做的决策息息相关。于是你会发现,数据的引用是个巨大的黑洞,因为你永远也无法将所有的数据收入囊中。因此,尽管我们在大数据的支持下为企业做出了一个决策,但这个决策往往如同印象派的画作一般,只描绘出了个大概,和真实情况仍相距甚远。

5. 数据是客观的,但千万个读者就有千万种解释

没错,数据是客观的,如一张净推荐值(Net Promoter Score)表格中,显示的净推荐值均为7。然而除此之外,其他内容都是主观的。一方面,其主观性体现在过程中——收集信息的内容不同,收集信息的时间地点不同,甚至采访对象的选择也有因人而异。另一方面,主观性也体现在结果中——相同的数据,每个人的解读方式也不一样。详情案例可参阅 《Hidden biases in big data》 。

6. 数据可以让故事变得更具有说服力

市场营销人员往往是一个讲故事的人。我们在讲故事的时候引用相关数据,将会使得我们的故事更为动听及具有说服力。然而,正因为数据的解读具有主观性,我们可以更加自如的将符合我们期望值、具有说服力的故事说给用户听。尽管如此如何运用数据由我们说了算,但在讲述故事的时候,我们仍要合理地和负责任地运用相关数据。

7. 好的数据支持我们做明智的选择

决策为企业和个人做选择提供一个框架,而数据则有利于为做选择提供相应信息。好的数据将会引导人们做出明智的选择。反之,不好的数据将会成为我们成功道路上的绊脚石。

8. 用实验来证实数据之间的因果关系

大数据时代一个非常重要的词语是“相关性”,然而我们要清楚,相关性并非因果关系。作为市场营销人员,在了解到企业行为和消费者行为之间相关关系后,我们接下来应当考察该关系是否为因果关系——做实验。保持其他变量不变,检验相关变量去证实或证伪我们的猜想。谷歌每年都会进行超过一万次的实验,其实验产生了巨大的数据量为谷歌服务,也因此说明了, 大量的实证实验优于纯粹以数量取胜的数据 。

9. 平衡数据与用户体验之间的关系

Gord曾用过一个非常生动形象的比喻: “营销如同开车,仪表盘则如同营销过程中所产生的各种数据(如营业额等),挡风玻璃则如同用户体验。” 显然在行车时,仪表盘上的数字和挡风玻璃外的世界,我们二者都要兼顾。同理,在营销过程中数据和用户体验均很重要。

10. 数据具有时效性

随时间推移,当下数据的保留价值越来越低。例如,在我想买车的时候,车商视我为目标客户,定期向我推送相关信息。然而,在我买车后的六个月,他们就开始对我不理不睬。这个例子在一定程度上说明,数据是具有时效性的,因而掌握有效和准确的数据对于运用数据的市场营销人员来说至关重要。

11. 数据运用的“是什么”和“为什么”

在运用数据做营销决策的时候,我们需要考虑到这些数据“是什么”(confirmation)和“为什么”会得出这些数据(exploration)。当我们在考虑“是什么”的时候,会了解到:事物是否发生,或发展到什么程度了;而当我们在考虑“为什么”的时候,我们想要去寻求新的发展模式,新的事业和新的伟大构想。另,同样的数据,我们不仅可以用它去探讨“是什么”,同样可以探讨“为什么”,这取决于市场营销人员所要研究的命题。

12. 拥有两块手表并不能准确的判断时间,反而会制造混乱

手表定律 是每个市场营销人员都需要掌握的定律之一。这个世界被各种矛盾的数据充斥着,用不一样的数据或研究方法去讨论同一个问题可能会得出截然不同的答案。面对这种情况我们可以做的有两件事,一件是既然数据已经不一样,那么我们就去了解是什么因素让数据呈现出两种不同的结果,通过此举我们往往会有意想不到的新发现;另外,不要为一分一毫的数据偏差而过于纠结,我们需要的不是完美的数据,而是利于我们做出明智决策的、准确地恰如其分的数据。

13. 模型并非现实

模型并非现实,它充其量是现实的反映,有时候它甚至会歪曲了现实。一名哲学家兼科学家Alfred Korzybski曾经说过:“地图并非实际地形。”伟大的科学家George E.P. Box也曾说过:“所有模型都是错误的,只有一些是有用的。”。因此,在实际运用当中,我们要正确看待数据,不能“唯数据主义”,除了数据,我们仍应对其它信息保持高度的警惕,特别是那些体现现实生活的信息。正如同Swiss Army Aphorism所说:“如果地图和实际地形不符,选择地形。(毕竟地图没有办法完全显示出那悬崖峭壁。)”

14. 数据可视化是把双刃剑

数据可视化(包括但不限于图形和表格)是一把双刃剑。就目前来说,数据可视化在数据运用中发挥着积极的作用——使人们更加直观地读懂数据,方便做决策。然而,无论是有意或无心,它可以为我们呈现有效的信息,同样也可以为我们呈现无效的信息,其弊端也许日后会日益显现。若想要了解更多有关数据可视化的内容并掌握这门技巧,可参阅 Stephen Few , Kaiser Fung , Edward Tufte , Nathan Yau , and Fernanda Viégas and Martin Wattenberg

总的来说,虽然大数据发展已久,但 数据运用也许在当今市场营销领域中仍欠缺开发利用 。因此,我们应正视数据的作用,并开始有效的利用它。

SocialBeta

http://www.socialbeta.com/articles/14-data-driven-marketing-rules.html?utm_source=tuicool

大数据导航 HAO.199IT.COM

点击文末“阅读原文”获取“最新数据资讯

『 WeMedia 』自媒体联盟覆盖千万人群,『199IT-互联网数据中心』为其成员。( 账户:i199IT)

者 | Adrien Joly

译者 | 张卫滨

策划 | 丁晓昀

有时候,JavaScript(甚至带有类型检查的 TypeScript)会因为其不可预测的特性和缺乏约定而遭到批评。对于那些知道 JavaScript 是为 web 浏览器设计的脚本语言的人来说,这就不足为奇了。


但是,现在它已经成为开发全栈 web 的首选语言,也是跨平台移动应用的热门方案。那么,当开发人员的 JavaScript/TypeScript 代码库开始老化,由此带来的复杂性痛苦地增长时,他们该采取什么行动才能最大限度地减少资源浪费并保持工作满意度呢?


本文将基于我 10 多年来编写 JavaScript 代码的经验和 5 年多拯救 JS/TS 项目的经历,向读者介绍如下内容:


  • 如何评估 JS/TS 代码库的质量和风险。
  • 对于需要修复的部分,该如何确定其优先级。
  • 有哪些非破坏性的方法可以让 JS/TS 代码库逐渐变得更健康。


清理工作台

在开发下一个特性时,每个警告、类型错误或非正常的测试都会让开发人员浪费时间、精力和专注度。


代码警告尤其令人讨厌,因为开发人员会习惯性地忽略它们,“只要一切按预期运行就好”。因此,它们会迅速累积,当我们遇到缺陷、事故或系统的意外行为时,就很难将其作为有用的线索。


类型错误就是一个很好的样例。当我们的用户遵循“快乐路径(happy path)”时,这些错误似乎无关紧要,因为软件似乎能够按照预期运行。所以,我们可能会使用@ts-ignoreany或类型断言来暂时忽略它们。但是,这样做的话,就意味着如果有一天用户选择不同的路径,就会面临运行时错误。


这样的话,开发人员就需要调查、重现和修复一个新的缺陷,而这个缺陷恰恰是他们几个月前允许走捷径所造成的。如果你的代码被各种警告和/或暂时忽略这些警告削弱了质量,那么找到这个捷径将耗费大量的时间。



当生产环境的数据库因“内存不足”错误而崩溃时,该警告可能会帮助开发人员找到崩溃的原因


警告和类型错误是查找缺陷和事故的线索。我们累积(或忽略)的警告和错误越多,开发人员就会花费越多的时间去调查。如果代码是他们很久以前编写的,那情况就会更糟糕了。


我们能做些什么呢?


  1. 确保开发人员在开发过程中能够尽快看到警告和类型错误。这不应该花费额外的成本。如果可能的话,集成到他们的 IDE 中。
  2. 不要让警告和类型错误累积。尽快修复它们。
  3. 提高信噪比。如果团队一致认为某条引发警告和类型错误的规则没有用处的话,就干脆禁用它。
  4. 如果你确信需要在代码的特定部分忽略掉某条规则的话(也就是,使用 code>@ts-ignore、any或类型断言),请添加注释以记录忽略该规则的原因。
  5. 不要在运行时添加 try-catch 代码块来捕获编程错误(比如,业务逻辑中意料之外的未定义值)。而是要使用这种代码块来处理外部系统的预期错误(如输入/输出异常、校验、环境问题等)。在开发过程中,应使用静态代码分析和单元测试来捕获编程错误。
  6. 不要让带有警告和类型错误的代码进入生产环境。使用持续集成流水线来强制要求这一规则。



类型检查器认为缺少一个预期的属性。忽略这个错误将意味着要承担持久化不一致数据的风险,在几个月之后,你可能需要花费几天的时间来调查和解决这个问题


我们可以使用哪些工具来实现这一目标呢?


有许多静态代码分析工具可供使用,最常用的包括:


  • ESLint,能够用来探测代码中的语法错误和反模式;
  • TypeScript(启用严格的规则),借助.ts文件或JSDoc注解以探测类型错误;
  • 除此之外,SonarCloud、SourceGraph、Codacy或类似的在线工具服务也有助于跟踪共享代码库中多个代码质量度量指标的变化情况。


警告也可能来自其他工具:依赖安装器(如npmyarn)、打包器(如webpack)、代码处理器(babelscss)和执行环境(CI 运行器)。不要忽视它们!


如果遵循这些建议会让你的代码变得非常冗长和/或复杂(比如防御式代码),你可以需要对其进行重新设计。


 "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix",
    "lint:errors": "eslint . --quiet",
    "lint:typescript": "tsc --noEmit --skipLibCheck",
    "lint:jsdoc-typing": "tsc --noEmit --allowJs `find ./ -name '*.js' -name '*.d.ts'`"
  },

复制代码


借助静态代码分析器和 npm 脚本,能够让开发人员轻松快速地探测有问题的代码


后续该怎么办?


安装和配置静态代码分析工具是一个良好的开端,但这还不够。


要想取得持续的成功,要确保开发团队做到如下几点:


  • 充分认识到部署不含编程错误的代码的重要性,并相信静态代码分析可以帮助他们实现这一点;
  • 充分理解 TypeScript 的运行原理(参见TypeScript: Handbook)
  • 定期修复警告和类型错误,起码要比引入它们的频率更高;
  • 保持这些措施,永不间断。


如下几种策略可能会提供帮助:


  • 奖励提高代码质量的代码贡献行为,从而激励开发人员。其中,有种方法是使用可插入持续集成流水线的工具来跟踪开发人员推送的每个变更的代码质量变化,例如可以使用 SonarCloud 和/或 Codacy。
  • 让一名开发人员负责确保代码质量永不下降。
  • 让另一名开发人员负责定期更新依赖,从而能够让团队能够从它们的逻辑和安全修复中受益。


为何要把每个角色都交给一个专门的人?


当某项职责没有人负责时,集体责任往往会被其他“优先事项”所取代(比如,本周多交付一个特性,但是代价是忽略一个警告)。


定期轮换角色,确保每个人都能参与其中并保持积极性。


使用(恰当类型的)测试覆盖关键的业务逻辑


现在,我们有了一支致力于保持代码库整洁的团队,我们相信用户很少会遇到编程错误。


但是,业务逻辑中的错误该怎么办呢?


例如,如果一个新添加的功能破坏了另一个功能该怎么办?如果开发人员从一开始就误解了该功能的预期行为,又该怎么办?如果这样的错误最终导致了严重的收入损失又该如何处理?


与编程错误类似,业务逻辑问题可能会在生产环境由用户发现,但我们更希望尽早发现它们。因此,定期测试软件非常重要,这个过程可以使用自动化和/或手动测试。


从业务角度看,测试有两个作用:


  • 符合功能性需求:每个特性的实现都能满足开发时的需求。
  • 检测回归:在对代码进行任何修改后,所有现有的特性都能按照预期运行。


确保功能性测试(也称为“验收测试”)涵盖大多数关键业务特性,单元测试或集成测试涵盖大多数关键技术组件。此外,确保持续集成在任何测试失败时都能向开发人员提供可执行的反馈。


对于有些开发人员来说,将测试工作委托给其他人(如产品负责人或 QA 团队)是很有诱惑力的做法。在每个新特性完成后,进行一次这样的委托测试,以确保特性实现符合功能性需求,并进行协作迭代,这样做可能是合理的。


但是,委托他人进行回归检测并不是一个好主意,原因包括:


  • 它增加了合并代码和部署代码之间的延迟。
  • 它增加了发现回归问题和修正它们之间的延迟。
  • 随着功能性范围的不断扩大,检测回归所需的时间也会随之增长。如果负责这些测试的人没有将其自动化,他们最终可能会跳过越来越多的测试。因此,一段时间之后,出现回归测试未发现问题的风险就会越来越高。


回归测试是一项痛苦且可能代价高昂的负担,尤其是需要不同角色(如产品负责人和开发人员)必须协作的情况下。从长远来看,回归测试自动化意味着可以节省大量的时间,而且开发人员具有编写自动化测试的技能,所以,开发人员首先要承担起检测回归的责任,而不必让其他角色参与进来,这符合他们的利益。


如果要涵盖的功能范围很大该怎么办?


从最关键的业务特性开始。要找出这些特性,你可以问自己:“就收益和/或减少成本而言,在生产环境中可能发生的最糟糕的事情是什么?”


例如,电子商务网站的回答可能是如下的特性:


  • “信用卡购物”特性每分钟可以带来大约 1000 美元的收入。
  • 如果销售人员必须要求首席技术官手动将产品添加到数据库中,则“将产品添加到目录中”特性每小时的成本约为 500 美元。
  • 如果客户支持团队需要手动处理订单,那么“打印条形码以退回订单”将使我们每天损失 500 美元。


基于这些业务关键的用例,从它们开始编写端到端的自动化测试肯定就是非常有意义的。


何时运行测试?


在每次代码更新或添加到代码库之时,在将其部署到生产环境之前。


借助git hook,在每次提交时运行测试可能就足够了,因为它能可靠地运行,而且其持续时间不会导致开发人员编写更少的测试。


不管是否使用git hook,都要确保每次推送可用于生产环境的代码时,测试能在某处运行(例如,最好是在持续集成环境中)。



在持续集成环境中,每次提交都会运行代码检查和自动化测试。


我们应该编写什么样的测试?


需要优化的变量包括:


  • 测试所覆盖的功能性和技术性范围的大小。
  • 从测试中获得反馈的时间。
  • 修复失败测试所报告的问题所需的时间。
  • 因为误报而损失的时间(即由于随机原因导致失败的测试)。


如果你的团队在编写自动化测试和/或可测试代码方面经验不足,那么可以从一些端到端测试开始。然后,逐步增加对范围更小的代码单元的测试。这样做可以激励开发人员编写易于测试的代码。例如,通过隔离责任、减少耦合和/或将业务逻辑写成纯函数。遵循依赖注入架构是实现这一目标的好方法。(参见六边形架构或简洁架构)


我们是否应该 Mock 第三方 API?


自动化测试(如本文所述)的目的是探测团队的功能性范围内的回归,而不是第三方的功能。基于这一点,在测试中 Mock 第三方是合理的。


也就是说:


  • Mock 应始终与当前 API 的行为相匹配。这意味着开发人员需要持续关注 API 的变化,并相应的更新它们的 Mock。
  • 当实际 API 的行为与预期不符时,你可能依然希望得到警告。


探测自己的代码中的问题和第三方 API 中的问题并不遵循相同的生命周期:


  • 每次代码进行变更时,所涉及的范围都应该进行测试。
  • 仅在第三方的代码发生变更的时候,才应该对其进行测试。(也就是说,每次提交代码变更都测试第三方依赖是没有什么意义的)。


你需要持续监控第三方提供商是否能够正常运行并达到预期效果。但是,第三方错误不一定能够在发生之时就探测到,因此最好是定期监控,而不是在开发人员每次推送代码变更的时候进行监控。


所以,需要搭建两个专门的流水线:


  • 你自己的 CI 流水线会在你的代码发生变更的时候测试自己的范围。
  • 另外一个 CI 流水线定期检查第三方所涉及的范围是否按照预期运行。


为了编写长期最有用、最健壮的测试,我建议遵循F.I.R.S.T.原则。确保开发人员不会滥用mock。


细致保护代码库中新的/现代化的部分


假设你的代码库已经或者将要开发数年的时间,那么随着时间的推移,它很可能会在代码风格和质量方面失去内聚力。更糟糕的是,由于技术债务、缺乏测试或意外复杂性的积累,某些组成部分的维护可能会变得很复杂。


在这种情况下,要像上文所建议的那样,在整个代码库中对代码实现一致的内聚预期可能会变得很复杂。不过,这也没有关系。


你不希望看到的是期望值降低到一个最低的平均水准。这样的话,你可以把代码划分为不同的范围,并为每个范围设置不同的期望水平。


例如,考虑一个即将为电子商务网站实现新特性的团队。他们希望这个新特性能够比代码库中的其他特性更健壮、更易于维护。为了实现这一点,他们在配置静态代码分析工具(如 ESLint 和 TypeScript)时采用比代码库的其他部分更严格的规则,并针对专门为该特性而创建的目录使用覆盖的方式启用更多的规则。通过这种方式,团队可以提高新代码的质量,而不必急于对代码库中“遗留”的部分进行现代化处理。


"rules": {
    "prettier/prettier": "error",
    "deprecation/deprecation": "warn"
  },
  "overrides": [
    {
      // Tolerate warnings on non critical issues from legacy JavaScript files
      "files": ["*.js"],
      "rules": {
        "prefer-const": "warn",
        "no-inner-declarations": ["warn", "functions"],
        "@typescript-eslint/ban-ts-comment": "warn",
        "@typescript-eslint/no-var-requires": "off"
      }
    },
    {
      // Enforce stricter rules on domain / business logic
      "files": ["app/domain/**/*.js", "app/domain/**/*.ts"],
      "extends": ["async", "async/node", "async/typescript"],
      "rules": {
        "prefer-const": "error",
        "no-async-promise-executor": "error",
        "no-await-in-loop": "error",
        "no-promise-executor-return": "error",
        "max-nested-callbacks": "error",
        "no-return-await": "error",
        "prefer-promise-reject-errors": "error",
        "node/handle-callback-err": "error",
        "node/no-callback-literal": "error",
        "node/no-sync": "error",
        "@typescript-eslint/await-thenable": "error",
        "@typescript-eslint/no-floating-promises": "error",
        "@typescript-eslint/no-misused-promises": "error",
        "@typescript-eslint/promise-function-async": "error"
      }
    }
  ]

复制代码


通过配置覆盖,我们可以为不同的部分设置不同的 ESLint 规则


与之类似,如果要对整个代码库进行现代化改造,也要循序渐进。你可以创建一个具有更严格规则的专用目录,并逐渐将遗留代码迁移至该目录,同时修复代码的警告和类型错误。


从何处开始?


有种方式是逐步将功能范围中陈旧的部分迁移到更好的设计中。例如,选择一个难以编写自动化测试的特性,并将它的实现迁移到六边形架构中,将业务/领域逻辑根据输入命令(即“API”)和副作用(即“SPI”)分离开来。通过编写自动化测试来指导迁移,并将新的实现放在具有更严格静态代码分析规则的专用目录中。


import { makeFeatures }=from './domain/features';
import { userCollection } from './infrastructure/mongodb/UserCollection';
import { ImageStorage } from './infrastructure/ImageStorage.js';








/** @type {import('./domain/api/Features').Features} Features*/
const features=makeFeatures({
  userRepository: userCollection,
  imageRepository: new ImageStorage(),
});








routes.post('/avatar', (request, response)=> {
  features
    .setAvatar(request.session.userId, request.files[0])
    .then(
      ()=> response.json({ ok: true },
      (error)=> response.json({ ok: false })
    );
});

复制代码

setAvatar特性经过了重新设计,由于采用了依赖反转,使其易于单独进行测试。下面是我们迁移另一项特性的过程,即播放列表删除


如果你决定遵循这一路径,如下是一些建议:


  • 如果你的团队没有重新设计遗留特性的经验,那么就从简单的小特性开始。否则的话,请选择一个未来几周或几个月内要实现的特性最依赖的那个特性。
  • 在编码之前,明确范围、业务事件和路径。例如,与你想重新设计的领域(或限界上下文)所涉及的专家一起组织一次事件风暴。
  • 可视化要迁移范围的当前架构,例如使用像ARKit、Dependency-Cruiser或类似的依赖分析工具,并写明不想在目标架构中重复出现的问题,以免重蹈覆辙。
  • 如果有疑问的话,请使用软件设计工具(如时序图、状态机图、ADR)协作完成恰当的设计。


在迁移完每个限界上下文之后,你将会得到一个代码库,在代码库中 100%的代码都应按照更严格的规则进行检查。


每日部署,但同样的错误不要犯两次


尽管使用了静态分析工具来检测缺陷,使用了自动化测试来探测回归,但用户还是会在生产环境中发现问题。这是无法避免的。但是,有一种方法可以降低出现此类问题的概率,并缩短团队修复问题的时间:


  • 每日部署(前提是你确信失败的风险很低)。
  • 同样的错误不要犯两次。


为何要每日部署?


简约版答案:因为DORA研究项目发现,大多数执行团队每天都在进行部署,或者每天部署多次。


详尽版答案:

  • 因为这能够让开发人员更快地找到在生产环境中出现新缺陷的根本原因。也就是说,部署越频繁,最新部署和上次部署之间的提交次数就越少。
  • 基于相同的原因,如果最新版本不能按照预期运行,回滚到上一个版本的成本会更低(就回滚代码提交的次数而言)。
  • 因为这能鼓励团队将工作分成更小、更安全的增量。DORA 认为,这也是表现最好的团队所遵循的做法。


如何确保相同的错误不犯两次?


在生产环境中出现意料之外的行为是可以的。在有些情况下,这甚至是一件好事。


当意料之外的行为给企业和/或开发团队带来巨大损失时(例如,网站中断,导致几个小时无法使用),开发人员应该采取措施防止类似的事件再次发生。


如何探测生产环境中的问题?


有多种方式可以探测生产环境中的问题:


  • 理想情况:开发人员发现问题并立即修复。
  • 常规情况:员工发现问题并向开发团队报告。
  • 更糟糕的情况:用户向开发团队报告问题。
  • 最糟糕的情况:用户发现了问题,但并没有报告。


无论是哪种情况,开发人员都需要以下信息:问题是什么、问题的具体表现(如错误信息)、如何重现问题(如环境+过程),以及用户的初衷和期望是什么。


但是,如何在最糟糕的情况下获得这些数据呢?这就是错误监控工具(如Sentry)的用武之地了。通过将它们注入到生产环境中运行的产品中,它们就能像探针一样检测运行时错误,并将它们汇总到已知错误的列表中,直到每个错误都被开发人员修复为止。此外,它们还会获取有关错误上下文的数据(如用户代理、所使用软件的版本、操作系统、确切的时间戳等),以帮助开发人员重现错误。


但令人遗憾的是,与静态代码分析器类似,这些工具并不能解决问题。因此,与警告和类型错误一样,要确保尽快处理每个错误。团队让错误累积得越多,使用这些工具的动力和效率就会越低。


此外,在使用这类监控工具时,请确保个人和/或机密数据不会从系统中泄露出去。


从战术上讲,有许多方法可供选择。你可以让一名开发人员负责修复生产环境的错误,并将其作为最优先的事项。这个角色可以定期轮换(比如每天),这样可以激励每个人都编写更健壮的代码。或者,也可以在每天的会议上将新错误单独分派给志愿开发人员。


如何降低复发风险?


不必慌张!当生产环境中发生事故时,都要遵守如下程序:


  1. 保留事故发生前、发生时和发生后的痕迹,以帮助你进行事后分析(注意:在事故发生前做好充分的监控和日志收集工作)。
  2. 在内部和外部就事故进行沟通。
  3. 稳定生产环境,例如,回滚到之前能正常运行的版本。
  4. 编写并部署修正版本,以修复问题。
  5. 查找并解决导致问题的根本原因,并采取预防措施。


避免重蹈覆辙的关键在于上述程序的最后一步。


这也是经常被忽视的过程。大多数情况下,是因为没人觉得自己有责任这样做。很多时候,是因为产品负责人(或产品团队)向开发人员施压,要求他们优先完成开发计划中的特性,而不是保护现有代码和/或调整开发流程。有时,开发人员自己也会决定开发更多的特性,而不是避免再次犯错。



调查事故根本原因时的注意事项


如何查找事故的根本原因?


在这个方面,“5 个为什么(5 WHY)”技巧是很有用的。例如:


  • 生产系统为什么会崩溃?——因为一个未登录的用户访问了页面 B。
  • 用户为什么能够访问页面 B?——因为主页上有一个链接。
  • 用户在访问页面 B 的时候为什么没有看到登录页面?——因为在页面渲染时,后端还不知道登录状态。
  • 为什么页面渲染时还不知道登录状态?——因为我们的会话管理后台很慢,等待这个状态会大大降低我们的网络性能指标。
  • 为什么会话管理后端很慢?——因为它使用的是未经优化的遗留数据库。


在本例中,根本原因是整个网站都依赖于遗留的会话管理后端,这使得导航难以预测,有时还会导致生产环境崩溃。因此,除非团队修复传统的会话管理后端,否则类似的崩溃很可能很快就会在生产环境中再次发生。团队现在应该修复遗留的会话管理后端吗?也许不用。但是他们应该努力制定一个能够实现该目标的补救计划。


在实践中,如何实现低故障率的日常部署呢?


让一位开发人员负责确保尽快发现生产中的意外行为(如运行时错误、缺陷、事故……),尽快修复,并采取措施防止今后再次发生各类问题。


通过这种方式,开发人员能够感受到有能力在良好的条件下开展工作。例如,在生产过程中设置恰当的监控和日志,确保撰写有用的事后报告,并采取预防措施。


当信心达到良好水平时,逐步增加部署频率。


以正确的激励机制调整产品开发团队


此时,开发人员就具备了编写高质量软件,并尽快发现缺陷的能力。这些缺陷最好是在设计或实现时发现,而不是在生产环境中。他们能够快速发现并修正生产环境的错误,不会重复犯同样的错误。他们对自己的代码和开发流程充满信心,因此每天都能在生产中实现改善。而且,他们在对软件功能化范围进行预期改善的同时,也会逐步改善代码库中最古老部分的设计和质量,使其保持健康、稳健并易于长期维护。


但是,令人遗憾的是,这种平衡很快就可能被瓦解。举例来说:


  • 如果开发人员失去了长期保持高设计标准和/或代码质量的动力。
  • 如果部分开发人员不遵循团队的质量准则,造成系统性返工、挫折和延误。
  • 如果开发人员误解了功能性需求,而急于修复无法达到预期效果的特性,从而牺牲了长期的技术责任。
  • 如果有人(如经理、产品负责人或其他人)向开发人员施压,要求他们每周发布更多的特性,或在紧急的期限内完成任务。
  • 如果激励和/或奖励开发人员的绩效指标与其代码库的长期质量和健壮性不一致。例如,根据每周交付的特性数量确定晋升奖金。


防止或解决这类情况可能会非常困难,因为这需要良好的领导力和/或软技能。


一个常见的错误是培养某种思维定式,即开发人员应该主要致力于实现优先的、计划好的和设计好的特性。


这样做是有问题的,因为:


  • 它要求开发人员处于这样一种状态,即对软件做的每一项变更都要有精确和明确的规范。这可能会导致开发人员无法与负责制定这些规范的人员进行健康的双向合作。对于那些喜欢整天独自工作的开发人员来说更是如此。
  • 它让开发人员处于这样一种境地,即难以衡量那些与功能性路线图没有直接贡献的开发活动,如更新依赖、提高代码质量、培训更好的设计和编码技术。
  • 这很容易让人倾向于根据指标(如用户故事的开发速度)来跟踪开发人员的绩效(或“生产力”),而忽略了对可持续开发实践的投资,即代码质量、阻碍回归、错误管理等。


下面是一些关于如何避免上述陷阱的建议:


  • 在详细阐述业务问题的解决方案时,至少让一名开发人员参与设计过程。这将提高开发人员的责任心,使他们能够为一个充分理解的问题实现一个好的解决方案。有时,由于开发人员了解当前的建模和实现方式,他们会提出替代解决方案,从而在满足需求的同时节省大量的开发时间。
  • 确保产品和技术代表能够公开、友好地协商功能性和技术性项目的优先级和规划。例如,如果开发人员需要重新设计代码库的某个部分,那么他们就应该说服其他人相信这一点的重要性,解释这将为下一个特性的开发带来哪些具体的改善,以及延迟该项目的风险和成本是什么。同样的建议也适用于产品经理如何对即将开发的功能改善进行优先排序和规划:通过解释来说服开发团队并让他们参与进来。这样做可以增强参与设计和实现特性的所有员工的信任、协作和参与度。
  • 在管理方面,确保开发人员不会得到这样的激励,即“每周尽可能多地发布特性”。找到使每个开发人员的职业目标与团队的短期和长期期望相匹配的发展轨道。这样做的目的是防止出现开发人员理直气壮地只从事短期改善相关工作的情况。
  • 最后,确保为开发人员提供资源和指导,以不断提高他们的软硬技能。为他们提供培训和/或指导资源。鼓励他们通过结对和/或群体编程的方式共同完成任务。鼓励他们与其他/非开发人员角色进行良好的协作,包括领域专家、产品负责人、产品设计师、客户支持团队、终端用户等。


结论


JavaScript 语言及其不断变化的软件包和实践组成的生态系统会使代码库迅速变得难以维护。正如我们在本文所讨论的那样,无需从头重写所有的内容,也无需暂停新特性的开发,就可以避免由此造成的开发速度和/或代码质量的下降。


关于如何在 TypeScript 和 JavaScript 项目中应用这些推荐做法的更多实用建议,我建议你参考Yoni Goldberg的最佳实践列表。它们是为 Node.js(后端)项目编写的,但其中很多也适用于前端代码库。

原文链接:前端老手10年心得,JavaScript/TypeScript项目保养实用指南_架构/框架_InfoQ精选文章


闻 法 讯

(第16期)



法讯回归,如闻为您带来最新法律动态~


一、法律动态

1. 2023年9月20日,国家金融监督管理总局发布《保险销售行为管理办法》(“《办法》”),将于2024年3月1日。《办法》共6章50条,重点对销售人员资质、跨区域展业、产品分级制度、产品宣传、离职后责任等方面进行了细化性规范。《办法》旨在完善行为监管制度体系、构建保险销售行为监管框架,全文刊载于国家金融监督管理总局网站:http://www.cbirc.gov.cn/cn/view/pages/rulesDetail.html?docId=1129945&itemId=4214&generaltype=1

2.2023年9月25日,最高人民法院发布《最高人民法院关于优化法治环境促进民营经济发展壮大的指导意见》(“《指导意见》”)。《指导意见》从六个方面对审判执行工作提出了明确要求,重点对保护民营企业产权和企业家合法权益、严厉打击恶意“维权”侵犯民营企业合法权益的行为、对中小微民营企业的融资、股东不当行为等给予司法保障等,提出了相关意见。《指导意见》全文刊载于最高人民法院网站:https://www.court.gov.cn/zixun/xiangqing/413942.html

3. 2023年10月16日,国务院发布了《未成年人网络保护条例》(“《条例》”),将于2024年1月1日实施。《条例》从提升未成年人网络素养、加强网络信息内容规范、拒绝网络欺凌、预防和干预未成年人沉迷网络、保护未成年人信息以及对未成年人网络消费数额进行限制等六个方面,提出了规范要求。《条例》是我国出台的第一步专门性的未成年人网络保护综合立法,旨在进一步完善互联网领域治理体系,为健全青少年健康成长提供重要的法治保障。《条例》全文刊载于中国政府网:https://www.gov.cn/zhengce/zhengceku/202310/content_6911289.htm

4. 2023年11月10日,香港特别行政区政府确认《关于内地与香港特别行政区法院相互认可和执行民商事案件判决的安排》(“《安排》”)将于2024年1月29日生效并实施。《安排》在管辖判定、适用范围、具体认可和执行的判断标准和程序等方面的规定,较现行有效的《最高人民法院关于内地与香港特别行政区法院相互认可和执行当事人协议管辖的民商事案件判决的安排》更加完善,有效扩大互相认可和执行判决的民商事争议范围、遏制恶意规避法院执行判决的行为。《安排》全文刊载于最高人民法院网站:https://www.court.gov.cn/fabu-xiangqing-139501.html

5. 2023年11月15日,最高人民法院发布《最高人民法院关于综合治理类司法建议工作若干问题的规定》(“《规定》”)。《规定》旨在落实“抓前端、治未病”的重要指示精神,对提出司法建议的名义、事前沟通、协同落实、文书规范等进行规定,以规范司法建议工作,引导人民法院结合审判执行工作依法能动履职。《规定》全文刊载于最高人民法院网站:http://courtapp.chinacourt.org/zixun/xiangqing/417752.html

6. 2023年11月21日,司法部发布《行政复议普通程序听取意见办法(征求意见稿)》和《行政复议普通程序听证办法(征求意见稿)》并向社会公开征求意见。相关文件系为规范行政复议普通程序听取意见和听证工作,进一步提高行政复议工作质效,更好的保护公民、法人、其他组织的合法权益。意见反馈截止日期为2023年11月30 日,意见征求公告及草案刊载于司法部官网:http://www.moj.gov.cn/pub/sfbgwapp/zwgk/tzggApp/202311/t20231121_490029.html








作者 陈晓燕

责编 高萍



往期推荐

01

知网被罚8760万,“知识垄断”不可为

02

案外人提出异议后,还能另行提起确权之诉吗?

03

双语|一文读懂新妇保法,企业该做些什么?(下)


特别声明

  • 本文为如闻原创,如需转载,请联系本公众号后台。
  • 本公众号的信息仅作一般性参考,不应视为如闻律师事务所或其律师针对特定事务出具的正式法律意见或建议。如您有意就相关议题进一步交流或探讨,欢迎与本所联系。


扫码关注我们

上海如闻律师事务所


《金刚经》卷首语:“如是我闻”,如闻律师事务所藉此得名。“盛世法,如闻人”是本所之铭。法律的精神在于维护社会的公平与正义。但,“徒法不足以自行”。法律的正确实施,公平价值得以实现,离不开一位好律师来为您的权益保驾护航。愿我们能和您一起,在这个新时代里,追逐梦想,实现梦想。所有的如闻人,以钻研精神,饱含着无限热情,践行着法律者的初心,为所有如闻的朋友们,做好专业的服务。

我们的精神就是:如你所需,如闻永远和你在一起。