【阅读笔记】The Effective Engineer

Part 1: Adopt the Right Mindsets

1. Focus on High-Leverage Activities

Use Leverage as Your Yardstick for Effectiveness

杠杆率 = 产出 / 投资时间

杠杆率大概就相当于 ROI,即投资回报比

Increase Your Leverage in Three Ways

提高杠杆率的三个途径:

  • 减少做某件事的时间
  • 增加做某件事的产出
  • 换到有更高杠杆率的事情上

翻译成三个问题:

  • 如何缩短完成这件事情的时间?
  • 如何提高这件事情的产出价值?
  • 有什么值得花费我时间的事情可以产出更多的价值?

Direct Energy Toward Leverage Points, Not Just Easy Wins

聚焦于高杠杆的事情

Key Takeaways

  • 使用杠杆率来衡量你的工程效率
  • 有系统的提高你的时间杠杆率
  • 将你的努力集中在杠杆点上

2. Optimize for Learning

Optimizing for learning is a high-leverage activity for the effective engineer.

Adopt a Growth Mindset

拥抱成长性思维,意味着对你可以改变的各个方面都承担责任,而不是将失败和缺点归咎于你无法控制的事情。

Invest in Your Rate of Learning

three important takeaways

  • 学习也遵循指数式增长曲线
  • 越早优化学习,就可以享受越久的复利
  • 由于复利的作用,微小的学习率偏差在长远看来也能产生巨大的差异

要想让自己获得长期的成功,就必须把自己当成一个处于测试阶段的初创企业或产品,需要每天不断地投资、迭代。

Seek Work Environments Conducive to Learning

Here are six major factors to consider when choosing a new job or team and the questions you should be asking for each of them:

  • 快速增长(公司业务)
  • 培训(公司制度)
  • 开放(公司文化)
  • 节奏(工作节奏)
  • 人(同事关系)
  • 自主性(工作内容)

Dedicate Time on the Job to Develop New Skills

为了投资于自己的成长,你应该拿出自己的20%时间。每天抽出一到两小时的时间,比每周抽出一整天的时间更有效,因为这样你就可以把提高技能当成一种日常习惯。

在这20%的时间里,对你已经在工作的领域和你已经使用的工具有更深的了解,或者可以从“临近科学”获得经验(即工作上下游相关其他工种的一些知识经验)。

利用在工作中可利用的资源的十项建议

  • 研究由你公司最好的工程师编写的核心抽象的代码
  • 写更多的代码。针对提高编码能力,和阅读代码相比,练习是更高杠杆率的活动
  • 浏览内部提供的任何技术或教育材料
  • 掌握你所使用的编程语言
  • 将代码发给最严厉的批评者评审
  • 报名参加你想提高的领域的课程
  • 参与你所感兴趣的项目的设计讨论
  • 从事多样化的项目工作
  • 确保你所在的团队至少有几个高级工程师,你可以向他们学习
  • 毫不畏惧的跳入你不懂的代码中

Always Be Learning

激发工作场所以外的学习习惯的十个出发点

  • 学习新的编程语言和框架
  • 投资于需求量大的技能
  • 阅读书籍
  • 参加讨论小组
  • 参加讲座、会议和聚会
  • 建立并维持一个强大的关系网络
  • 关注一些博客
  • 写一些东西
  • 做一些业务项目
  • 追求自己喜欢的东西

Key Takeaways

  • 为自己负责
  • 不要降低你的学习速率
  • 寻找可以持续成长的工作环境
  • 利用工作机会提高技术技能
  • 寻找工作场所以外的学习机会

3. Prioritize Regularly

Track To-Dos in a Single, Easily Accessible List

To-do lists should have two major properties: they should be a canonical representation of our work, and they should be easily accessible.

Focus on What Directly Produces Value

公司关注的是你创造的价值,例如产品推进、业务指标、用户获取、销售额等,而不是工作了多长时间、完成了多少任务、写了多少代码、开了多少会。

Focus on the Important and Non-Urgent

我们每天都被紧急的事情所淹没:会议、邮件、电话、bug、值班告警、DDL 等。

Partitioning of activities based on urgency and importance

按上图我们根据紧迫性和重要性对事情进行划分,将事情划分为四个象限,其中第二象限重要、不紧急的事最值得我们长期投资关注的,即使没有 DDL。

  • 重要、紧急:高优问题、DDL 等
  • 不重要、紧急:大多数的 email、电话、会议
  • 重要、不紧急:职业生涯规划、建立强人际关系、读书、建立新的高效习惯、构建工具以改善工作流、学习新的语言等等
  • 不重要、不紧急:上网、浪费时间的活动

Protect Your Maker’s Schedule

和其他专业工作相比,软件工程师需要更多、更长的连续时间段来提高工作效率。

尽可能的将会议安排在连续的时间段或者一天的早晚,而不是分散这些会议。

当别人请求帮助时,可以在你完成某项任务停下来休息时再去帮忙,而不是立刻停下自己的工作。

Limit the Amount of Work in Progress

限制同时在进行中的工作数量,人脑的并发处理能力非常有限,尽量避免上下文切换。

Fight Procrastination with If-Then Plans

通过 if-then 计划来避免拖延。例如收集一些 20 分钟内可以完成的短任务,如代码评审、写面试反馈、回邮件、解决小 bug、写独立的单元测试等。

“if I only have 20 minutes before my next activity, then I will do ______.”

Make a Routine of Prioritization

制定优先顺序,养成不断重新回顾、调整这些计划优先级的习惯。

几个有效方法

  • 使用 TODO List 工具来管理任务优先级,可按日、周、月维度制定 TODO List。
  • 在经历旺盛的早上制定或调整任务优先级,反思前一日没有完成的工作计划。
  • 采用番茄工作法,25 分钟集中处理任务,5 分钟方松。

Key Takeaways

  • Write down and review to-dos
    写下并回顾 to-dos
  • Work on what directly leads to value
    做有直接价值的事情
  • Work on the important and non-urgent
    做重要但是不紧急的事情
  • Reduce context switches
    减少上下文切换
  • Make if-then plans to combat procrastination
    使用 if-then 计划和拖延症做斗争
  • Make prioritization a habit
    养成制定优先级的习惯

Part 2: Execute, Execute, Execute

4. Invest in Iteration Speed

Move Fast to Learn Fast

迭代的越快,你能越快的知道这些工作是否有效。

持续部署是提供给你用于加快迭代速度的有力工具之一。

Invest in Time-Saving Tools

节省时间的工具可以带来丰厚的回报。更快的工具会被使用的更多。

值得花费一些努力去寻找一个更平滑的方式以便降低从现有工作流切换到新的工具的成本。

Shorten Your Debugging and Validation Loops

缩短调试和验证的时间周期。

当你修复一个 bug 或者迭代一个新的 feature,发现自己又在重复进行同样的行为的时候,停下来想一想,你是否可以缩短这个时间周期。

Master Your Programming Environment

熟练你的编程环境,包括下面这些点

  • 在版本控制里跟踪变更
  • 编译、构建代码
  • 跑单元测试和应用程序
  • 重启开发中的 Web Server
  • 测试一个表达式的行为
  • 查找函数文档
  • 跳到函数定义
  • 在文本编辑器里重新格式化代码或者数据
  • 找到函数的调用方
  • 重新排列桌面窗口
  • 导航到文件的特定位置

巩固编程功力的入手点

  • 熟练你喜欢的文本编辑器或者 IDE:例如 Emacs、VIM or something else
  • 学习至少一个高产、高级的编程语言:例如 Python、Ruby
  • 熟悉 UNIX 或者 Windows 的 shell 命令:例如 grep、sort、uniq、wc、awk、sed、xargs、find
  • 更加习惯于使用键盘而不是鼠标
  • 自动化你的手工操作
  • 使用交互式解释器来测试自己的想法:Python、Ruby、JavaScript
  • 使运行单元测试尽可能的快和简单

Don’t Ignore Your Non-Engineering Bottlenecks

不要忽视你的非工程的瓶颈。优化迭代速度的最佳策略和优化系统性能一样:找出最大的瓶颈,然后解决它们。

高效工程师会找出并处理这些最大的瓶颈,尽管可能这些瓶颈并不涉及到写代码或者不在他们的舒适区内。

  • 一个常见的瓶颈就是对其他人工作的依赖。沟通对于推进与人相关的瓶颈点至关重要。
  • 另一个常见的瓶颈类型是获得关键决策者的批准。
  • 第三种瓶颈是项目启动之后的审查流程。

在大公司,解决这些瓶颈可能超出了你的影响范围,而你能做的最好的事情是围绕它们开展工作。在小的初创公司,你通常都可以直接解决瓶颈本身。

Key Takeaways

  • 迭代的越快,学的越多
  • 在工具化上投资
  • 优化你的 debug 工作流
  • 掌握你手艺的基本原理
  • 全面了解你的迭代循环

5. Measure What You Want to Improve

Use Metrics to Drive Progress

好的衡量标准能实现一些目标。如果你不能衡量它,你就不能改进它。

  • 首先,他们帮助你专注于正确的事情。
  • 其次,随着时间的推移,良好的衡量标准有助于防止未来的倒退。
  • 第三,好的衡量标准可以推动前进。
  • 第四,一个好的指标可以让你在一段时间内衡量你的效率,并将你所做的事情与你可以做的其他事情进行比较。

Pick the Right Metric to Incentivize the Behavior You Want

挑选正确的指标来激励你想要的行为。指标选择需要关注的点:

  • maximizes impact 最大化影响
  • actionable 可行动的
  • responsive 反应迅速同时健壮

Instrument Everything to Understand What’s Going On

监控一切以了解发生的事情。

Internalize Useful Numbers

内化有用的数字还可以帮助你发现数据监测中的异常。

了解有用的数字可以明确改进的领域和范围,有用的数据有:

  • 注册用户数、日活、月活
  • 每秒请求数
  • 数据存储容量上限
  • 每天读写数据量
  • 支持一个特定服务需要的服务器数量
  • 不同的服务的吞吐量
  • 流量的增长率
  • 页面平均加载时长
  • 产品不同部分之间的流量分布
  • 不同的 Web 浏览器、移动设备、操作系统的流量分布

Be Skeptical about Data Integrity

对数据的完整性持怀疑态度。有时候会混淆相关性和因果关系。

这里有一些策略,你可以用来增加对数据完整性的信心。

  • Log data liberally, in case it turns out to be useful later on.
  • Build tools to iterate on data accuracy sooner.
  • Write end-to-end integration tests to validate your entire analytics pipeline.
  • Examine collected data sooner.
  • Cross-validate data accuracy by computing the same metric in multiple ways.
  • When a number does look off, dig in to it early.

Key Takeaways

  • Measure your progress
    衡量进度
  • Carefully choose your top-level metric
    仔细的选择最顶级的指标
  • Instrument your system
    监控你的系统
  • Know your numbers
    了解你的数据
  • Prioritize data integrity
    优先考虑数据完整性

6. Validate Your Ideas Early and Often

尽早并且经常性的验证你的想法,尽快根据用户反馈来优化。

尽早并经常验证我们的想法有助于我们完成正确的事情。

Find Low-Effort Ways to Validate Your Work

找到低成本的方式来验证你的工作。一个可行的验证想法的方式是花 10% 的投入构建一个小而又足够信息的原型。

投入少量的工作来收集数据以验证你的项目假设和目标。从长远来看,你会为自己节省很多浪费的精力。

Continuously Validate Product Changes with A/B Testing

持续通过 A/B 测试来验证产品变更。

Beware the One-Person Team

当心一人团队。需要建立有效的反馈渠道:

  • 保持开放,乐于接受反馈
  • 尽早且经常的提交代码评审
  • 请求最严格的评审者来评审代码
  • 询问同事的想法看法
  • 先设计系统的接口或 API
  • 投入编码前先展示你的设计文档
  • 如果可能,请对正在进行的项目进行结构设计,以便与队友共享一些上下文
  • 在投入太多时间之前,对有争议的问题寻求讨论和支持

Build Feedback Loops for Your Decisions

为你的决策建立反馈回路。

设计实验验证你的猜想,不论好坏,从实验结果中学习。

Key Takeaways

  • Approach a problem iteratively to reduce wasted effort
    迭代的去处理问题,以避免浪费投入
  • Reduce the risk of large implementations by using small validations
    将大的实现拆分成小模块验证以降低风险
  • Use A/B testing to continuously validate your product hypotheses
    使用 A/B 测试来持续的验证你的产品假设
  • When working on a solo project, find ways of soliciting regular feedback
    当工作在一个独立项目中时,寻求一个定期的外部反馈
  • Adopt a willingness to validate your decisions
    采取积极的态度去验证你的决定

7. Improve Your Project Estimation Skills

项目估期是高效工程师需要学习的最难的技能之一。

Use Accurate Estimates to Drive Project Planning

使用准确的估期来驱动项目计划。下面列出一些策略:

  • 拆分项目成小的任务
  • 估期建立在任务需要多久完成,而不是你或者其他人希望多久完成
  • 将估期视为概率分布,而不是最佳情况
  • 让实际做这项工作的人来估期
  • 当心锚点偏差
  • 使用多种方式来估计同样的任务
  • 警惕人月神话:加人缩短不了工期
  • 通过历史数据来验证估期
  • 使用时间框架来限制任务的增长
  • 允许别人挑战你的估期

Budget for the Unknown

给未知事物留下缓冲预算。

Define Specific Project Goals and Measurable Milestones

设定明确的项目目标和可衡量的里程碑。

明确定义的目标提供了一个重要的过滤器,用于将任务列表中的必须有与最好有分开。

定义特定项目目标的第二个好处是,它可以在关键利益相关者之间建立了明确性和一致性。

Reduce Risk Early

尽早暴露问题并降低风险。

如何降低集成风险?尽早做端到端的脚手架和系统整合测试。

Approach Rewrite Projects with Extreme Caution

以极其谨慎的态度对待重写项目。

有重写经验的工程师,倾向于把大的项目重写分解成一系列的小项目。

Don’t Sprint in the Middle of a Marathon

不要在马拉松比赛中冲刺。

为什么更多的工作时间不一定意味着能赶上发布日期的一些原因:

  • 工作时长增加,每小时工作效率降低
  • 和你想象的相比,你可能比计划表落后的更多
  • 额外的工作会压垮团队成员
  • 增加工作时长会伤害成员的工作热情
  • 随着截止日期的临近,沟通的开销会增加
  • 最后冲刺会产生大量的技术债

Key Takeaways

  • Incorporate estimates into the project plan
    将估期纳入到项目计划中
  • Allow buffer room for the unknown in the schedule
    为日程表中的未知因素留出缓冲空间
  • Define measurable milestones
    定义可衡量的里程碑
  • Do the riskiest tasks first
    先做风险大的任务
  • Know the limits of overtime
    明确加班的局限性

Part 3: Build Long-Term Value

8. Balance Quality with Pragmatism

Establish a Sustainable Code Review Process

建立可持续的代码评审流程。好处有:

  • 尽早发现 bug 和设计缺陷
  • 增加对代码变更的责任心
  • 对如何写好代码进行积极的示范
  • 共享代码库的相关知识
  • 提升长期的敏捷度

Manage Complexity through Abstraction

通过抽象来管理复杂度。正确的抽象可以增加生产力,有以下好处:

  • 通过降低原始问题的复杂度为更容易理解的问题
  • 降低未来的维护成本并且更加容易后续功能迭代
  • 解决一个复杂的问题一次,解决方案未来就可以使用很多次

好的抽象应该是:

  • 容易学习
  • 在没有文档的情况下依然容易使用
  • 很难误用、用错
  • 足够强大以满足需求
  • 容易扩展
  • 对使用者很合适

开始使用抽象的一些建议:

  • Find popular abstractions in your codebase at work or from repositories on GitHub. Read through their documentation, dig through their source code, and try extending them.
  • Look through the open source projects at technology companies like Google, Facebook, LinkedIn, and Twitter. Learn why abstractions like Protocol Buffers, Thrift, Hive, and MapReduce have been indispensable to their growth.
  • Study the interfaces of popular APIs developed by Parse, Stripe, Dropbox, Facebook, and Amazon Web Services, and figure out what makes it so easy for developers to build on top of their platforms. Also reflect on APIs that you or the rest of community don’t like, and understand what you don’t like about them.

Automate Testing

自动化测试。有以下优点:

  • Automated testing doesn’t just reduce bugs; it provides other benefits as well.
  • Tests also allow engineers to make changes, especially large refactorings, with significantly higher confidence.
  • When code does break, automated tests help to efficiently identify who’s accountable.
  • Finally, tests offer executable documentation of what cases the original author considered and how to invoke the code.

仅仅因为自动化测试是有益的,并不意味着为所有东西建立自动化测试总是一个好主意。100% 的代码覆盖率是很难实现的,有些代码比其他代码更难实现自动化测试。

Repay Technical Debt

偿还技术债。

  • 技术债不会只是在我们做快速、肮脏的变通工作时才会积累起来。每当我们在不完全了解问题空间的情况下编写软件时,我们的第一个版本最终都可能设计得不如我们所希望的那么干净。
  • 成为一个高效工程师的关键是在面临 DDL 的时候,可以引入一定的技术债,但同时也会周期性的偿还技术债。
  • 高效工程师花费有限的时间以最高的杠杆率偿还债务——代码库中人流密集的部分中花费最少的时间进行修复。

Key Takeaways

  • Establish a culture of reviewing code
    建立 code review 文化
  • Invest in good software abstractions to simplify difficult problems
    在好的软件抽象上投入以简化困难的问题
  • Scale code quality with automated testing
    通过自动化测试提高代码质量
  • Manage your technical debt
    管理你的技术债

9. Minimize Operational Burden

Embrace Operational Simplicity

拥抱操作的简单性。

拥有复杂架构设计带来一系列的维护问题:

  • 工程师的专长经验被分散到多个系统上
  • 复杂性带来潜在人员的单点故障问题
  • 新成员面临着陡峭的学习曲线
  • 投入到提升抽象程度、库和工具的资源被分散到不同的系统上

Build Systems to Fail Fast

快速失败并不意味着让程序给终端用户输出崩溃。可以用全局的异常处理,快速上报这些错误,但优雅的给普通用户异常降级处理。

Relentlessly Automate Mechanical Tasks

坚持不懈地实现机械任务的自动化。每次你做了某些机器可以完成的工作,问问自己是否值得自动化这些工作。

工程师很少做自动化的原因:

  • 没有时间立刻做
  • 受到公共性悲剧的影响,做有利于个人利益的事,但却违背了团队长期利益
  • 不熟悉自动化工具
  • 低估了未来相同任务的频率
  • 没有在很长的时间范围内将节省的时间内化

可以在下面这些事上做自动化:

  • Validating that a piece of code, an interaction, or a system behaves as expected
  • Extracting, transforming, and summarizing data
  • Detecting spikes in the error rate
  • Building and deploying software to new machines
  • Capturing and restoring database snapshots
  • Periodically running batch computations
  • Restarting a web service
  • Checking code to ensure it conforms to style guidelines
  • Training a machine learning model
  • Managing user accounts or user data
  • Adding or removing a server to or from a group of services

Make Batch Processes Idempotent

让批处理任务保持幂等性。无副作用,可重试。

Hone Your Ability to Respond and Recover Quickly

磨练你的快速响应和恢复的能力。

针对主要的故障,最有效的防御措施就是经常失败,建立快速恢复的能力。将时间和精力集中在我们的快速恢复能力上,比起一开始就预防失败,具有更高的杠杆作用。

Key Takeaways

  • Do the simple thing first
    先做简单的事情
  • Fail fast to pinpoint the source of errors
    快速失败以便快速找到问题的根源
  • Automate mechanics over decision-making
    自动化比决策更重要
  • Aim for idempotence and reentrancy
    旨在实现幂等和可重试
  • Plan and practice failure modes
    计划和实践失败模式

10. Invest in Your Team’s Growth

如果你想提高效率,那么重要的是要认识到,建立一支强大的团队和积极的文化具有相当大的影响力。

在职业生涯的早期就思考如何帮助你的同事成功,这会灌输正确的习惯,进而养成你自己的成功。

Make Hiring Everyone’s Responsibility

让招聘工作成为每个人的责任。

良好的面试过程可以实现两个目标。 首先,它筛选可能在团队中表现出色的人员类型。 其次,它使候选人对团队,任务和文化感到兴奋。

  • 花时间和你的团队一起考虑清楚,对于潜在候选人到底哪些特性是你最关心的
  • 周期性的回顾讨论当前面试流程的有效性
  • 设计面试问题,带有多个层次深度,以便能够适配不同能力水平的面试者
  • 控制面试节奏以便获得更高的信噪比
  • 通过迅速发出简短答案来扫描危险信号,以探测广阔的表面区域
  • 在面试中经常与另一位团队成员搭配
  • 不要害怕使用非常规的面试方法,只要它们能帮助你确定团队所关心的信号

Design a Good Onboarding Process

设计一个好的入职流程。

第一印象很重要。 良好的初始经验会影响工程师对工程文化的理解,影响其交付未来的能力,并根据团队的工作重点指导他的学习和活动。

入职流程的四个目标:

  • 新工程师尽快提升产出
  • 传授团队文化和价值
  • 使新工程师拥有成功所需的广泛基础知识
  • 通过社交方式将新工程师整合到团队中

Share Ownership of Code

共享代码的主人翁意识。

当你成为某个项目的瓶颈时,你就失去了做其他事情的灵活性。

一些共享策略:

  • 避免一个人的团队
  • 互相 review 代码和设计
  • 在整个团队中轮换任务
  • 保持代码的可读性和质量
  • 针对软件设计和架构进行技术演讲
  • 文档化,不论是设计文档还是代码注释
  • 记录完成工作所需的复杂工作流程或非显而易见的解决方法
  • 花时间在教学和指导其他团队成员上

Build Collective Wisdom through Post-Mortems

通过事后复盘来建立集体智慧。

Build a Great Engineering Culture

建立伟大的工程师文化。伟大的工程师文化有以下特征:

  1. Optimize for iteration speed.
    为迭代速度而优化
  2. Push relentlessly towards automation.
    持续无情的追求自动化
  3. Build the right software abstractions.
    建立正确的软件抽象
  4. Focus on high code quality by using code reviews.
    通过代码评审关注高质量的代码
  5. Maintain a respectful work environment.
    维护一个互相尊重的工作环境
  6. Build shared ownership of code.
    建立一个共享的代码主人翁意识
  7. Invest in automated testing.
    在自动化测试上投入
  8. Allot experimentation time, either through 20% time or hackathons.
    分配实验性时间
  9. Foster a culture of learning and continuous improvement.
    培养持续学习和提升的文化
  10. Hire the best.
    雇佣最优秀的人才

Key Takeaways

  • Help the people around you be successful
    帮助你周围的人获得成功
  • Make hiring a priority
    将招聘作为优先事项
  • Invest in onboarding and mentoring
    在入职培训和指导上投资
  • Build shared ownership of code
    建立代码的共享主人翁意识
  • Debrief and document collective wisdom
    总结并记录集体智慧
  • Create a great engineering culture
    建立伟大的工程师文化

Reference

comments powered by Disqus