<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>caines.ca</title>
	<subtitle>Software engineering notes from Gregg Caines</subtitle>
	
	<link href="/atom.xml" rel="self"/>
	<link href=""/>
	<updated>2026-06-21T17:46:18Z</updated>
	<id>https://caines.ca/</id>
	<author>
		<name>Gregg Caines</name>
		<email>gregg@caines.ca</email>
	</author>
	
	<entry>
		<title>Agentic Bug Fixing: /undefect</title>
		<link href="/posts/2026-06-17-agentic-bug-fixing-undefect/"/>
		<updated>2026-06-17T00:00:00Z</updated>
		<id>/posts/2026-06-17-agentic-bug-fixing-undefect/</id>
		<content type="html">&lt;p&gt;I&#39;ve got a skill that drastically improves code quality and architecture and it&#39;s powered by defects.&lt;/p&gt;
&lt;p&gt;I&#39;m sure you&#39;ve already had many scenarios where you&#39;ve had your agent fix the same bug 3-4 times. That&#39;s not just a defect, it&#39;s a systemic failure.&lt;/p&gt;
&lt;p&gt;Sure, we want to fix the bug -- but it&#39;s even better to fix the problem that caused the problem: to learn what went wrong and what conditions made us bug-prone. Fixing the bug isn&#39;t as powerful as fixing the conditions that created it.&lt;/p&gt;
&lt;p&gt;That&#39;s what &lt;code&gt;/undefect&lt;/code&gt; is for: it investigates a defect deeply and makes it easy to detect -- without fixing it yet. (If you&#39;d rather see it work before reading the design, skip to &lt;a href=&quot;#what-a-run-looks-like&quot;&gt;what a run looks like&lt;/a&gt;.)&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;You can &lt;a href=&quot;https://github.com/cainus/skillz/blob/main/skills/undefect/SKILL.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;grab the skill from my &lt;code&gt;skillz&lt;/code&gt; repo on GitHub&lt;/a&gt;, or you can &lt;a style=&quot;cursor: pointer&quot;&gt;click here to expand it here&lt;/a&gt;.&lt;/summary&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; undefect
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;
  Investigate a software defect without fixing it. Use when the user wants a
  complete bug investigation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; root&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;cause explanation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; early detection measures
  through types/tests/logging/user feedback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; verification that each detection
  measure catches the defect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; architectural recommendations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; and a scan for
  similar defects from similar causes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; while explicitly preserving the defect
  for a later fix.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; Undefect&lt;/span&gt;

Use this skill to understand a defect deeply and make it easy to detect, without fixing the defect yet.

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Prime Directive&lt;/span&gt;

Do not fix the defect as the outcome of this skill.

If investigation requires temporarily fixing the defect to prove causality, do it only as an experiment. Before finishing, revert the temporary fix and leave only detection, observability, documentation, or user-feedback changes that do not correct the defect itself.

Our main goal is to either eliminate the potential for this class of defect, or failing that, make detection simpler and faster.

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Workflow&lt;/span&gt;

&lt;span class=&quot;token list punctuation&quot;&gt;1.&lt;/span&gt; Establish the defect precisely.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Reproduce it from the user-visible behavior, a failing command, a failing test, logs, or a minimal code path.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Record the expected behavior, actual behavior, trigger conditions, affected surface area, and any non-reproduction cases discovered.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Prefer local deterministic reproduction before production reproduction. Avoid production mutation unless the user explicitly allows it.

&lt;span class=&quot;token list punctuation&quot;&gt;2.&lt;/span&gt; Explain why the bug exists.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Trace the code path from input/event to wrong outcome.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Identify the missing, incorrect, or duplicated responsibility that permits the defect.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Before calling it a local bug, ask whether the failing behavior is caused by two sources of truth, duplicated policy, split ownership, or drift between surfaces that should share one contract.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; If the defect involves ordering, prioritization, authorization, validation, naming, state transitions, derived status, or other policy, explicitly identify the canonical owner that should decide that policy. If no clear owner exists, call that out as part of the root cause.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Distinguish facts from inferences.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; If useful, prove causality with a temporary experiment, then revert that experiment.

&lt;span class=&quot;token list punctuation&quot;&gt;3.&lt;/span&gt; Add the fastest local detection mechanism that can reveal the defect without fixing it.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Prefer compile-time/type-checking when realistic.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Otherwise prefer a focused unit/integration test.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Use end-to-end tests only when lower-level tests cannot express the failure.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Prefer detectors at the contract boundary or canonical policy owner over detectors in only one consumer. For drift bugs, add a detector that compares sibling surfaces or forces them through the same shared contract.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Keep the detector narrowly scoped to the defect.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Run the detector and confirm it fails or signals because the defect still exists.

&lt;span class=&quot;token list punctuation&quot;&gt;4.&lt;/span&gt; Add the fastest production/system feedback mechanism that can reveal the defect without fixing it.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Prefer structured logging for invisible backend failures or missing side effects.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Add user feedback when the user can recover, retry, or needs to know work did not happen.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Avoid redundant detectors. If a type check makes a unit test unnecessary, or a test makes extra logging unnecessary, skip the redundant measure.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; After each measure, trigger the defect and confirm the measure fires.

&lt;span class=&quot;token list punctuation&quot;&gt;5.&lt;/span&gt; Preserve silent-failure prevention.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; The final state should not allow the defect to remain completely silent for both developers and users.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Aim for one fast local signal and one fast production/user-facing signal.

&lt;span class=&quot;token list punctuation&quot;&gt;6.&lt;/span&gt; Look for enabling architecture problems.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Identify refactorings that would make this class of defect harder to create.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Favor structural improvements: single source of truth, typed contracts, centralized side-effect helpers, parameterized APIs, exhaustive switches, shared adapters, or stronger invariants.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; When there are multiple implementations of the same business policy, recommend combining them behind one owner instead of patching each caller independently.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; When behavior differs by surface (UI, CLI, API, worker, integration), decide whether the difference is intentional. If it is not intentional, recommend a shared contract and list every surface that should consume it.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Present these as recommendations unless the user asks to implement them.

&lt;span class=&quot;token list punctuation&quot;&gt;7.&lt;/span&gt; Look for similar defects from similar causes.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Search for nearby code paths, sibling features, duplicate implementations, adapter variants, route variants, and test gaps that share the same missing, incorrect, or duplicated responsibility.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Use the root cause as the search key, not just the symptom text.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; For each plausible similar defect, report whether it is confirmed, ruled out, or still uncertain.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Add detection for confirmed similar defects only when it fits the user&#39;s requested scope and does not fix the defect.
   &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Do not broaden into unrelated cleanup; keep the pass focused on defects enabled by the same cause.

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Verification Rules&lt;/span&gt;

After every detection or feedback measure:

&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Trigger the defect again.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Report the command, test, log line, or UI feedback that proves the detector worked.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; If the detector does not fire, improve it or explain why that detection route is not viable.

Before finishing:

&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Re-run the fastest detector.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Confirm the defect is still unfixed unless the user explicitly changed the goal.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Confirm any temporary fix experiments were reverted.

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Final Response Shape&lt;/span&gt;

Lead with the root cause and the detection measures added.

Include:

&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Why the defect exists.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; What detection/feedback was added.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; How each detector was verified.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Whether the defect remains intentionally unfixed.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Any architectural refactorings recommended for a later change.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Similar defects from similar causes that were confirmed, ruled out, or left uncertain.
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Any tests or commands that were not run.&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;h2 id=&quot;what-a-run-looks-like&quot;&gt;What a run looks like&lt;/h2&gt;
&lt;p&gt;Here&#39;s a (lightly fictionalized) run on a drift bug -- the case &lt;code&gt;/undefect&lt;/code&gt; is most interesting on -- as it actually scrolls by in the terminal:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; /undefect customers see &quot;free shipping unlocked&quot; at a $50 cart subtotal,
  but checkout still charges them $6.99 shipping

● I&#39;ll investigate without fixing it: reproduce, find the root cause, and
  leave behind detection that fails *because* the bug is still live.

● Search(pattern: &quot;free.?shipping|shippingCost|FREE_SHIPPING&quot;)
  ⎿  6 matches across 4 files

● Read(cart/summary.js)
  ⎿  read 24 lines
● Read(checkout/shipping.js)
  ⎿  read 18 lines

● Reproduced. The threshold lives in two places and they disagree at the
  boundary:

      cart/summary.js       subtotal &gt;= 50   -&gt; banner says &quot;free&quot;
      checkout/shipping.js   subtotal &gt; 50    -&gt; charges $6.99

  At exactly $50 the cart says free and checkout charges. This isn&#39;t a local
  bug -- it&#39;s two sources of truth for one pricing policy, with no canonical
  owner. Both surfaces re-derive the rule, so they&#39;re free to drift.

● Adding a local detector at the contract seam -- it forces both surfaces to
  agree on the same input instead of testing just one consumer.

● Write(shipping-policy.contract.test.js)
  ⎿  wrote 6 lines

● Bash(npx vitest run shipping-policy.contract.test.js)
  ⎿   FAIL  shipping-policy.contract.test.js &gt; banner and checkout agree at 50
          expected false to be true
          - Expected:  true   (banner: free)
          + Received:  false  (checkout: charged $6.99)
        Tests  1 failed | 5 passed (6)

● Good -- red, and only at 50. The reproduction is now nailed to a test.

● Adding a production signal so the silent version of this stays loud: a
  structured log when the two surfaces disagree at request time.

● Update(checkout/shipping.js)
  ⎿  +3 lines (detection only -- does NOT change the charge)

● Bash(curl -s localhost:3000/checkout -d subtotal=50 &gt;/dev/null; tail -1 dev.log)
  ⎿  WARN shipping_policy_drift {&quot;subtotal&quot;:50,&quot;banner&quot;:true}

● Fires. The $50 cart is still charged $6.99 -- I have not fixed the bug.

● Sweeping for the same *cause* (&quot;threshold re-derived per surface&quot;), not the
  symptom text:
  ⎿  email/receipt.js             CONFIRMED  hardcodes `subtotal &gt; 50`
     promo/eligibility-worker.js  CONFIRMED  uses `&gt;= 50` AND a stale `45` flag
     mobile/CartScreen.tsx        UNCERTAIN  calls /cart/summary -- needs a trace
     admin/order-export.csv       RULED OUT  reads persisted shipping_charged

● Done. The defect is still live, and now it&#39;s cornered:

  Root cause   Two sources of truth for the free-shipping threshold, no
               canonical owner. `&gt;=` vs `&gt;` drift breaks the $50 boundary.
  Detection    1 failing contract test (red at $50) + 1 drift log line.
  Verified     Watched the test fail for the right reason; saw the log fire.
  Still broken Yes -- $50 carts are still charged. Fix intentionally deferred.
  Recommend    One owner: shippingPolicy.qualifiesForFree(subtotal), called by
               both surfaces. The contract test then guards the seam forever.
  Similar      2 confirmed, 1 uncertain, 1 ruled out (above).&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One $50 bug, cornered by a test I watched go red -- and three more places the same policy is duplicated, surfaced by the sweep.&lt;/p&gt;
&lt;p&gt;Here&#39;s the thinking behind the design.&lt;/p&gt;
&lt;h2&gt;Why forbid the fix?&lt;/h2&gt;
&lt;p&gt;Like I said, this skill purposely leaves the defect unfixed. That&#39;s so you can check whether the tests or other measures actually find the defect. I can&#39;t tell you how many times I&#39;ve seen people write tests after the fix, and they get coverage but don&#39;t actually ensure the defect can&#39;t happen again. You have to write your tests first and see them fail in order to &amp;quot;test your tests&amp;quot;.&lt;/p&gt;
&lt;p&gt;The moment a bug is fixed, the agent loses its reproduction. There&#39;s nothing left to point a new test at, nothing to confirm a log line fires for, nothing to prove an architectural change actually closes the hole. The defect is the only ground truth you have, and a fix destroys it.&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;/undefect&lt;/code&gt; keeps the bug alive on purpose, and uses it as a target to verify against. Every detection measure it adds gets &lt;em&gt;run against the live defect&lt;/em&gt; to prove it actually fires. By the time the skill finishes, you have a failing test (or a type error, or a log line) that you&#39;ve watched fail for the right reason.&lt;/p&gt;
&lt;h2&gt;Root cause, not symptom&lt;/h2&gt;
&lt;p&gt;The symptom above was &amp;quot;checkout charged $6.99 at a $50 cart.&amp;quot; The cause was &amp;quot;we handle pricing differently in two different places instead of having a &lt;a href=&quot;https://en.wikipedia.org/wiki/Single_source_of_truth&quot;&gt;single clear source of truth&lt;/a&gt;.&amp;quot;&lt;/p&gt;
&lt;p&gt;Once you&#39;ve got the root cause, you&#39;ve identified a pattern that allows you to ask:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Are there other possible defects caused by this pattern?&lt;/li&gt;
&lt;li&gt;Do we have any safety measures in place to help eliminate/prevent/detect this pattern in the future?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You want to be able to inoculate both cross-codebase and into the future. Every defect is an opportunity to improve the system that the agent is working in.&lt;/p&gt;
&lt;h2&gt;One fast signal locally, one in production&lt;/h2&gt;
&lt;p&gt;Steps 3-5 are a deliberate pair. A test that catches the bug on your laptop does nothing for the version of this bug that happens silently in production six weeks from now. A log line does nothing for the version a teammate reintroduces before they ever deploy. So the skill aims for &lt;em&gt;both&lt;/em&gt;: one fast local detector and one fast production/user-facing signal, and explicitly tries to avoid the defect ever being completely silent again.&lt;/p&gt;
&lt;p&gt;It also tries &lt;em&gt;not&lt;/em&gt; to pile on redundant detectors. If a type makes the bug impossible to express, you don&#39;t also need a unit test for it. The cheapest, fastest signal that actually fires wins.&lt;/p&gt;
&lt;h2&gt;Verify everything fires&lt;/h2&gt;
&lt;p&gt;I don&#39;t trust a detector I haven&#39;t watched fail. Neither should the agent. The verification rules force it to trigger the defect again after each measure and report the exact command, test, or log line that proved the detector worked. This is the same instinct as &lt;a href=&quot;https://martinfowler.com/bliki/TestDrivenDevelopment.html&quot;&gt;TDD&#39;s red step&lt;/a&gt;; a test you&#39;ve never seen fail is a test you can&#39;t trust.&lt;/p&gt;
&lt;p&gt;LLMs are &lt;em&gt;especially&lt;/em&gt; prone to writing a confident-looking test that passes for the wrong reason. Making the defect prove the detector closes that gap.&lt;/p&gt;
&lt;h2&gt;The similar-defects sweep&lt;/h2&gt;
&lt;p&gt;Step 7 is the payoff for doing root-cause analysis properly: The same missing validation probably exists in the sibling route. The same drift probably exists on the CLI that the UI just exposed. So the skill goes looking, and reports each candidate as confirmed, ruled out, or uncertain.&lt;/p&gt;
&lt;p&gt;This is where one bug investigation quietly prevents three more.&lt;/p&gt;
&lt;h2&gt;Why this is a separate skill from fixing&lt;/h2&gt;
&lt;p&gt;You could imagine folding all of this into a normal &amp;quot;fix the bug&amp;quot; flow. I keep it separate on purpose. Fixing is goal-directed and wants to converge fast; investigation wants to stay open and suspicious. Mixing them means the convergence pressure of &amp;quot;make it green&amp;quot; wins, and the investigation gets skipped. By making &lt;code&gt;/undefect&lt;/code&gt; a thing you run &lt;em&gt;before&lt;/em&gt; you fix -- and one that refuses to fix -- the investigation actually happens.&lt;/p&gt;
&lt;h2&gt;Better Taste == Better Autonomy&lt;/h2&gt;
&lt;p&gt;Concretely, this is what changes for me day to day: I can hand the agent a list of 20 defects, tell it to run &lt;code&gt;/undefect&lt;/code&gt; on each, implement the recommendations, and fix the bugs -- and trust that what comes back is investigated, not just patched.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/undefect&lt;/code&gt; is really just my taste in debugging, written down -- the same way &lt;a href=&quot;/posts/2026-03-10-agentic-refactoring-defrag/&quot;&gt;&lt;code&gt;/defrag&lt;/code&gt;&lt;/a&gt; is my taste in refactoring. I highly doubt that agent autonomy will be sufficiently achieved through bigger/better models alone. We need to inject our human taste into the recipe or be ever-present babysitters. Every skill like this is one more thing you no longer have to be in the room for.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Agentic Refactoring: /defrag</title>
		<link href="/posts/2026-03-10-agentic-refactoring-defrag/"/>
		<updated>2026-03-10T00:00:00Z</updated>
		<id>/posts/2026-03-10-agentic-refactoring-defrag/</id>
		<content type="html">&lt;p&gt;Here&#39;s a question: if you were told you were going to get the biggest, worst codebase that you had to work on, sight-unseen, but you could magically apply one refactoring to it, what would that refactoring be?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;good naming?&lt;/li&gt;
&lt;li&gt;no god classes?&lt;/li&gt;
&lt;li&gt;tabs instead of spaces? 🙃&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think it&#39;s a good question, because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The magic largely exists all of a sudden in the way of LLMs.&lt;/li&gt;
&lt;li&gt;I want to be &lt;em&gt;reading&lt;/em&gt; less agentic code, but I don&#39;t want &lt;a href=&quot;https://en.wikipedia.org/wiki/Slop_(artificial_intelligence)&quot;&gt;slop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LLMs don&#39;t handle slop well either&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Slop is the reason that you can ask an agent to build out a full 3d game, but it explodes into a fine mist if you ask it immediately after to change the character&#39;s shirt color.  LLMs need good factoring / code organization just like humans do.&lt;/p&gt;
&lt;p&gt;To that end I&#39;ve been running an agentic refactor skill for Claude Code that I call &lt;code&gt;/defrag&lt;/code&gt;.  I run it after a large new feature or after a couple of smaller features to keep the code maintainable and to keep the agents effective.  It also happens to contain my 14 answers to the original question.&lt;/p&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; defrag
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Analyze code for refactoring opportunities and suggest the top 10 highest&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;value improvements. Use when the user says /defrag&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;refactor&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;clean up code&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; or asks for code improvements.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; Defrag - Code Refactoring Analysis&lt;/span&gt;

Analyze the specified file(s) or the user&#39;s current selection and identify the top 10 highest-value refactoring opportunities.

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Refactoring Types to Look For&lt;/span&gt;

&lt;span class=&quot;token list punctuation&quot;&gt;1.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;shorten_file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Files &gt;300 lines should be broken into multiple coherent files
&lt;span class=&quot;token list punctuation&quot;&gt;2.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;shorten_function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Functions &gt;50 lines should be broken into smaller functions with descriptive names
&lt;span class=&quot;token list punctuation&quot;&gt;3.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;reduce_nesting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Replace nested conditionals with guard clauses and early returns
&lt;span class=&quot;token list punctuation&quot;&gt;4.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;extract_function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Extract repeated or complex code into well-named functions
&lt;span class=&quot;token list punctuation&quot;&gt;5.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;rename_for_clarity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Improve variable/function names that are unclear or too short
&lt;span class=&quot;token list punctuation&quot;&gt;6.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;simplify_conditionals&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Simplify if/else logic, use early return where possible
&lt;span class=&quot;token list punctuation&quot;&gt;7.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;extract_constants&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Move magic numbers/strings to local constants (NOT global constants files)
&lt;span class=&quot;token list punctuation&quot;&gt;8.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;consolidate_duplicates&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Merge duplicate code blocks
&lt;span class=&quot;token list punctuation&quot;&gt;9.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;modernize_syntax&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Use modern language features (destructuring, optional chaining, etc.)
&lt;span class=&quot;token list punctuation&quot;&gt;10.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;avoid_globality&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Move global items closer to where they&#39;re used; no utils/constants/managers files
&lt;span class=&quot;token list punctuation&quot;&gt;11.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;optimize_imports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Clean up unused or poorly organized imports
&lt;span class=&quot;token list punctuation&quot;&gt;12.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;remove_dead_code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Remove unused code.  In typescript you can use knip for that.
&lt;span class=&quot;token list punctuation&quot;&gt;13.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;add_tests&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Identify code lacking test coverage
&lt;span class=&quot;token list punctuation&quot;&gt;14.&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;break_up_hotspots&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - look at the last 30 days of git history for the 5 files with the most changes.  Suggest decomposition for any file that&#39;s changed more than 30 times.

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Scoring (Value Score 0-100)&lt;/span&gt;

Calculate each refactoring&#39;s value using these weights:
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Readability improvement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; (35%)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Maintainability improvement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; (30%)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Bug risk reduction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; (25%)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Performance impact&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; (5%)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Scope size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; (5%)

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Output Format&lt;/span&gt;

For each refactoring opportunity, provide:

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; {rank}. **{type}** (Value: {score}/100)&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;File:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`{filepath}:{start_line}-{end_line}`&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Description:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; {one-line description}
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Rationale:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; {why this helps}

&lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Before:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;{language}&lt;/span&gt;
&lt;span class=&quot;token code-block language-language&quot;&gt;{current code snippet}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;After:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;{language}&lt;/span&gt;
&lt;span class=&quot;token code-block language-language&quot;&gt;{refactored code snippet}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token hr punctuation&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Instructions&lt;/span&gt;

&lt;span class=&quot;token list punctuation&quot;&gt;1.&lt;/span&gt; Read the file(s) the user specifies (or use their IDE selection)
&lt;span class=&quot;token list punctuation&quot;&gt;2.&lt;/span&gt; Analyze for all refactoring types listed above
&lt;span class=&quot;token list punctuation&quot;&gt;3.&lt;/span&gt; Score each opportunity using the weighted formula
&lt;span class=&quot;token list punctuation&quot;&gt;4.&lt;/span&gt; Sort by value score (highest first)
&lt;span class=&quot;token list punctuation&quot;&gt;5.&lt;/span&gt; Present the top 10 refactorings
&lt;span class=&quot;token list punctuation&quot;&gt;6.&lt;/span&gt; End with: &quot;Found {N} refactoring opportunities. Top 10 shown with average score: {avg}&quot;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; Important Rules&lt;/span&gt;

&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Do NOT apply changes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - This is analysis only (plan mode)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Sort by value_score&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Highest value first
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Show before/after code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - For each suggestion
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Be specific&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Include exact file paths and line numbers
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;Follow YAGNI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Don&#39;t suggest over-engineering or future-proofing
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;No global constants files&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; - Constants belong near their usage

After presenting, ask: &quot;Would you like me to apply any of these? Say &#39;apply #1&#39; or &#39;apply all&#39;.&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s the thinking behind some of these rules:&lt;/p&gt;
&lt;h2&gt;About function length and file size&lt;/h2&gt;
&lt;p&gt;I got the ideal numbers by asking the LLM for ideal maximums.  It probably doesn&#39;t know any better than I do, so feel free to fill in your own choices, but if you&#39;re coding agentically for long you&#39;ll hit whatever maximum you set eventually.  Why this helps: These maximums are two primary drivers of abstraction.  Just like a human, the LLM can look at a file name or function name and assume what it does from the name instead of having to read all the code in it.  That means it has to read a lot less code, and it uses a lot less context.&lt;/p&gt;
&lt;p&gt;I also asked the LLM &amp;quot;which is more expensive for LLMs: long files or long functions?&amp;quot;  It told me that it can grep through long files but it has to read the entirety of a function, so long functions are more expensive for it.  I don&#39;t actually totally believe the LLMs with these answers.  I&#39;ll need to run some evals on all of this at some point, but I think it&#39;s a good starting point.&lt;/p&gt;
&lt;h2&gt;Reducing code&lt;/h2&gt;
&lt;p&gt;I feel like reducing code has got to be one of the easiest ways for a codebase to require less context.  Larger codebases are usually harder for an llm to manage than smaller ones with all else equal.  To that end, I try to find and remove dead code and deduplicate code.  This didn&#39;t require more proof for me anyway.&lt;/p&gt;
&lt;h2&gt;Reducing complexity&lt;/h2&gt;
&lt;p&gt;LLMs are better at complexity than us, but they have all the same issues in following code that we do.  For that reason I try to reduce nesting, early return when possible, and avoid making things more global than they need to be.&lt;/p&gt;
&lt;h2&gt;Adding Tests&lt;/h2&gt;
&lt;p&gt;Tests are a no-brainer part of good &lt;a href=&quot;https://martinfowler.com/articles/exploring-gen-ai/harness-engineering.html&quot;&gt;harness engineering&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Breaking up Hotspots&lt;/h2&gt;
&lt;p&gt;I call files that are changed really frequently &amp;quot;hotspots&amp;quot;.  The problem with hotspots is that if you&#39;re using many agents in parallel, they easily cause merge conflicts.  It&#39;s just another good signal that a file needs to be broken up.&lt;/p&gt;
&lt;h2&gt;What I removed: 3rd party library suggestions&lt;/h2&gt;
&lt;p&gt;I used to have a rule that asked it to suggest a 3rd party library for any repeated pattern it finds. I removed it after an LLM told me that 3rd party libraries can be a liability if it&#39;s not trained on them. It&#39;s often easier to solve patterns internally where the source code is available to read.&lt;/p&gt;
&lt;h2&gt;A few interesting things I&#39;ve seen with this approach&lt;/h2&gt;
&lt;p&gt;It actually works pretty well.  If you&#39;re refactoring with this often, it will only find issues in code you&#39;ve worked on recently and haven&#39;t refactored.  So it&#39;s really finding and fixing things as it goes, if you keep the discipline to refactor frequently.  I have a codebase that&#39;s approaching 250K LOC (that I&#39;ve never looked at) that is still workable for agents.&lt;/p&gt;
&lt;p&gt;This approach is a little outside of regular &lt;a href=&quot;https://martinfowler.com/articles/exploring-gen-ai/harness-engineering.html&quot;&gt;harness engineering&lt;/a&gt; where we&#39;d usually be trying to make sure that the LLM produces the code that we want.  The approach is after-the-fact, and can be applied to existing terrible codebases.  I think that&#39;s useful because even if all your additions to the codebase are excellent quality, the codebase can still drift into something unmaintainable.&lt;/p&gt;
&lt;p&gt;Ultimately none of this is all that scientific which irks me a bit.  I tried to ask the LLM about things that made sense and incorporate its guidance, but I think running some real evals (hitting it with a barrage of tests that try things and measure context-usage as well as results with different rules/tasks/codebase) will get more reliable results.&lt;/p&gt;
&lt;p&gt;I do plan to do that eventually and post updates.  In the meantime, I&#39;d love to hear from you about how /defrag works for you or what other strategies you think I&#39;m missing.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Context Management: Why your AI Keeps Forgetting What You Said</title>
		<link href="/posts/2026-02-12-managing-context/"/>
		<updated>2026-02-21T00:00:00Z</updated>
		<id>/posts/2026-02-12-managing-context/</id>
		<content type="html">&lt;p&gt;One of the main reasons I see people getting poor results from agentic coding is that they&#39;re not managing their context properly. They&#39;re getting results like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The AI forgets clear instructions you gave multiple times.&lt;/li&gt;
&lt;li&gt;It keeps suggesting an idea you&#39;ve rejected multiple times.&lt;/li&gt;
&lt;li&gt;It gets desperate about completing the task at hand quickly rather than doing it well.&lt;/li&gt;
&lt;li&gt;It assumes fundamental things that it should be asking about.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is context?&lt;/h2&gt;
&lt;p&gt;The &amp;quot;context&amp;quot; is the LLM&#39;s short-term memory of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;any instructions / documentation that you pre-loaded (eg claude.md, skills, agents, etc)&lt;/li&gt;
&lt;li&gt;your conversation with it&lt;/li&gt;
&lt;li&gt;what it&#39;s done / read during the conversation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By &amp;quot;managing your context&amp;quot;, I generally mean: you try to keep your context usage below ~60% where possible.  The exact number will depend on the model used, but 60% seems to be a good rule of thumb.  The poor results you get from high context usage are commonly called &amp;quot;&lt;a href=&quot;https://research.trychroma.com/context-rot&quot;&gt;context rot&lt;/a&gt;&amp;quot;.&lt;/p&gt;
&lt;h2&gt;Why do you want to keep context usage low?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;When Claude Code gets to 95% it will automatically &amp;quot;compact&amp;quot;, meaning it will automatically create a summary of the current context and restart from that.  The summary will have to remove details in order to be smaller and they may be details you care about.  This is one way the LLM &amp;quot;forgets&amp;quot; your instructions, or &amp;quot;forgets&amp;quot; that it already tried a particular solution unsuccessfully.&lt;/li&gt;
&lt;li&gt;LLMs pay more attention to the beginning and end of your context (ie the &amp;quot;&lt;a href=&quot;https://arxiv.org/abs/2307.03172&quot;&gt;lost in the middle&lt;/a&gt;&amp;quot; problem).  The bigger the middle gets, the bigger the opportunity for it to &amp;quot;forget&amp;quot; vital information in the middle.&lt;/li&gt;
&lt;li&gt;LLMs are &lt;a href=&quot;https://arxiv.org/abs/2310.13548&quot;&gt;trained to prioritize helpfulness&lt;/a&gt;, and as &lt;a href=&quot;https://arxiv.org/abs/2510.05381&quot;&gt;context degrades their reasoning&lt;/a&gt;, they seem to compensate by becoming more &amp;quot;agreeable&amp;quot;—asking fewer questions, making more assumptions, and skipping verification.  In my experience this manifests as them acting more desperate and doing dumber / more reckless things.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Tools for managing context in &lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code&quot;&gt;Claude Code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can check your context usage in Claude Code with the &lt;code&gt;/context&lt;/code&gt; command anytime to see what it currently is.  You can reset your context by clearing all memory of the current conversation with &lt;code&gt;/clear&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also try to reduce your context usage by clearing it and restarting with a summary of the current conversation with &lt;code&gt;/compact&lt;/code&gt; as well.  It&#39;s basically the same &amp;quot;compaction&amp;quot; that happens automatically when you get to 95% context usage, but you control the timing.&lt;/p&gt;
&lt;h2&gt;Tactics&lt;/h2&gt;
&lt;h3&gt;Clear aggressively&lt;/h3&gt;
&lt;p&gt;The main thing you&#39;ll want to do is to run &lt;code&gt;/clear&lt;/code&gt; as often as you can without losing valuable conversation.&lt;/p&gt;
&lt;h3&gt;Check your starting context&lt;/h3&gt;
&lt;p&gt;You also need to check what your context usage is when you first start a conversation.  You can call &lt;code&gt;/clear&lt;/code&gt; and then &lt;code&gt;/context&lt;/code&gt; immediately after to see what you&#39;re starting with.  Hopefully you haven&#39;t overburdened Claude Code with a massive amount of documentation, MCP servers, or skills that have you starting out every conversation already pretty high.  You may have thought &amp;quot;I&#39;ll give Claude all the information and power that I can to get the best results&amp;quot;, but that can often backfire.&lt;/p&gt;
&lt;h3&gt;Use sub-agents&lt;/h3&gt;
&lt;p&gt;Using &lt;a href=&quot;https://code.claude.com/docs/en/sub-agents&quot;&gt;sub-agents&lt;/a&gt; can be a help as well.  When you spawn a sub-agent, it gets its own fresh context window and reports back only its results, saving the main agent from all that context-pollution.&lt;/p&gt;
&lt;h3&gt;Manually compact&lt;/h3&gt;
&lt;p&gt;I personally like more control and transparency than &lt;code&gt;/compact&lt;/code&gt;, but I like the idea.  If I&#39;m in a long valuable conversation, I like to have it create a summary in a temporary summary.md file that I can check for completeness and accuracy.  If it looks good, I &lt;code&gt;/clear&lt;/code&gt; and have it read that file in to continue from.  This works really well if it&#39;s in the middle of long list of tasks.&lt;/p&gt;
&lt;h3&gt;Use plan mode&lt;/h3&gt;
&lt;p&gt;Use &lt;a href=&quot;https://www.anthropic.com/engineering/claude-code-best-practices&quot;&gt;plan mode&lt;/a&gt;!  It&#39;s great for conversationally iterating with Claude Code about what you want to do (both asking and answering questions, and sometimes asking &lt;em&gt;for&lt;/em&gt; questions) until you have a well-conceived plan.  Claude Code will then let you accept the plan, clear context and start execution fresh.&lt;/p&gt;
&lt;h3&gt;Set up context-tracking&lt;/h3&gt;
&lt;p&gt;Set up better context usage tracking.  In Claude Code, I set up a &lt;a href=&quot;https://code.claude.com/docs/en/statusline&quot;&gt;custom status line&lt;/a&gt; that shows me the context at all times:&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;~/.claude/statusline.sh&lt;/code&gt; that shows context % with color-coded warnings (requires &lt;code&gt;jq&lt;/code&gt; to be installed):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;PCT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$input&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.context_window.used_percentage // 0&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cut&lt;/span&gt; -d. &lt;span class=&quot;token parameter variable&quot;&gt;-f1&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$PCT&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-ge&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;70&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token entity&quot; title=&quot;\033&quot;&gt;\033&lt;/span&gt;[31m⚠️ CONTEXT &lt;span class=&quot;token variable&quot;&gt;${PCT}&lt;/span&gt;%&lt;span class=&quot;token entity&quot; title=&quot;\033&quot;&gt;\033&lt;/span&gt;[0m&quot;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Red&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$PCT&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-ge&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token entity&quot; title=&quot;\033&quot;&gt;\033&lt;/span&gt;[33mContext &lt;span class=&quot;token variable&quot;&gt;${PCT}&lt;/span&gt;%&lt;span class=&quot;token entity&quot; title=&quot;\033&quot;&gt;\033&lt;/span&gt;[0m&quot;&lt;/span&gt;     &lt;span class=&quot;token comment&quot;&gt;# Yellow&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token entity&quot; title=&quot;\033&quot;&gt;\033&lt;/span&gt;[32mContext &lt;span class=&quot;token variable&quot;&gt;${PCT}&lt;/span&gt;%&lt;span class=&quot;token entity&quot; title=&quot;\033&quot;&gt;\033&lt;/span&gt;[0m&quot;&lt;/span&gt;     &lt;span class=&quot;token comment&quot;&gt;# Green&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make it executable with &lt;code&gt;chmod +x ~/.claude/statusline.sh&lt;/code&gt;, then add this to &lt;code&gt;~/.claude/settings.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;statusLine&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.claude/statusline.sh&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Watch for symptoms&lt;/h3&gt;
&lt;p&gt;Ultimately you need to watch for symptoms: If it&#39;s doing reckless things, ignoring instructions and generally giving poor results, it&#39;s probably time for a &lt;code&gt;/compact&lt;/code&gt; or &lt;code&gt;/clear&lt;/code&gt;. Don&#39;t let yourself get stuck in a doom loop where it makes the same mistakes over and over and you keep telling it to fix the same things.&lt;/p&gt;
&lt;p&gt;Managing context is a skill. At first you&#39;ll need to consciously check your context usage and remind yourself to clear. Over time you&#39;ll start to feel when the context is getting bloated—you&#39;ll notice the quality degrading before you even look at the percentage. That&#39;s when you know you&#39;ve internalized it.&lt;/p&gt;
&lt;p&gt;The goal isn&#39;t to obsess over the number. It&#39;s to get consistently good results by giving the LLM the space it needs to think clearly.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Agentically Ambitious</title>
		<link href="/posts/2026-02-09-agentically-ambitious/"/>
		<updated>2026-02-09T00:00:00Z</updated>
		<id>/posts/2026-02-09-agentically-ambitious/</id>
		<content type="html">&lt;p&gt;One thing I&#39;ve noticed when working with others while coding with agents is that many people are still working at too low of a level by default.&lt;/p&gt;
&lt;h3&gt;Level 0: Line-by-line dictation&lt;/h3&gt;
&lt;p&gt;Obviously if you&#39;re telling it line by line what to type (and no one is -- this is a straw man), you&#39;re not getting the value out of the LLM that you could be.&lt;/p&gt;
&lt;h3&gt;Level 1: Technical solutions&lt;/h3&gt;
&lt;p&gt;The next level up is specifiying technical solutions in detail, eg &amp;quot;Create a model and a controller for retrieving rows from the widget table&amp;quot;.  This is a common level for many people that have been burnt by older less-effective models.  It&#39;s a waste because the agent knows how to build out CRUD endpoints for any web framework under the sun.  Or if it doesn&#39;t, it can just follow examples in your codebase.  It&#39;s extremely good at this now.&lt;/p&gt;
&lt;h3&gt;Level 2: System properties&lt;/h3&gt;
&lt;p&gt;An improved level that I see people default to frequently is describing properties of their system like &lt;code&gt;Create an api endpoint  GET /api/widget/234 that gets widgets&lt;/code&gt;.  This is definitely an improvement, but it&#39;s still not as high level as we can get: nothing changes in the world when this endpoint exists.  Backends need frontends to create full products.  The example I&#39;ve given here can still be absolutely crushed by the agent in most cases.  You may still be at too low of a level.&lt;/p&gt;
&lt;h3&gt;Level 3: Product-oriented&lt;/h3&gt;
&lt;p&gt;A further improvement level is when you&#39;re coding agentically across all the necessary services in a way that is user-facing or product-oriented.  eg &amp;quot;Create an orders page to show orders&amp;quot; that is run on a mono-repo or in a parent folder holding all the necessary repos.  More often you&#39;re describing real user value instead of parts of the system.&lt;/p&gt;
&lt;p&gt;It&#39;s worth noting that this is the lowest level that non-programmers will be operating at, so if non-programmers are blowing you away in productivity, now you know why.  You&#39;re being silly if you let that happen!&lt;/p&gt;
&lt;h3&gt;Level 4: Problem-first and Level 5: Exploratory&lt;/h3&gt;
&lt;p&gt;And there are more levels even further outside!  Instead of giving it a spec, you can give it a problem to solve and have it write its own spec (There are lots of tools for this like &lt;a href=&quot;https://github.com/Fission-AI/OpenSpec&quot;&gt;openspec&lt;/a&gt; or &lt;a href=&quot;https://github.com/github/spec-kit&quot;&gt;spec-kit&lt;/a&gt;).  Or instead of giving it a problem to solve, you could just ask &amp;quot;what should we do next?&amp;quot;&lt;/p&gt;
&lt;p&gt;I generally pick the highest level of abstraction that I think it can pull off.  That&#39;s going to get you the biggest bang-for-the-buck when it works.  The one where we&#39;re just supplying product specifications works extremely well today if your codebase doesn&#39;t suck.&lt;/p&gt;
&lt;p&gt;In the end, it may not always do what you want.  When it does something you don&#39;t like, you can throw it away and restart or iterate with it to where you want to go.  But these new frontier models are so much better than previous models that it&#39;s worth a shot at trying something at a higher level or even without so much detail.  And sometimes it has a better idea than the one you were going to specify which for me is just pure magic.&lt;/p&gt;
&lt;p&gt;I would strongly consider being more ambitious if you&#39;re working at one of the lower levels here.  And if it fails at a higher level, think about how you &lt;em&gt;could&lt;/em&gt; make it work (eg skills, prompts, agents, documentation, etc) if you were to give it another shot.  I realize that with previous models you needed to specify the hell out of everything, but the technology has changed considerably in the last 3-4 months.  Try dropping to a lower level only after you&#39;ve proven that the higher level won&#39;t work.&lt;/p&gt;
&lt;p&gt;I also think the exact technical details of the solution matters a lot less now that you can refactor to what you want cheaply and easily as well, whenever you want.  As long as you have the functionality, the performance, the UX, etc that you need, the exact code isn&#39;t all that important.  I know that&#39;s going to blow a lot of minds, but I do encourage you to consider it.&lt;/p&gt;
&lt;p&gt;If you&#39;re one of those people that&#39;s been using the agent for everything, but you don&#39;t feel like you&#39;re able to get the productivity gains that other people are seeing it could be that still working too far down into the details.  The more ambitious you are, the more agentic you are.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Vibe Reviewing</title>
		<link href="/posts/2026-01-26-vibe-reviewing/"/>
		<updated>2026-01-26T00:00:00Z</updated>
		<id>/posts/2026-01-26-vibe-reviewing/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https://lakshminp.substack.com/p/clean-code-is-dead-long-live-clean&quot;&gt;Steve Yegge shipped 225,000 lines of Go code he&#39;s never read.&lt;/a&gt;  I just hit 170k lines on a side project without looking at the code.  Vibe-coding is old news at this point, but what about vibe-reviewing?  And possibly more terrifying: Can we build software without reading the code at all?&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://www.simonandschuster.com/books/Vibe-Coding/Gene-Kim/9781966280026&quot;&gt;the vibe-coding book&lt;/a&gt;, Yegge describes reviewing 10,000 lines of code a day.  But he&#39;s not reading for elegance or comprehension.  He&#39;s reviewing outcomes -- test results, whether the thing works.  Code review becomes behavior review.&lt;/p&gt;
&lt;p&gt;I&#39;m exploring the same territory.&lt;/p&gt;
&lt;h2&gt;The Problem with Human Review&lt;/h2&gt;
&lt;p&gt;Sure, human code reviewers are slow and unreliable for stopping defects.  The invention of pull-requests didn&#39;t bring in an unprecedented new age of software quality.&lt;/p&gt;
&lt;p&gt;But the real problem with code review as a quality gate is that it comes at the end of the development process.&lt;/p&gt;
&lt;p&gt;Code reviews as a quality gate are a massive source of waste where we discover problems way too late, requiring fixes that are more expensive than they need to be.  My favourite &lt;a href=&quot;https://en.wikipedia.org/wiki/W._Edwards_Deming&quot;&gt;W. Edwards Deming&lt;/a&gt; quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let&#39;s make toast the American Way: I&#39;ll burn it, you scrape it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you&#39;ve ever had a PR where someone says &amp;quot;I have an idea for a better approach entirely&amp;quot;, you&#39;re scraping toast. Couldn&#39;t we instead just improve how we make things from the start and eliminate as much &amp;quot;scraping&amp;quot; as possible?&lt;/p&gt;
&lt;p&gt;Even now in the age of AI, there are a million agents to automate PRs instead of employing agents to eliminate the need for review entirely.  I&#39;ve rarely heard anyone talk about using the same agents in precommit as they do for pull requests.&lt;/p&gt;
&lt;h2&gt;We&#39;ve Done This Before&lt;/h2&gt;
&lt;p&gt;Remember when we had human QA gates before releases / deployment?  Someone had to manually approve that the software worked before it could go out.  Then we built automated tests and CI/CD pipelines and staged roll-outs and feature flags, and good observability and we managed to remove the humans from the loop.  It was hard! We thought releases were so important that only humans could approve them.  But then we figured out a better way.&lt;/p&gt;
&lt;p&gt;The same pattern can happen with code review.  We currently have human gates before code merges.  But if we can automate the review -- really automate it, not just run some linter bot that everyone ignores -- we can remove humans from that loop too.&lt;/p&gt;
&lt;p&gt;AI doesn&#39;t have to be perfect.  It just has to be better than what we&#39;re doing today.  (There&#39;s no question that it&#39;ll be faster.  Waiting for a code review has got to be in the top 3 of software development soul-crushers.)&lt;/p&gt;
&lt;h2&gt;&amp;quot;But Review is for Knowledge Sharing!&amp;quot;&lt;/h2&gt;
&lt;p&gt;Common objection: code review spreads context across the team.  Everyone learns the codebase by reviewing each other&#39;s code.&lt;/p&gt;
&lt;p&gt;But most of that context is never used.  You learn things in review that you never actually need.  And deep codebase knowledge is devalued now anyway -- AI can navigate it for you.&lt;/p&gt;
&lt;p&gt;Why learn preemptively when you can ask just-in-time?  When you actually need to understand something, ask an agent.  The context is there when you need it.  You don&#39;t have to carry it around in your head.&lt;/p&gt;
&lt;h2&gt;Fresh Eyes Without Reading&lt;/h2&gt;
&lt;p&gt;I wrote myself a couple of useful Claude skills for review of the agent&#39;s work without looking at the agent&#39;s work.&lt;/p&gt;
&lt;p&gt;The first is obviously /review .  You can jam every opinion and quality check in there that you want.  This is what you&#39;ll iterate on: every time you find an issue in a code review or a defect, consider adding the check to /review .  Soon it will have a barrage of checks in it so extensive that no human can compete.&lt;/p&gt;
&lt;p&gt;The second is /summary .  All it does is summarize the code changes.  It&#39;s useful for me to run on a clear context to see if the AI can figure out what the code is trying to do.  And so it can find things that it&#39;s doing that are not coherent with the rest of the effort.&lt;/p&gt;
&lt;p&gt;I use them both on a clear context ( /clear in claude code terminal ) so they have no hints about what to expect, and they have no biased agent (motivated to land the PR) interpreting the output.  I don&#39;t read the code, I just point a fresh agent with these skills at it and see what comes back.&lt;/p&gt;
&lt;p&gt;Lastly, things can still happen over time that make the code suck.  Files get long, functions get long, &amp;quot;single sources of truth&amp;quot; show up in multiple places.  I have a skill called /defrag that helps me find high-value refactorings.  Basically everything that improves context management and quick semantic understanding.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ensures short files/functions&lt;/li&gt;
&lt;li&gt;reduces hotspots (files that change all the time)&lt;/li&gt;
&lt;li&gt;consolidates sources of truth&lt;/li&gt;
&lt;li&gt;improves naming&lt;/li&gt;
&lt;li&gt;removes dead code&lt;/li&gt;
&lt;li&gt;adds missing tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The agents need refactoring just like we humans do if they&#39;re going to effectively and quickly navigate the codebase.  This is the primary way I keep the agent successful as the codebase gets large.  If it has to use up all its context figuring out your codebase, it will have no context left to intelligently handle your prompts.&lt;/p&gt;
&lt;p&gt;I also ended up building a PR tool for myself for handling code review without reading code:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/img/vibe-reviewing/pr-review.png&quot; alt=&quot;AI-powered PR review showing summary and code review issues&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You still need to understand the code (at this point!) but you don&#39;t need to pore through it to figure out what needs to be fixed.  AI can give you understanding at whatever resolution you need.  Maybe you don&#39;t need to read all the code.  I&#39;m at 170K lines of code in this codebase without reading any code.&lt;/p&gt;
&lt;h2&gt;Reliable Systems from Unreliable Parts&lt;/h2&gt;
&lt;p&gt;You&#39;ve probably seen some hallucinations, or just terrible results in your vibe-coding attempts.  That doesn&#39;t mean all is lost though.  Here&#39;s an analogy:&lt;/p&gt;
&lt;p&gt;TCP is a reliable protocol built on top of an unreliable one.  IP packets get lost, arrive out of order, get corrupted.  But TCP uses redundancy, acknowledgments, and retries to create reliability from unreliability.&lt;/p&gt;
&lt;p&gt;The same principle applies here.  Individual AI agents are unreliable.  They hallucinate.  They make mistakes.  They miss things.  But multiple agents, possibly from different vendors and models, tasked with bringing different perspectives -- that&#39;s how you get to a more trustworthy solution.&lt;/p&gt;
&lt;p&gt;There are &lt;a href=&quot;https://github.com/zscole/adversarial-spec&quot;&gt;consensus skills&lt;/a&gt; for Claude that do exactly this.  Multiple agents review the same thing and have to reach agreement.  If one agent hallucinates, the others catch it.  Unreliable pieces used together to create reliable systems.&lt;/p&gt;
&lt;p&gt;This is why I&#39;m not worried about AI reliability for code review.  We don&#39;t need each individual agent to be perfect.  We just need the overall system to be reliable.  And we know how to build reliable systems from unreliable parts.  We&#39;ve been doing it since TCP.  I wrote more about this in &lt;a href=&quot;/posts/2026-02-10-probabilistic-to-deterministic/&quot;&gt;Probabilistic to Deterministic&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Making It Work&lt;/h2&gt;
&lt;p&gt;A few practical things:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reviews should happen precommit.&lt;/strong&gt;  Anything the review finds should be added to Claude -- CLAUDE.md files, custom slash commands, system prompts.  If a review catches something once, your agent should ideally never make that mistake again.  Put a feedback loop on your feedback loop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Organize code for AI.&lt;/strong&gt;  Smaller files that fit in context windows.  Clear naming that makes intent obvious without needing deep context.  We used to organize code for humans.  Now we organize it for AI too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lighten up your dev environment.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well this is pretty wild: Now my IDE is code-free.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/img/vibe-reviewing/code-free-ide.png&quot; alt=&quot;Code-free IDE&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I use &lt;a href=&quot;https://zellij.dev/&quot;&gt;zellij&lt;/a&gt; to tile my windows, put claude code cli in the middle, with a few running terminals on the right.  For git I love the auto-updating views that IDEs give you, so I vibe-coded a &lt;a href=&quot;https://github.com/cainus/vigil&quot;&gt;quick terminal app&lt;/a&gt; that just gives you that view.  It took about three prompts to create and two of them were to suggest a good name.  &lt;strong&gt;But there&#39;s nothing for viewing / editing code.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I don&#39;t at all think we&#39;re living in a post-code age (yet).  But I think code reading and writing by humans might be over.  To be clear: I definitely still need to know how to do software engineering to write anything complex beyond a one-shot, but of course coding is only part of software engineering, and it turns out it&#39;s a small part.&lt;/p&gt;
&lt;p&gt;I have no idea what this means or what&#39;s next.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Reliable Org</title>
		<link href="/posts/2024-10-14-the-reliable-org/"/>
		<updated>2024-10-14T08:00:00Z</updated>
		<id>/posts/2024-10-14-the-reliable-org/</id>
		<content type="html">&lt;p&gt;My software engineering background colors my management style in many ways.&lt;/p&gt;
&lt;p&gt;Here’s an example that’s a cornerstone for my definition of good management:&lt;/p&gt;
&lt;p&gt;Most people in software know a “200 OK” is a web server response that says that the request was successful, or a 400 Bad Request error that something went wrong.  Less common is a “202 Accepted” response, but it’s worth explaining: A 202 Accepted response means “I got your request, thanks.  I’ll work on that.”&lt;/p&gt;
&lt;p&gt;An endpoint that uses 202 is one that I would call “unreliable”, and that’s generally a system property to avoid with all else equal, just like it sounds.  An endpoint like that gives you no idea if your request will ultimately work -- just that the system accepted your request. With an endpoint that returns 200 OK or an error like 404 Not Found though, you get to find out and find out right away.&lt;/p&gt;
&lt;p&gt;When talking about whether an endpoint is “reliable” or any system or component is “reliable”, people usually think it means that it’s really good or perfect at doing its job.&lt;/p&gt;
&lt;p&gt;“Reliability” from a distributed computing perspective means that there’s a way for the system to communicate failure, not that it works really well.  An endpoint that gives 202 responses would be considered unreliable even if it had a 0% failure rate over a decade.  This is a critical difference because when a component can communicate problems that it encounters, you can do things like fix the component, or retry the component, or switch to a different similar component.  That is to say you can manage the component.&lt;/p&gt;
&lt;p&gt;Often less experienced engineers think that this definition of reliability doesn’t really matter as long as the component is just perfect at its job all the time, but a more robust system can be built by understanding that perfection is impossible, and instead we should build a system of components that communicate when they fail so we can properly manage the situation when inevitable failures do occur.&lt;/p&gt;
&lt;p&gt;So what does this have to do with people management?  Well people and teams and divisions and business units are all components of the larger system of the business.  Just as reliability is critical in distributed systems, it plays an equally important role in managing teams and organizations.   What does reliability by this new definition mean for systems of people?  It means that people communicate in a way that meets our new version of reliability: they can and do tell you when things are not going well.&lt;/p&gt;
&lt;p&gt;Reliability can usually simply be built into a software system, but for humans that bring a more emotional aspect to the system, you can’t get reliability that easily.  You need to consider multiple factors to make a system of people reliable.  I’d like to chat now about the hardest one to get right and the one that most organizations lack: psychological safety.&lt;/p&gt;
&lt;p&gt;Psychological safety is when people are free to voice opinions, disagree, take risks (and fail), and make mistakes without fear of punishment or other negative consequences.  An organization that can freely say when things have gone wrong is one that can be considered reliable in the same way that technical components that communicate failure can be considered reliable.&lt;/p&gt;
&lt;p&gt;Most companies don’t care about psychological safety.  Here’s what they do instead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Look for someone to blame when things go wrong&lt;/li&gt;
&lt;li&gt;Push pressure and goals down a hierarchy away from themselves shirking responsibility&lt;/li&gt;
&lt;li&gt;Cover-up mistakes and hide failures.&lt;/li&gt;
&lt;li&gt;Pursue conservative goals instead of game-changing breakthroughs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ll give you a real world example:  A friend of mine is a head nurse at a prestigious hospital.  She discovered that another nurse had accidentally given an incorrect and dangerous medication to a patient and didn’t know if she’d be fired or reprimanded.  Of course my friend corrected the situation immediately, but things could’ve gone a different way pretty easily.  Additionally upon further investigation, the dangerous medication was stored immediately next to the correct medication and had all the same colored labels.  Management can’t reduce the instances of cases like this if they don’t know about them, or the details of their causes, and if they can’t think beyond blaming the person that gave the wrong medication.&lt;/p&gt;
&lt;p&gt;Blame makes people hide things.  People hiding things makes them unreliable.&lt;/p&gt;
&lt;p&gt;Now you can probably think of a million other examples of this in real life.  Have you ever heard of an aviation disaster where they conclude “human error”?  That’s another ridiculous example of complete lack of psychological safety.  If they stop the investigation at “human error”, and still rely on humans in the airport, air control, and on planes, then I don’t know about you, but I’m personally pretty terrified for exactly the same thing to happen again.  If they instead assume that the human did the best they could in the situation and that we should find another way to improve our chances next time, then they’re actually on a path of learning and improvement.&lt;/p&gt;
&lt;p&gt;You have to choose between the ability to blame people and the ability to learn and improve.  You can’t have both.&lt;/p&gt;
&lt;p&gt;For this reason an organization that has psychologically safety is an organization that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learns&lt;/li&gt;
&lt;li&gt;Improves&lt;/li&gt;
&lt;li&gt;Is reliable&lt;/li&gt;
&lt;li&gt;Is manageable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you see it, it’s hard to consider any other type of management as management at all.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Breaking It Down, Part IV</title>
		<link href="/posts/2022-05-23-breaking-it-down-part-4/"/>
		<updated>2022-05-23T12:07:00Z</updated>
		<id>/posts/2022-05-23-breaking-it-down-part-4/</id>
		<content type="html">&lt;p&gt;&lt;small&gt;(special thanks to Deepa Joshi for her input!)&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;This is the fourth and final part of &lt;a href=&quot;https://caines.ca/posts/2022-04-30-breaking-it-down-part-1/&quot;&gt;my series on work breakdown&lt;/a&gt; (WBD) for large software efforts.  In the &lt;a href=&quot;https://caines.ca/posts/2022-05-9-breaking-it-down-part-3/&quot;&gt;last post&lt;/a&gt; I chatted in detail about what constitutes a good piece of work in the breakdown, but in this post I&#39;d like to get more holistic and talk about what the entire WBD will look like when it&#39;s done well, and how the pieces of it should inter-relate.  This is the critical big-picture view.&lt;/p&gt;
&lt;h2&gt;Properties of a Good WBD:&lt;/h2&gt;
&lt;p&gt;A good WBD will ideally have 3 primary properties defining the relationship between the pieces:  &lt;strong&gt;mutually exclusive&lt;/strong&gt;, &lt;strong&gt;collectively exhaustive&lt;/strong&gt; and &lt;strong&gt;prioritized&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Mutually Exclusive&lt;/h3&gt;
&lt;p&gt;The pieces should ideally have no overlap of effort between them.  You haven’t really successfully broken something down if the pieces haven’t been completely separated.  Some pieces will definitely require other pieces to be completed first, but that can be done with proper sequencing and without actual overlap.&lt;/p&gt;
&lt;h3&gt;Collectively Exhaustive&lt;/h3&gt;
&lt;p&gt;The pieces should ideally comprise the entire effort and not just part of it.  It’s much more difficult to manage an incomplete WBD where we’re regularly adding more work.  Many runaway projects that I’ve seen suffer from a lack of holistic view of the entire breadth of the project.
Sometimes there are a bewildering number of unknowns, but those should be handled as early as possible with questions, experiments, prototypes, research, etc, so that the WBD converges on “collectively exhaustive” as quickly as possible.&lt;/p&gt;
&lt;h3&gt;Prioritized&lt;/h3&gt;
&lt;p&gt;Prioritization is another huge part of the breakdown process.  If we’re continuously delivering value, we want to be delivering the highest value first and then decreasing value over time.  There are different kinds of value to consider too:  derisking, dependencies, learning &amp;amp; business-value.  You also want to consider the cost of them (usually just measured in developer time, but not always).  I’m not going to get into prioritization frameworks, or tell you how to decide between the things that deliver business-value, but it is useful to talk about how to prioritize business value among the other kinds of value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;User / Business learning:&lt;/strong&gt; Probably the biggest waste in software development is building the wrong thing, so we want to prioritize this type of learning pretty highly.  Especially learning that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stops us from building the wrong thing&lt;/li&gt;
&lt;li&gt;Informs us about what we should be building&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Approach-Derisking:&lt;/strong&gt;  Assuming we’ve got high confidence in what we’re building, we next want to derisk our approach.  First we want to derisk the actual plan by figuring out whatever we need to, to ensure the work breakdown is comprehensive.  Secondly we want to do any technical research, prototypes, or experimentation that we need to do to clear up anything that’s technically complex and not straightforward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;User / Business value:&lt;/strong&gt; You want to deliver things in order of business value so you capitalize on your efforts in the most optimal way possible.  Even if you’re not delivering to production until completion of the entire effort, you still want to derisk the highest value things first by getting them as complete as possible first.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dependencies:&lt;/strong&gt; You’re basically forced to prioritize fulfilling dependencies before their dependents, but it’s helpful to make this explicitly part of your prioritization.  Otherwise there’s potential for people to not see dependencies and start work on something with unfulfilled dependencies.  They’re sure to eventually get blocked and forced to work on the dependency.  Dependencies themselves have risks as well, so it’s better to work on them first and not have them block other efforts.&lt;/p&gt;
&lt;p&gt;It’s also worth noting that the clock runs out on plans before they’re complete all the time.  Companies change priorities and cancel plans in progress.  Prioritizing like this ensures that the work that we don’t do is the lowest value work, and ensures that even if we’re interrupted, we’ve still captured as much value as possible in the time we had.  It’s also worth looking at the lower priority work early-on to see if that work can just be considered for a subsequent effort instead, or even eliminated.  Proactively removing work that doesn’t need to happen as part of this effort can have a massive positive impact on the size of the effort and the speed at which it’s delivered.&lt;/p&gt;
&lt;h2&gt;Where Possible, Begin with Deployment&lt;/h2&gt;
&lt;p&gt;Being able to build and deploy the work is table-stakes.  You can’t play the game of software delivery if you can’t build and deploy the work.  I highly recommend that the first thing that you do is to ensure deployment is possible and safe.&lt;/p&gt;
&lt;p&gt;For new software where no one is using it yet, it’s good to set up your build and deployment so that you ensure early and often that what works on your machine works equally well in your target production environment.  It takes no additional time because you have to do this eventually anyway, and you don’t want to be debugging environmental differences after you thought everything was done.&lt;/p&gt;
&lt;p&gt;For existing software, ensuring safe deployment is equally critical.  If we’re focused on continuous delivery and we’re so results-oriented that our progress is visible in production, we’re almost certainly using &lt;a href=&quot;https://martinfowler.com/articles/feature-toggles.html&quot;&gt;feature flags&lt;/a&gt; so it’s worth chatting a bit about them as part of the WBD for those that are working this way.&lt;/p&gt;
&lt;p&gt;My primary piece of advice is that you always deliver the feature flag FIRST as part of the greater effort, because that’s what enables the rest of the delivery to be both safe and continuous.&lt;/p&gt;
&lt;p&gt;Secondarily, it should reveal as small a piece of functionality as possible to be still visible.  The functionality revealed could just be a placeholder for future work (like a “hello world” message), but you do want to show that the feature flag is working end to end (be Visible!).  This proves that you will be continuously deployable as you go, and allows you to turn on the feature flag internally so everyone can test the real production progress whenever they want.&lt;/p&gt;
&lt;p&gt;I think this feature-flags-first policy is worth noting here separately because in general people naturally tend to not add the feature flag until the perceived end of an effort when they start thinking about delivering everything in totality to real users.  Adding the feature flag last means that you’re integrating your work at the very end.  That’s a completely unnecessary addition of risk.  Your internal teammates have a harder time seeing things along the way and giving feedback, and you unnecessarily delay finding out about any trickiness of adding the flag that might seriously impact your timeline.  Some feature flags are really non-trivial to add.&lt;/p&gt;
&lt;h2&gt;Continuity&lt;/h2&gt;
&lt;p&gt;Finally, I’d like to discuss how to do all this continuously.  A good WBD is the essential core of a good plan in general.  The thing to know about plans though is that they quickly drift away from being the most optimal plan as we work through them.  We learn new things.  We find out that we had some things wrong.  Circumstances change.  Plans fall apart.&lt;/p&gt;
&lt;p&gt;For these reasons my strong recommendation is that, as you go, you continue assessing your work breakdown along all the criteria written here, and improve it continuously.  You don’t want to foolishly pursue a plan that is falling apart.  You want to react to new information and keep adjusting the plan.&lt;/p&gt;
&lt;p&gt;The most common questions you’ll want to ask yourself are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do we still have a comprehensive view of the work?  Or is there more essential work that needs to be added?&lt;/li&gt;
&lt;li&gt;Are we still prioritizing properly?  Did we find new risks that we should derisk as soon as possible?&lt;/li&gt;
&lt;li&gt;Is there anything we can take out of the work breakdown and do another time instead?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, make your planning and replanning activities more continuous.  Ask yourself continuously: Is this still the best plan?  If it’s not, fix it!&lt;/p&gt;
&lt;h2&gt;In Conclusion&lt;/h2&gt;
&lt;p&gt;I know that this 4-part series about breaking large software efforts down can seem like a bunch of bureaucracy compared to immediately getting to work on writing the code, but it really is pretty critical if your software effort is large.  Sure I&#39;ve seen teams function well without this kind of rigor, but usually it&#39;s when they have work that is already naturally broken down into thin vertical slices (eg maintenance teams or growth teams).  For other types of teams that actually are delivering larger efforts, not putting the time in to get a good WBD can mean that you&#39;re working on the wrong things more often, or delivering value to users more slowly.  In the worst cases, the project can go completely off-track and be a total failure.  Not only will a good WBD help prevent these types of things, but sometimes you can even apply a good WBD to a failing project and bring it back on track.&lt;/p&gt;
&lt;p&gt;Think of it instead as a design exercise.  You want to design your work so it&#39;s the kind of work that makes you look and feel successful as you accomplish it.  It also happens to be the kind of work that will actually be successful.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Breaking It Down, Part III</title>
		<link href="/posts/2022-05-9-breaking-it-down-part-3/"/>
		<updated>2022-05-19T15:46:00Z</updated>
		<id>/posts/2022-05-9-breaking-it-down-part-3/</id>
		<content type="html">&lt;p&gt;&lt;small&gt;(special thanks to Deepa Joshi for her input!)&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;I introduced the concept of thin vertical slices for work breakdowns (WBD) in &lt;a href=&quot;https://caines.ca/posts/2022-05-9-breaking-it-down-part-2/&quot;&gt;my last post&lt;/a&gt; but the idea is by no means new, and I didn&#39;t invent it; thin vertical slices have been the state-of-the-art for work breakdown (WBD) for decades.  People often don&#39;t spend time studying the state-of-the-art though, and they&#39;re more comfortable breaking things down along more natural boundaries, so a lot of teams don&#39;t actually break things up along vertical lines.  I think ignoring this best practice either hurts or dooms a lot of larger software efforts though, so I&#39;d like to just go over the subject again here, even though this a pretty well-trodden concept.&lt;/p&gt;
&lt;h2&gt;Thin Vertical Slices&lt;/h2&gt;
&lt;p&gt;Ultimately each piece in a WBD needs to have certain properties in order to really meet our goals.  Those properties are Vertical, and Thin.  Let’s dig into them:&lt;/p&gt;
&lt;h3&gt;Vertical&lt;/h3&gt;
&lt;p&gt;Breaking things down along vertical lines where “Working software is the primary measure of progress” gets us both Visibility (true visibility!) and actual Value Delivery.  Also if we’re succeeding at visibility and value delivery regularly, we get a feeling of momentum for free, and so Motivation is easy to maintain as well.&lt;/p&gt;
&lt;p&gt;This can be hard, because it means a particular piece of work may need different developers to make sure you tackle all the necessary horizontals or components in it.  That’s fine!  Multiple people can coordinate around a single piece of work.  That’s the price we’re willing to pay to ensure &lt;a href=&quot;https://caines.ca/posts/2022-05-9-breaking-it-down-part-2/&quot;&gt;Visibility, Value Delivery, and Motivation&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Thin&lt;/h3&gt;
&lt;p&gt;Now if you manage to break everything down vertically, you can actually slice the work into ridiculously small pieces and enjoy completing things continuously all day long.  That’s really energizing and people watching the progress are generally getting a very real (and impressive) view of what’s happening and how fast things are moving.&lt;/p&gt;
&lt;p&gt;More importantly, breaking things down into smaller pieces that everyone agrees on is the best way to get everyone’s more-precise agreement on what we’re trying to do.  The more pieces there are, the less chance that there’s some large hidden detail that we disagree on.  Of course, once you get started the plan tends to fall apart a little bit (and sometimes a lot), but the discussion and documentation of the plan tends to still be valuable because it creates alignment around what you’re trying to do in increasing amounts of detail.  That alignment will be invaluable for recognizing when the plan isn’t on track and how to fix it.&lt;/p&gt;
&lt;p&gt;There is a balance to maintain as well.  It is possible to over-define a plan; if something is trivial and multiple possible solutions are roughly equivalent, planning every detail out can yield diminishing returns.  Planning itself takes time.  If your planning activities are not significantly reducing risk anymore, you can stop planning and get to work.  If you’ve ever been on a team that debates for more than 30 seconds about how to prioritize a typo fix, you know the pain of over-planning.&lt;/p&gt;
&lt;p&gt;Slicing your work into small pieces also makes it easier to estimate.  Small estimates simply have less error in them than larger estimates.  Also if your pieces are small enough, you can just count how many you tackle in a week to get a rough estimate of when you’ll be done.&lt;/p&gt;
&lt;h3&gt;Sidenote: Dealing with Uncertainty&lt;/h3&gt;
&lt;p&gt;It’s worth noting that some WBDs will be hard to do comprehensively because of unknowns.  If you break things down into small pieces, it’s likely that they drive out many pressing questions / unknowns.  It’s totally okay to create work items for experiments, prototypes, research, etc that may affect the direction of the rest of the work.  They may or may not have the same definition of done as usual production quality software because the goal is learning or derisking and not user-value.&lt;/p&gt;
&lt;p&gt;For example, if you’re not sure how much work something is, and want to choose a different solution if it’s really expensive, you might want to create a separate timeboxed piece of work solely for that investigation, eg “Hey I need 2 days to evaluate some libraries to see how hard that is”.  When the timebox expires we hopefully have an answer that we can work with, or we can decide if we should do another timebox.  A few subsequent failures of a timebox to yield our answers is itself an interesting data point -- maybe this thing is just more complex and expensive than we’re willing to take on.  Or maybe everyone agrees on more timeboxes still.&lt;/p&gt;
&lt;p&gt;In general, activities like these that make the plan clearer and help us derisk our efforts are worth doing first and in order of risk so the plan gets clear as quickly as possible and the work gets more and more straightforward.&lt;/p&gt;
&lt;h3&gt;Next Up&lt;/h3&gt;
&lt;p&gt;Alright! Now that I&#39;ve talked ad nauseum about the pieces of the WBD, it&#39;s time to talk about the properties of a good WBD as a whole.  &lt;a href=&quot;/posts/2022-05-23-breaking-it-down-part-4/&quot;&gt;The next and final part&lt;/a&gt; will get into that critical and rarely discussed aspect of WBDs.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Breaking It Down, Part II</title>
		<link href="/posts/2022-05-9-breaking-it-down-part-2/"/>
		<updated>2022-05-09T08:15:06Z</updated>
		<id>/posts/2022-05-9-breaking-it-down-part-2/</id>
		<content type="html">&lt;p&gt;&lt;small&gt;(special thanks to Deepa Joshi for her input!)&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;I &lt;a href=&quot;/posts/2022-04-30-breaking-it-down-part-1/&quot;&gt;previously explained&lt;/a&gt; why you should care about a good work breakdown (WBD), and gave some examples of common ways to do work breakdown that we should try to avoid.  None of that is much help unless you know what we’re really trying to achieve.  I’ll explain that here.&lt;/p&gt;
&lt;p&gt;The whole point of the WBD is manageability.  We break work down because a single big 3-month effort is just too difficult to manage without decomposing it and thinking of it in parts.  It’s just too much to fit inside any one person’s head at once in its entirety, so it’s easy to fail at managing the parts we overlooked or forgot.&lt;/p&gt;
&lt;p&gt;We can organize the WBD in additional ways that improve manageability as well though.  We want to make sure things stay as closely to our idea of “on-track” time-wise as possible.  When something is off-track, we want to be as obvious about that as possible as well so that we can do something about it as early as possible.  Manageability is about easily determining if our approach is working or not, and adjusting.&lt;/p&gt;
&lt;p&gt;In short, we want to ensure real progress and immediately see when we’re having difficulty progressing.  People need to know about progress in the software development process so that they can determine…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;…how to help.&lt;/li&gt;
&lt;li&gt;…what to do next.&lt;/li&gt;
&lt;li&gt;…how to set expectations and tell others.&lt;/li&gt;
&lt;li&gt;…if we’re meeting timeline expectations or not.&lt;/li&gt;
&lt;li&gt;…if an effort is stuck and might need external help or a different direction.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, there are 3 primary factors that help us ensure progress:  &lt;strong&gt;Visibility&lt;/strong&gt;, &lt;strong&gt;Value Delivery&lt;/strong&gt;, and &lt;strong&gt;Motivation&lt;/strong&gt;.  Let’s dig into these factors.&lt;/p&gt;
&lt;h2&gt;3 Factors For Ensuring Progress&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Visibility&lt;/strong&gt;:  Is what we’re trying to do obvious, concrete, well-shared, and well-understood? Can people (including us) see our progress?  Does what they see along the way accurately reflect real value being delivered?  As pieces are delivered, do we all get more confidence that we’re on the right track?  Do we have all the work enumerated so that we’re not adding more work at the last minute?  Are we managing the expectations of stakeholders?  If we get interrupted partway through, did we do the best we could have done with our time?  If we’re doing things that we don’t need to do, will other people be able to see that so that they can tell us?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Value Delivery&lt;/strong&gt;:  Are we derisking early?  Are we learning early?  Are we delivering the highest value things first?  Are we delivering the lower value things later, or successfully saying no to them?  Are we getting things to users as frequently and as soon as possible?  Are we providing maximum value at all times?  Are we learning as much as possible along the way so we can continuously improve the remaining plan?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Motivation&lt;/strong&gt;:  Are we tackling scary unknown parts quickly so they don’t hang over our heads?  Do we feel like we’re making progress and getting momentum?  Are we delivering regularly and feeling “in the flow”?  Are we reducing anxiety by making sure that there’s no point where we have to communicate a big negative surprise to stakeholders?  Are we tackling risky integrations early and frequently to avoid a bunch of rework?&lt;/p&gt;
&lt;p&gt;If we’re going to maximize these 3 factors, we need to break the work down in a particular way.&lt;/p&gt;
&lt;h2&gt;Working Software is the Primary Measure of Progress&lt;/h2&gt;
&lt;p&gt;Sure, “Working software is the primary measure of progress” is &lt;a href=&quot;https://agilemanifesto.org/principles.html&quot;&gt;the 7th principle of the Agile Manifesto&lt;/a&gt; , but here it’s worth learning and following because it gets us our goals of Visibility, Value Delivery, and Motivation so much better than anything else I’ve seen.&lt;/p&gt;
&lt;h3&gt;Why is working software the measure for “progress”?&lt;/h3&gt;
&lt;p&gt;Anyone who’s written a lot of software knows that a bunch of things can go wrong at different stages of the software development process.  Let’s talk through three of those stages:&lt;/p&gt;
&lt;h4&gt;Getting your change into main/master/trunk:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;It’s difficult to merge because of changes by others in the same files (merge debt).&lt;/li&gt;
&lt;li&gt;Fellow engineers have significant concerns about your solution/code.&lt;/li&gt;
&lt;li&gt;The people you need to review it aren’t in today.&lt;/li&gt;
&lt;li&gt;You break the build somehow.&lt;/li&gt;
&lt;li&gt;Your work doesn’t have merge conflicts, but also doesn’t fulfill a working contract with the larger system (eg “We’re done the backend.  We just have to do the frontend.”).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Showing PMs/designers/testers/stakeholders:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;We didn’t build what we thought we agreed on.&lt;/li&gt;
&lt;li&gt;We built it exactly how they asked for it, and after having seen it / used it, they realize it’s not as great of an idea as they originally thought.&lt;/li&gt;
&lt;li&gt;They find defects.&lt;/li&gt;
&lt;li&gt;The people that need to sign off on it are on vacation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Going to a Production environment:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The prod db has some data we didn’t expect.&lt;/li&gt;
&lt;li&gt;The feature doesn’t work at production scale.&lt;/li&gt;
&lt;li&gt;Users don’t like what we built.&lt;/li&gt;
&lt;li&gt;There’s a memory leak when we run it for a few hours&lt;/li&gt;
&lt;li&gt;We didn’t get the production instrumentation (logging / metrics / alerts) quite right&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are all the reasons that no one should really be all that excited when developers say “it’s done but I just have to…”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Merge it into main/master/trunk&lt;/li&gt;
&lt;li&gt;Get it code reviewed&lt;/li&gt;
&lt;li&gt;Test it / get it tested&lt;/li&gt;
&lt;li&gt;Show it to the designer / pm / tester for feedback&lt;/li&gt;
&lt;li&gt;Deploy it / release it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There’s just so much that can still go wrong that saying you’re done is incredibly misleading to yourself and to others.  Many of these things that can go wrong could even require you to have to start again entirely.&lt;/p&gt;
&lt;p&gt;This is why we say “working software is the primary measure of progress”.  If the thing is working in production, ideally in ways that are verifiable by non developers, and even more ideally in ways that end-users can verify, then we can prove to ourselves and others that we’ve passed all these stages of risk and something is actually done.  Delivering as close as possible to the real production environment also leaves very little opportunity for miscommunication about the progress; anyone should be able to go and see it for themselves.&lt;/p&gt;
&lt;p&gt;The brutal truth about software development is that until your code is actually working and in real actual use, &lt;a href=&quot;https://caines.ca/posts/2017-04-09-the-all-or-nothing-principle/&quot;&gt;you&#39;ve only really managed to cost your company time and money&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In general, you should embrace the most risk-free and comprehensive definition of done that you possibly can so that when you say “done”, it really lets others know that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You don’t need to work on it more.&lt;/li&gt;
&lt;li&gt;It’s ready for people to use.&lt;/li&gt;
&lt;li&gt;We’re achieving the results we wanted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is what everyone really needs to know.  All the previous stages still contain too much risk for you to be saying “done”.&lt;/p&gt;
&lt;p&gt;As a result, work should be broken down in ways where each piece:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;…can be validated/enjoyed by all interested humans including ones that are as close to real users as possible.&lt;/li&gt;
&lt;li&gt;…can be delivered as close to a real production environment as possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Outcomes &amp;gt; Outputs &amp;gt; Efforts&lt;/h2&gt;
&lt;p&gt;We want to be as outcome-oriented as possible, so that the progress we’re showing is as real as possible.  My shorthand for this is “Outcomes &amp;gt; Outputs &amp;gt; Efforts”, which means that while we appreciate efforts, we appreciate outputs more.  And while we appreciate outputs, we appreciate outcomes even more.&lt;/p&gt;
&lt;p&gt;We appreciate efforts like “coding” and “testing”, but not as much as we appreciate an actual output of the efforts like a shipped feature that we consider production worthy.  Similarly, we appreciate outcomes like “the users love the new features”, or “revenue is way up as a result of the features we built” or “we learned a lot from that latest experiment we shipped” even more than we appreciate the output of shipping the features.  So when we break work down, as much as possible, we want to avoid breaking pieces off that describe efforts, and ideally break pieces off that describe outcomes as much as possible.  Most times your pieces should at least describe an output.&lt;/p&gt;
&lt;p&gt;This is the reason that, for example, we generally don’t want “testing feature whatever” broken out as a separate work item from the rest of the work.  If the act of testing is extracted from the rest of the work, then the remaining work can never really meet a very meaningful or useful definition of done.  “Testing” is just an effort -- it’s very far from an actual business outcome.  It also forces the remaining work items to not include testing as well, relegating them to effort status as well.  Additionally, testing can find that the other work is broken in ways that invalidate it.  Ideally when you break work up, the pieces are maximally decoupled and can’t invalidate each other like that.&lt;/p&gt;
&lt;p&gt;Focusing less on effort and more on results is also the reason we don’t want work broken up along what we call horizontal lines.   For example, if you were to split the frontend work and backend work into separate pieces (even if the frontend work is in a different codebase, or even still if it’s worked on by different people entirely) that would mean that the separate efforts are never independently verifiable or usable by people as close to the user as possible in an environment as close to production as possible.&lt;/p&gt;
&lt;p&gt;Instead we want to slice the work in vertical pieces.  Imagine how you’d share a hamburger with someone else: you’d cut the burger vertically so they get bun, lettuce, tomato, burger, and bun again, all at once in one slice.  You would never slice horizontally and give them the top half.  Similarly, you want each piece of work to deliver a portion of the user’s experience, and not some horizontal slice like “the frontend” or “the backend”.&lt;/p&gt;
&lt;p&gt;Also notice that if our work is always broken-down along vertical lines, it’s easiest if it’s now broken-down into extremely small slices.  The thinner your vertical slices are, the easier/faster it is to get any one of them through all the risky merge/validate/release stages we talked about earlier.    Even more importantly, if something fails to get through one of those stages in a way that requires a dramatic change of plan, you learn about it as early as possible, instead of after building a bunch of software that doesn’t actually achieve the outcomes we want.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://caines.ca/posts/2022-05-9-breaking-it-down-part-3/&quot;&gt;my next post&lt;/a&gt; I&#39;ll dive a bit deeper into thin vertical slices, because they&#39;re so critical and so hard to get right.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Breaking It Down, Part I</title>
		<link href="/posts/2022-04-30-breaking-it-down-part-1/"/>
		<updated>2022-04-30T11:51:06Z</updated>
		<id>/posts/2022-04-30-breaking-it-down-part-1/</id>
		<content type="html">&lt;p&gt;&lt;small&gt;(special thanks to Deepa Joshi for her input!)&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;A critical skill for senior engineers is knowing how to break down a bunch of work into smaller, more manageable pieces.  You need to make sure you’re spending your time and effort on the right things, and that the rest of the organization is in agreement.  This isn’t always the most exciting part of software development, but I’ve seen a proper work breakdown (WBD) shave months off a project, even when done after the project is already months late.  I’ve never seen it be a waste of time, no matter how anxious people are “to get to work” (Those are semi-sarcastic quotes, because planning is part of the work of software development).&lt;/p&gt;
&lt;p&gt;Of course, the WBD is no big deal if your work is regularly simple and small and involves few people, but for anything more complex, not doing a proper WBD usually leads to lots of problems like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The larger organization feeling like it’s in the dark not knowing if the effort is on-track&lt;/li&gt;
&lt;li&gt;The developers themselves not realizing that they’re working on the wrong things (and the entire effort actually is off-track!).&lt;/li&gt;
&lt;li&gt;The project gets more off-track and there’s an increasingly difficult conversation to have with the larger organization about how the effort is failing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The WBD is critical to starting the effort on-track, keeping it on track, and even putting it back on track when it starts to seem out of control.&lt;/p&gt;
&lt;h2&gt;Bureaucracy Is A Lot More Fun Than Failing&lt;/h2&gt;
&lt;p&gt;If you’re anything like me you just want to get back to work and don’t really want to be concerned with this kind of bureaucratic bean-counting.  It’s certainly not much fun, and it can feel like a waste of time to spend so much time talking about the work instead of getting started on it.  Try to keep in mind though: wasting your time building the wrong things, getting results way slower than you could be, getting mounting pressure and criticism from an organization  -- all of those things -- are even less fun than doing a proper WBD.  A proper WBD is pure bliss compared to a large project failing.  You’ll never be a useful contributor to the management of a larger software effort unless you&#39;re willing to learn how to do it.&lt;/p&gt;
&lt;h2&gt;Your Intuition Won’t Cut It&lt;/h2&gt;
&lt;p&gt;A lot of developers have a bunch of experience doing WBDs along natural boundaries into smaller pieces and maybe have seen some success, especially on smaller projects.  If they haven’t studied what other people in the industry are doing though, they’re almost certainly not doing very effective WBDs.  Good WBDs don’t look at all like you would naturally or intuitively expect.  There are decades of prior thought on this and you’d ignore it at your folly.&lt;/p&gt;
&lt;p&gt;Here are some common methods of breaking work down that don’t work very well:&lt;/p&gt;
&lt;h3&gt;Splitting Along Architectural Lines&lt;/h3&gt;
&lt;p&gt;It’s important to not confuse a work breakdown with an architectural design.  You might have various architectural components involved in a larger effort you’re undertaking.  They could be standard architectural components like model/view/controller or just frontend/backend or multiple services in a more service-oriented or microservice architecture.  It’s absolutely worth a good chat about the architecture, and it’s worth doing an architecture breakdown with diagrams and written plans.  I would keep this very light in the beginning and define it as you go, but it’s definitely worth doing.&lt;/p&gt;
&lt;p&gt;Don’t confuse this with a WBD though!&lt;/p&gt;
&lt;p&gt;A WBD is intended to be something that makes sense to non-engineers with the ability to make progress visible.  Most architectural components make no sense to non-engineers, and deliver nothing on their own to users.  You actually can’t even honestly say to yourself that an architectural component is done with certainty unless it’s integrated and in use by its collaborating components.  Instead we want to drive uncertainty like that out as early as possible.&lt;/p&gt;
&lt;h3&gt;The Smallest Pieces Possible&lt;/h3&gt;
&lt;p&gt;In interviews when I ask Senior Engineering candidates how to break work down, the most common answer I get is “as small as possible”.  This is a nice answer insofar as it’s obvious that they do value breaking down larger pieces of work in general (rather than a single 3 month task!), but probably the smallest possible breakdown is character by character of the source code.  I’m certain that no one actually means that.&lt;/p&gt;
&lt;p&gt;If you’re doing the smallest pieces possible, very few of those pieces will deliver anything to users at all, or result in any learning for the company.  You can work for weeks without contributing to progress visibility or value delivery.  Of course we want to divide-and-conquer the larger effort, but we’ve got to be more thoughtful than just saying “the smallest pieces possible”.&lt;/p&gt;
&lt;p&gt;Instead, we want the smallest pieces possible that still make our progress obvious (ideally even delivering actual business value).  If you break things down further than that, you run the risk of showing false progress, and introducing many new kinds of risks.&lt;/p&gt;
&lt;h3&gt;Work that can be assigned to individuals&lt;/h3&gt;
&lt;p&gt;The next most common way of breaking work down seems to be for the purpose of assignment to different people on the team.  This is where you get tickets for the frontend devs and tickets for the backend devs, or one ticket for the devs and one ticket for the tester.&lt;/p&gt;
&lt;p&gt;This can be a nice clear way of showing who is working on what, but it actually hurts both visibility and value delivery.  You get people saying “it’s done but it just needs to be tested”, or “the backend is done but we still need to build the frontend”.  These are weak definitions of “done” where we can’t deliver anything to users, and we’ve learned nothing in production.  Saying “done” in these cases is a bit of a smoke screen to stakeholders; the testers could reveal bugs that require more work, and the frontend devs could uncover missing functionality on the backend.  Without them being in a production environment with real users you still won’t know about the defects that the testers missed, or whether your backend can handle the load.  Telling the stakeholders that something is done in any of these cases won’t really be 100% true and so at best won’t be as transparent/visible as you could be.  Sometimes I’ve seen people showing a frontend on its own and that can be downright deceptive to non-technical folks that don’t realize how much work there is involved in making the backend (which is sometimes the majority of the work).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; Unfortunately most ticketing systems only let you assign a piece of work to a single person, but you shouldn’t let the tool get in the way of you doing the right thing and having multiple people (where useful) working on the same ticket when it’s the most visible way to work and gets you actual value delivery.  You can easily chat informally (off the ticketing system) as a group about who does what if you want to take different portions of the ticket individually.  If you need to put a single name and face on a ticket, choose a leader for it and assign it to them.&lt;/p&gt;
&lt;h2&gt;The Cliffhanger&lt;/h2&gt;
&lt;p&gt;Ultimately a good WBD should put the focus on real accomplishments as much as possible instead of efforts, and put the focus on what the team is doing, rather than what individuals are doing.  How do you do that?  I’ll tackle that in &lt;a href=&quot;/posts/2022-05-9-breaking-it-down-part-2/&quot;&gt;my next post&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Hey that seems longer than 2 weeks</title>
		<link href="/posts/2022-04-28-hey-that-seems-longer-than-two-weeks/"/>
		<updated>2022-04-28T11:50:06Z</updated>
		<id>/posts/2022-04-28-hey-that-seems-longer-than-two-weeks/</id>
		<content type="html">&lt;p&gt;I’ve stumbled upon a style of estimation that I’ve seen be pretty successful.  I’ll call it “2W+ Estimation”.  &lt;a href=&quot;https://caines.ca/posts/2017-10-21-working-without-estimates/&quot;&gt;I&#39;ve mentioned it before&lt;/a&gt;, but without much detail.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There are two possible estimates given for any work that the team is about to take on: “more than 2 weeks” and “less than 2 weeks”.&lt;/li&gt;
&lt;li&gt;An estimate is not provided at all if the work seems like less than 2 weeks.  It is assumed to be less than 2 weeks.  We only mention an estimate if we want to note that something seems longer than 2 weeks.&lt;/li&gt;
&lt;li&gt;When something is bigger than 2 weeks of effort, we try to think of ways to change the scope to something deliverable in less than two weeks while accomplishing the same goals.  Sometimes we talk about whether the high cost means it should be prioritized lower.  Sometimes we agree it’s worth doing now anyway.  Sometimes we break it down into valuable deliverable pieces, where each is smaller than 2 weeks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s worth noting that there are 2 critical steps that we undertake afterward for any effort large or small: (1) break it down into thin vertical slices (2) check every day to make sure things are still tracking how we’d expect.  Bigger-sized projects tend to be riskier and go off the rails more often.  If one seems off the rails we might have to restart this process and reassess the remaining effort.&lt;/p&gt;
&lt;h3&gt;What’s so great about this estimation style?&lt;/h3&gt;
&lt;p&gt;It’s almost as fast as not estimating at all, but forces good conversations in higher risk scenarios.&lt;/p&gt;
&lt;p&gt;It uses time not complexity (like story points) because (1) everybody already knows and understands time and (2) complexity is not any easier to estimate.&lt;/p&gt;
&lt;p&gt;No overly precise estimates are ever given, so the estimates can’t be converted to precise calendar expectations.  We don’t like the effects on our codebase or people of them being rushed with arbitrary deadlines.&lt;/p&gt;
&lt;h3&gt;Why 2 weeks?&lt;/h3&gt;
&lt;p&gt;I imagine a different time frame could work better in different scenarios.  I even imagine a smaller time frame could work better for us.&lt;/p&gt;
&lt;h3&gt;How did we develop this?&lt;/h3&gt;
&lt;p&gt;We started by not estimating, and then smart people who found that too risky would pipe up pretty regularly and say “hey you know that’s pretty big right?”.  “Pretty big” seemed to be generally agreed to be “greater than 2 weeks”.&lt;/p&gt;
&lt;h3&gt;Who might this not work well for?&lt;/h3&gt;
&lt;p&gt;Well you probably already know if you’re at the kind of company that would even be willing to try this.  A lot of companies think spending more time on estimation gets better estimates, and that more precise estimates are worthwhile.  We don’t, but different companies value different things and sometimes those values have good reasons.&lt;/p&gt;
&lt;p&gt;The team needs to be willing and able to speak up when something is large because there’s no other mechanism than that kind of proactive candor.&lt;/p&gt;
&lt;p&gt;This may not work for a team that does sprints where you&#39;re trying to pack as much work into a given timeframe as reasonable, especially if those sprints less than or equal to 2 weeks.  We find sprints to be really weird, so we don&#39;t do them.  T-Shirt sizes might be better for those kinds of teams, or something even more precise.&lt;/p&gt;
&lt;p&gt;You still need to break stuff down well and reassess progress daily.  But everyone should be doing that regardless of estimation technique.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Sometimes TDD</title>
		<link href="/posts/2022-01-19-sometimes-tdd/"/>
		<updated>2022-01-19T11:50:06Z</updated>
		<id>/posts/2022-01-19-sometimes-tdd/</id>
		<content type="html">&lt;p&gt;It can sometimes feel like TDD is pretty dead in 2022.  I’m not sure what happened, because I think it’s a genius way to work, but most programmers I talk to seem to think that it’s a waste of time.  We don’t really have to be dogmatic about it though.  It’s not equally valuable at all times, and there are even rare times when a total kool-aid drinker like me doesn’t do it.  This post is meant to chat about the extremely high-value times.&lt;/p&gt;
&lt;h2&gt;For defects&lt;/h2&gt;
&lt;p&gt;I work with a lot of people that almost never do TDD but a few seem to pull it out a lot when they’re fixing defects.  It makes a lot of sense.  When you’ve got a defect, you’ve first got to make sure you know how to reproduce it.  If you write that code to reproduce it first, you’re 90% of the way to doing TDD.  Add an assertion to validate that your app code does the right thing, and then fix your app code to pass the test.  This really makes you feel like you’re making your code bulletproof and you won’t have to hear about this particular defect again.&lt;/p&gt;
&lt;h2&gt;For a complicated problem&lt;/h2&gt;
&lt;p&gt;I’ve had a few examples of complicated problems that would have been almost impossible (for me) to solve without TDD.  I once wrote a &lt;a href=&quot;https://github.com/cainus/Prozess&quot;&gt;kafka broker for node.js&lt;/a&gt; that ended up being the only Kafka broker in node.js at the time, used by a few big-named companies.  The protocol was all binary and I worked from the protocol documentation to write tests first, and then the code to pass the test.  I had my test environment hooked up to a real kafka server so that when a test passed, I knew it really worked.  I slowly worked my way through the protocol documentation this way until it was done and working.  I did a ton of refactoring along the way and a ton of refactoring afterward as well, and the tests gave me confidence in my changes and a very tight feedback loop.  Whenever I can tell that something is going to get really complicated, I switch gears to slow, methodical TDD.&lt;/p&gt;
&lt;h2&gt;For something that requires more “architecture” than usual&lt;/h2&gt;
&lt;p&gt;There are a lot of people that I’m not going to sell with this point, but it’s been the biggest thing for me with TDD.  If you’re working on a codebase that’s going to grow larger and larger over time and be worked on by many people, you need to think about the internal organization of that codebase (“architecture”) if you want to keep it from quickly becoming a big ball of spaghetti.  Not only do you need to think about architecture, but you also need to think about the testability of that architecture regardless of whether you write the tests first or after.  Driving out architectural pieces using TDD ensures that things are factored and working together in a way that is testable.  In this way the last D in TDD is more like “Design” than “Development” because the tests have you architecting the codebase differently.  Some will argue that it’s not the beautiful design that they would like, but I’ve often found that the factorings are quite elegant and that testability is more important than beauty anyway.  In my experience, when you’ve architected like this, you can bring on the hordes of test-later programmers pretty successfully and get great tests and great coverage.  In my experience, a codebase is testable much more easily if it’s TDD-able.&lt;/p&gt;
&lt;h2&gt;For something that’s untestable&lt;/h2&gt;
&lt;p&gt;If you’ve got something that’s untestable or hard to test and you’re struggling to get tests on it, it can feel like it would be even harder if you had to write the tests first.  In general I find the opposite is paradoxically true, and this is another case where the last D in TDD is more about “Design”.  Forget about that working code that you wrote and just try to write a small test like how you wish a test of it could look in the simplest human-readable way.  Now see if you can write code that can pass it, ignoring your previous app code.  Concentrating on the test first drives out a testable design and I believe you’ll almost always like the factoring as well.  Sometimes the test is the hardest part, so starting with it can be the best way to make sure you nail it.&lt;/p&gt;
&lt;p&gt;Anyway, these are just my opinions after a decade of TDD and working with many others that seem to only use it occasionally.  I still think TDD does a better job of getting tests and well-factored code in 99% of scenarios, but these 4 are the truly magical scenarios for me.  My advice is to give TDD a chance in these cases if you’ve given up on TDD entirely or if you never saw the point.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Block-Testing</title>
		<link href="/posts/2020-11-01-block-testing/"/>
		<updated>2020-11-02T02:45:14Z</updated>
		<id>/posts/2020-11-01-block-testing/</id>
		<content type="html">&lt;p&gt;How you do QA is probably terrible.&lt;/p&gt;
&lt;p&gt;Of course I don’t know you, but most software development shops that I’ve worked on or chatted with “do QA” in a way that is pretty terrible.&lt;/p&gt;
&lt;p&gt;Almost everyone does it, and almost everyone considers it a “best practice”, and yet somehow it never even got a name.  I’m going to call it “block-testing” because it’s the kind of testing that unfortunately makes continuous deployment and continuous delivery fundamentally impossible.&lt;/p&gt;
&lt;h3&gt;So what is it already?!?!&lt;/h3&gt;
&lt;p&gt;It’s the practice of having humans try to regression-test an entire product or some high-value subset of features across the entire product usually with the goal of finding reasons to stop it from being released.  The most extreme (worst) case of this being when a specific role exists solely for this purpose (almost always given the misnomer “QA”).&lt;/p&gt;
&lt;p&gt;Just to be super-duper clear: I’m aware that almost everyone is doing block-testing.  That doesn’t mean it’s a good fit for every organization though.  If you actually want to achieve continuous deployment or continuous delivery, this is one of the big-batch operations that you’ll need to forego.&lt;/p&gt;
&lt;h3&gt;What’s so bad about it?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A single manual run-through of a broad test script is slow (compared to existing automation)&lt;/li&gt;
&lt;li&gt;It’s expensive (compared to good automation, over the long-term)&lt;/li&gt;
&lt;li&gt;It frequently misses all but the most egregious regressions (more often than alternatives)&lt;/li&gt;
&lt;li&gt;It’s antagonistic, pitting different roles at the company against each other.&lt;/li&gt;
&lt;li&gt;It confuses where the responsibility for quality lies&lt;/li&gt;
&lt;li&gt;There are many other possible solutions to the same problem, many of which are faster and more comprehensive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alright a couple of those things are obvious to most people I think so let’s just dig into a couple of the less obvious ones:&lt;/p&gt;
&lt;h4&gt;It’s antagonistic&lt;/h4&gt;
&lt;p&gt;Hiring people whose sole purpose is to find reasons to stop a release is counter to the goals of a company that is trying to release software quickly.  Of course block-testers are actually tasked with the important goal of making sure each release is high-quality (and that’s a critical goal!), but the end result is that as block-testers, they naturally tend to optimize their role to “trying to find release-blockers”.  They’ll log other defects too of course, but those don’t have the same importance to them (or anyone else) as issues that block releases.&lt;/p&gt;
&lt;p&gt;Also when you’ve got one group of people responsible for finding fault in another group’s work, you’re going to have conflict between the groups.  Engineers are going to start saying that the bug isn’t theirs or the bug isn’t “that bad”.  Testers are going to say the opposite.  Each group is going to blame the other when management wonders why releases are delayed or infrequent.  You’ll get the same finger-pointing when a defect gets through to production as well.  The ensuing arguments are a massive waste of time and each “side” becomes less empathetic to the other’s plight over time.&lt;/p&gt;
&lt;h4&gt;It Confuses where the Responsibility for Quality Lies&lt;/h4&gt;
&lt;p&gt;I’ve heard the words “You’re the tester! Test it!” a few times in my career.  The sentiment is that development and testing are distinct phases rather than something that happens iteratively during development, and “the developers do the developing and the testers do the testing”.  “This frees developers up to just focus on just development”.&lt;/p&gt;
&lt;p&gt;Nothing really could be further from the truth and I have some serious doubts about the experience of any developer that thinks that they shouldn’t be testing their own work along the way as if they can hammer out 15 or more LoC and won’t have to bother to try and see if it works.  The fact of the matter is that quality is entirely the responsibility of the developer and any successful developer is testing constantly as they go.  Conversely, the tester’s only role is to assess the quality.  The tester has no responsibility whatsoever to improve it.&lt;/p&gt;
&lt;p&gt;At the same time, the very presence of the tester is a very confusing signal.  It signals that the developers aren’t wholly responsible for quality (and maybe even that they’re not trusted with it!).  It diminishes their &lt;a href=&quot;https://en.wikipedia.org/wiki/Skin_in_the_game_(phrase)&quot;&gt;skin in the game&lt;/a&gt;, and disincentives quality.  Of course a tester-only role has no ability to actually fix defects, and you can’t sanely hold someone responsible for something they have no control over.&lt;/p&gt;
&lt;p&gt;I would wager that this division of responsibility is the single greatest cost of block-testing.  The testers and the developers start to engage in a kind of game of ping-pong where the developer tries to see what they can get past the tester, and the tester tries to find ways to block the release for any reason at all.  I’ve seen a feature go back and forth from developer to tester more than a half-dozen times before the tester agrees that it’s okay to release.  That back-and-forth often plays out over days through an issue tracker for trivially-fixed-but-important issues in high value features.  If you’re looking closely for this kind of activity you can see it all over the place, and it can look about as effective as a football team that uses telegrams to communicate mid-play.  These hand-offs are all classic waste from a &lt;a href=&quot;https://dzone.com/articles/waste-4-handoffs&quot;&gt;Lean perspective&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are many other possible solutions to ensuring quality, many of which are faster and more comprehensive.&lt;/p&gt;
&lt;p&gt;Once you realize the harm, the cost, and the inadequacy of block-testing, you naturally have to ask, “but is there anything better?”.  You can’t really fault an organization for block-testing if there are no alternatives.&lt;/p&gt;
&lt;h3&gt;Let’s chat about some alternatives:&lt;/h3&gt;
&lt;h4&gt;Move Fast and Avoid False Dichotomies&lt;/h4&gt;
&lt;p&gt;It’s really unfortunate that the industry has resolved itself to the belief that you have to either go slow or you’ll break things, and that quality and speed are an inevitable and universal trade-off.  This is a really limiting belief.&lt;/p&gt;
&lt;p&gt;In order to get creative, let’s forget the “best practices” for a minute and get back to first-principles:  Here’s what we’re trying to do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We want to minimize users’ exposure to defects and outages.&lt;/li&gt;
&lt;li&gt;We want to minimize the time spent between a developer completing a change on their workstation and it getting to users to keep delivery radically fast.&lt;/li&gt;
&lt;li&gt;We want to catch more issues than a human can.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Preventative Measures&lt;/h4&gt;
&lt;p&gt;Preventative measures are anything that you might do to prevent a defect from affecting a user.  They’re a pretty critical part of achieving goal A.&lt;/p&gt;
&lt;p&gt;However, goal B means we really have to be careful what steps we put between the developer and the production environment.  Ideally they’re critically important and they’re fast.  Each of these steps has to pay for themselves.  Because of this, you have to be &lt;em&gt;really&lt;/em&gt; careful about what preventative measures you choose.  Some really fast preventative measures: static-typing, automated tests, broken-link-checking spiders, linters.&lt;/p&gt;
&lt;h4&gt;Mitigating Measures&lt;/h4&gt;
&lt;p&gt;You also have to start thinking about how to achieve Goal A with more than just preventative measures.  Preventative measures aren’t everything.  Even the most ardent block-testers have non-preventative measures:  feedback from the end-user (even if it goes through 5 levels of support first).  I’ll call these post-deployment measures “mitigating measures”.  There are 3 main categories for the types of mitigation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reducing the severity of a defect (# of users, impact per user, etc)&lt;/li&gt;
&lt;li&gt;Finding defects faster&lt;/li&gt;
&lt;li&gt;Fixing defects faster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hopefully those categories get your imagination started.  User feedback is a mitigation measure; it’s just the slowest and most expensive one.  Here are a few that do better:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fast automated deployment.  If you can’t get a fix out quickly, more users will be affected for longer than necessary.&lt;/li&gt;
&lt;li&gt;Telemetry: logging, metrics, and alerts.  Instrument your codebase in as many ways as possible to make it self-report issues it might be having.  Alerts will tell you when things are going wrong faster than user-feedback and often you’ll learn about things that humans (manual testers or even end-users) did not, or even could not find.&lt;/li&gt;
&lt;li&gt;One-click rollback.  Make it so that your production environment can be rolled back to the previous known-good deployment as quickly and easily as possible.&lt;/li&gt;
&lt;li&gt;Staged roll-out.  Coupled with great telemetry, a gradual deployment process allows you to halt deployment and roll-back (even automatically) if there is a spike in crashes or logged errors before something is fully deployed.&lt;/li&gt;
&lt;li&gt;Feature flags / Feature toggles / kill switches.  Control (post-deployment) what users get what features and when.  If there are any problems, only the allowed users are impacted, and the broken functionality is quickly reverted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, you will probably want to do these things even if you never eliminate block-testing from your release process.  The prevailing practice seems to be to forego these things and expect the human block-tester will catch everything though.  That’s a kind of bury-your-head-in-the-sand quality management.&lt;/p&gt;
&lt;p&gt;If you try these things out though, you’re almost certainly going to see that these practices are cheaper, faster, and more effective than block-testers though.&lt;/p&gt;
&lt;h4&gt;“But Automation is Expensive!”&lt;/h4&gt;
&lt;p&gt;Automation IS expensive!  I have no argument against that.  It is.  I’ve seen numerous well-covered codebases have more test code than application code, so the upfront costs of automated tests are probably close to the same as writing the application code itself.&lt;/p&gt;
&lt;p&gt;Over the long haul it pays for itself though.  A well-covered codebase easily has thousands of tests each getting run thousands of times a year, so we’re talking about millions of behaviour verifications on the conservative end of things.  Humans simply cannot compete with that.  Humans are slow, and even the best of them are terrible at repetitive detail-oriented tasks.  As expensive as automation is, block-testers are even more expensive.&lt;/p&gt;
&lt;h4&gt;“But developers are terrible at testing!”&lt;/h4&gt;
&lt;p&gt;They’re really not.  Many haven’t had much practice because they’re working in block-testing environments where the responsibility is muddled, but they’re actually quite good at it with a little practice when they have the full responsibility and trust for it.  Don’t be surprised when they don’t choose manual-testing for the solution to every quality problem though.&lt;/p&gt;
&lt;h4&gt;“Do we fire our QA?”&lt;/h4&gt;
&lt;p&gt;Block-testing is so common in the industry that many people have a really hard time understanding the place of specific testing personnel in the SDLC without it. There&#39;s absolutely a place for specific testing personnel, but they&#39;ve got to start contributing to improving quality beyond block-testing, and that change is understandably difficult.&lt;/p&gt;
&lt;p&gt;Compared to computers, humans really are slow and terrible at repetitive detail-oriented tasks.  However humans have well-known strengths that computers do not:  they’re creative and curious.&lt;/p&gt;
&lt;p&gt;So there are still places for manual testing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Post-deployment exploratory testing.  This is a great match for curious humans, and doesn’t slow delivery.&lt;/li&gt;
&lt;li&gt;Feature-by-feature for new features only, with the developers present and actively involved, before code-complete of that feature.  It’s probably best if the tester doesn’t actually do the tests themselves at all, but instead talks the developer through what tests to perform.  This hands-on approach improves the developer’s testing ability more permanently and doesn’t confuse the fact that the developers own quality.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that said, I’ve been working with multiple teams for the better part of a decade that have no manual tester role at all.  When they do test manually, the developers are testing things themselves, often as a group (mob testing!).  You’ll probably want to at least consider eliminating the role of manual testing entirely.&lt;/p&gt;
&lt;p&gt;There’s still a place for quality-minded people other than manual testing though.  In fact, the concept of QA and block-testing are really opposites.  Actual quality assurance is about making sure that quality is baked into the &lt;em&gt;process&lt;/em&gt; from beginning to end.  Personnel that just do block-testing are not doing that at all.  At best they’re quality control (QC) and that’s a far less valuable role.  QA would be involved in a bunch of completely different concerns: How can we prevent defects from ever existing?  How can we find them faster?  How can we mitigate their impact?  How can we recover from them faster?&lt;/p&gt;
&lt;p&gt;Here’s a laundry list of possible Quality Assurance tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run &lt;a href=&quot;/posts/2015-03-08-reclaiming-value-from-bugs-and-outages/&quot;&gt;learning post mortems&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;measure quality in many different ways (defect rate, MTTR, MTBF, etc).&lt;/li&gt;
&lt;li&gt;regularly visit production logs and metrics to look for live quality issues&lt;/li&gt;
&lt;li&gt;coach devs on how to more aggressively test their work&lt;/li&gt;
&lt;li&gt;get into test automation&lt;/li&gt;
&lt;li&gt;liaise with users and customer support about quality issues&lt;/li&gt;
&lt;li&gt;help establish quality criteria for a task before it gets started, and throughout its development&lt;/li&gt;
&lt;li&gt;Look for patterns in defects&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;“Does it really never make sense?”&lt;/h4&gt;
&lt;p&gt;The economics of block-testing make more sense if you anticipate very few releases with increasingly smaller differences.  Agencies write this kind of software, but I haven’t personally done this kind of work in over a decade so I could be convinced of the economics either way by someone with more recent and extensive experience .  Here I’m specifically talking about teams working on a software product that exists over a long period of time.&lt;/p&gt;
&lt;h4&gt;“But my situation is different because…”&lt;/h4&gt;
&lt;p&gt;Okay!  I believe you!  There are rarely one-size-fits-all practices in software development.  I’m simply submitting this counter-argument for consideration.  I’ve certainly worked at and heard from many organizations that should strongly consider stopping block-testing because the value proposition for them is just not there.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Downward Spiral of Test-Later Automated Testing</title>
		<link href="/posts/2020-07-25-the-downward-spiral-of-test-later-automated-testing/"/>
		<updated>2020-07-25T15:29:55Z</updated>
		<id>/posts/2020-07-25-the-downward-spiral-of-test-later-automated-testing/</id>
		<content type="html">&lt;p&gt;I’ve seen this pattern a number of times in my years as a software developer, and it’s always hard to watch:&lt;/p&gt;
&lt;h3&gt;(1) “We don’t need automated tests on this stuff.  It’s way too simple.”&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;( The codebase grows until it’s more and more out of control.  We’re getting scared to make changes and manual testing is taking forever. )&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;(2) “It turns out that we need tests, but this stuff isn’t very testable, so the most focused tests we can write are integration or e2e tests.”&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;( Test suite starts off well, but quickly becomes very slow and very flakey.  When tests fail, it takes a lot of debugging to figure out why.  They also require all kinds of complicated setup making them too hard to write.)&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;(3) “Automated testing is really expensive compared to the benefit!  We’re probably not going to bother to write tests for simple things.”&lt;/h3&gt;
&lt;p&gt;It’s obvious why this pattern keeps occurring:  Every next step makes sense given the current state.&lt;/p&gt;
&lt;p&gt;It’s hard to break out of the cycle too, because it’s self-reinforcing.  Working around the damage seems to create more damage.  The things that seem like obvious solutions from an “in the spiral” point-of-view only make the problem worse.&lt;/p&gt;
&lt;p&gt;Undoing the damage takes a lot of expertise and investment.  But most importantly it’s expensive as hell the longer it goes on.  You waste time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;avoiding necessary changes/improvements that are too scary&lt;/li&gt;
&lt;li&gt;writing hard-to-write tests&lt;/li&gt;
&lt;li&gt;debugging huge sweeping e2e tests&lt;/li&gt;
&lt;li&gt;maintaining overly complex code (“You shouldn’t have to change the code just to test it!”)&lt;/li&gt;
&lt;li&gt;doing more manual testing&lt;/li&gt;
&lt;li&gt;rerunning flakey tests&lt;/li&gt;
&lt;li&gt;investigating more obscure testing tools and strategies&lt;/li&gt;
&lt;li&gt;waiting for test runs to finish&lt;/li&gt;
&lt;li&gt;waiting for releases to be approved by humans&lt;/li&gt;
&lt;li&gt;dealing with defects in areas “that aren’t worth the effort to test” or are “too simple to test”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Over the long run, cutting quality measures almost always costs you more than you gain.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Trap of Solution-First Thinking</title>
		<link href="/posts/2019-02-24-the-trap-of-solution-first-thinking/"/>
		<updated>2019-02-24T16:34:04Z</updated>
		<id>/posts/2019-02-24-the-trap-of-solution-first-thinking/</id>
		<content type="html">&lt;p&gt;I think that the most important thing I&#39;ve learned while trying to improve my abilities as an organizational change agent (read: a programmer that likes to get his way), is to never ever present some idea as a best practice. If you don&#39;t know the reasoning well enough to explain it with that reasoning alone, you don&#39;t understand the problem or the practice well enough to suggest it.&lt;/p&gt;
&lt;h2&gt;Escaping Solution-first Thinking&lt;/h2&gt;
&lt;p&gt;One of the most powerful techniques you can use for convincing people is to stop coming to them with improvement ideas when the problems they solve aren&#39;t already obvious to them. I&#39;ve been on both sides of these kinds of attempts to convince people and they rarely work. When I&#39;m on the receiving end and I hear &amp;quot;Hey Gregg, I think we should do X&amp;quot;, I immediately need to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;What&#39;s the problem you&#39;re trying to solve?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Why are you prioritizing that problem ahead of our other problems?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What other solutions did you consider for solving that problem?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What are the pros and cons of each possible solution?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What made you consider this solution to be the best of all them &lt;em&gt;for your situation&lt;/em&gt;?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first question is the foundation of it all though: &lt;strong&gt;What&#39;s the problem you&#39;re trying to solve?&lt;/strong&gt; When I&#39;m thinking of suggesting a practice and I can&#39;t immediately and clearly answer that, I know I&#39;m stuck in solution-first thinking. No one will be convinced by someone with that approach except the very few that happen to share your biases. I generally drop any idea like that entirely at that point instead of inventing an after-the-fact rationale. If my idea wasn&#39;t conceived &amp;quot;problem-first&amp;quot;, it&#39;s not coming from the right place.&lt;/p&gt;
&lt;p&gt;(I once had a junior engineer bravely ask &amp;quot;Why do we use version control?&amp;quot;. I had been using version control for almost 2 decades and still really needed to force myself through those 5 questions. It was illuminating for both of us.)&lt;/p&gt;
&lt;h2&gt;&amp;quot;Best Practices&amp;quot; imply a Fixed Mindset&lt;/h2&gt;
&lt;p&gt;Is your best practice really &amp;quot;best&amp;quot;? Will there never be a better one? Did you give your team a chance to find their own solution that is better for their particular situation?&lt;/p&gt;
&lt;p&gt;In general if you think you&#39;ve found a best practice, you&#39;re probably not going to look for one that&#39;s better. You&#39;ll be standing in the way of your team improving and in fact the craft of software development improving as a whole. You&#39;ll be the last to adopt a better a practice if someone presents one.&lt;/p&gt;
&lt;p&gt;What you call a &amp;quot;best practice&amp;quot; today came from an open-minded team that decided they wanted to try for something better than the current state of practice. It didn&#39;t come from a team that was happy with the status quo.&lt;/p&gt;
&lt;h2&gt;There&#39;s Value in Emulation&lt;/h2&gt;
&lt;p&gt;With all of that said, for things that are inconsequential, just using a &amp;quot;best practice&amp;quot; is often the smartest thing you can do. One real-life example for me was when some engineers on my team decided to use http&#39;s DELETE method to update a record in a new way after already using PUT for the usual scenario. They tried it locally and it worked. Why they didn&#39;t simply just use a POST to a new url was beyond me, but the reinvention of that proverbial wheel came back to bite us when our reverse proxy didn&#39;t allow bodies on DELETE requests. The lesson here is that if there&#39;s a standard way to do something and you&#39;re working in an area that doesn&#39;t really matter to your team/company, I&#39;d always recommend just using the standard way. Sometimes you do just need a proverbial wheel and there&#39;s no reason to reinvent it.&lt;/p&gt;
&lt;p&gt;Emulating others is a necessary step in learning too. If you&#39;re used to looking at practices used elsewhere and considering reapplying what has worked, definitely keep doing that. You should always keep learning about practices used elsewhere and it would be wasteful to always be reinventing the wheel by working only from first principles.&lt;/p&gt;
&lt;p&gt;What I&#39;m saying though is that for practices that really matter to your team, the next level is to additionally take the time to deeply understand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What problem is being solved by that practice&lt;/li&gt;
&lt;li&gt;At least a few other possible solutions&lt;/li&gt;
&lt;li&gt;The downsides of that practice (there are almost always downsides)&lt;/li&gt;
&lt;li&gt;If the practice is still the best one amoung all the others &lt;em&gt;for your situation&lt;/em&gt;, and why&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Being rigourous in your understanding of a practice and its rationale ensures that you don&#39;t apply the practice unnecessarily, or to the wrong problem, or incorrectly. Without this, you&#39;re just emulating a mature team and not actually maturing; you&#39;re cargo-culting.&lt;/p&gt;
&lt;h2&gt;Proxy Goals as Best Practices&lt;/h2&gt;
&lt;p&gt;The anti-pattern of &amp;quot;best practices&amp;quot; promotion includes arguing for hand-wavey proxy goals too. I&#39;m talking about reasoning like &amp;quot;Let&#39;s do X because X is...&amp;quot;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RESTful&lt;/li&gt;
&lt;li&gt;functional&lt;/li&gt;
&lt;li&gt;object-oriented&lt;/li&gt;
&lt;li&gt;what Linus Torvalds does&lt;/li&gt;
&lt;li&gt;what I did before on my previous team&lt;/li&gt;
&lt;li&gt;DRY&lt;/li&gt;
&lt;li&gt;Agile&lt;/li&gt;
&lt;li&gt;Lean&lt;/li&gt;
&lt;li&gt;trending on hacker news&lt;/li&gt;
&lt;li&gt;what jira expects us to do&lt;/li&gt;
&lt;li&gt;what github expects us to do&lt;/li&gt;
&lt;li&gt;what the scrum guide expects us to do&lt;/li&gt;
&lt;li&gt;what facebook/spotify/[insert famous company here] does&lt;/li&gt;
&lt;li&gt;what a great blog post I just read says to do (I&#39;m pretending there&#39;s no irony here)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may think some or all of these are great proxy goals to pursue (and maybe some are) but I personally think a few of them are terrible proxy goals for almost any situation and I can gaurantee that other people do too (some of which are probably on your team). Ultimately there are two problems with arguing for proxy goals:&lt;/p&gt;
&lt;p&gt;(1) Proxy goals can become misaligned with your actual goals.
(2) When you&#39;re trying to convince someone, you very rarely will know if they are aligned with your proxy goals. They&#39;re much more likely to be aligned with the team&#39;s or the company&#39;s actual goals though.&lt;/p&gt;
&lt;p&gt;I&#39;ve seen examples of all of these types of arguments for proxy goals (and made a couple of them myself) and though they can feel like shortcuts to a convincing argument, they really just make your job as a convincer much harder. First you have to convince somebody that Agile, for example, is a good goal, and then you have to convince them that your solution is indeed the most Agile. Usually they&#39;re just trying to get work done, so these unnecessary leaps of logic are extremely taxing on them. You&#39;re not going to win the hearts and minds this way. I&#39;ve been through a few Agile transformations now, and the only successful one was the one where I never used the word &amp;quot;Agile&amp;quot; (It turns out that in general, jargon alienates people! Who would have thought?). Suggest real solutions to real problems in plain English and people will get behind you.&lt;/p&gt;
&lt;h2&gt;Results are what matter&lt;/h2&gt;
&lt;p&gt;Certainly your customer and/or the company&#39;s stakeholders generally won&#39;t care about what you think is a best practice if it&#39;s not obviously changing actual results. I&#39;ve personally seen attempts at many of those indirect goals I listed be both successful to one team&#39;s goals and detrimental to another&#39;s. When they&#39;re detrimental, you&#39;ve blown all your social capital for future influence, so it&#39;s important to get them right. And any practice is hard to get right if you don&#39;t understand why.&lt;/p&gt;
&lt;p&gt;Throwing out your &amp;quot;best practice&amp;quot; mindset and stopping solution-first thinking forces you to be working on solving actual problems. Solving actual problems gives you a lot of clout within your organization, and allows you to more easily push for more ideas in the future.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A Javascript to Typescript Conversion Case Study</title>
		<link href="/posts/2018-12-11-a-javascript-to-typescript-conversion-case-study/"/>
		<updated>2018-12-11T15:01:43Z</updated>
		<id>/posts/2018-12-11-a-javascript-to-typescript-conversion-case-study/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Evergreen Update ( 2022-01-35 ):&lt;/strong&gt;  After some time working with Typescript, I&#39;m actually completely sold on its
usefulness and value, which I certainly was not at the time of this writing.  I was surprised that none of the usual
explanations seemed really true, eg it didn&#39;t reduce the number of tests or types of test that I wrote at all.  What
it did do though is it greatly sped up my feedback loop: (1) Things that I used to run tests for (even subsecond tests)
were instead immediately apparent right in the IDE.  (2) Things that I used to read tests for (like method signatures
and object shapes) were instead immediately apparent right in the IDE.  I wouldn&#39;t say my quality improved, or that my
teams can manage larger codebases;  I&#39;d just say that we&#39;re all faster now at doing the same things.  Also, I&#39;m pretty
sure that if you&#39;re not doing heavy automated testing, none of this will ring true for you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;And now for the original post:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;I&#39;m part of a team that&#39;s just finishing up a Javascript-to-Typescript conversion of an approximately 60 K LOC (lines of code) Javascript web service (resulting in about 86 K LOC of Typescript), so I wanted to throw some anecdata at the conversation around the costs and benefits of static-typing.&lt;/p&gt;
&lt;h2&gt;A few caveats worth mentioning right away:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;We continued adding features while converting.&lt;/li&gt;
&lt;li&gt;We spent a bunch of time additionally working on making the service&#39;s input types definable in Typescript with runtime validation (we convert typescript to json-schema during the compile step).  This expanded the effort significantly, but it also allowed us to trust that type safety would hold at run-time.&lt;/li&gt;
&lt;li&gt;We additionally converted from Promises to async/await as we went.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Alright, Let&#39;s do some math&lt;/h2&gt;
&lt;p&gt;In calendar time the conversion took about a year, but I estimate the actual developer effort was about 6 engineer-months. ++&lt;/p&gt;
&lt;p&gt;85,000 LOC over 6 developer-months is around 14K LOC per month, or 475 LOC per day.  From a naive line-by-line viewpoint that rate could seem slow, but there were many things that are easy in Javascript that are just infeasible in Typescript and had to be reworked entirely. +++  We also spent a chunk of time improving performance of compilation.&lt;/p&gt;
&lt;p&gt;While I&#39;m giving LOC stats, it&#39;s going to be worth noting that this codebase additionally has ~100K LOC worth of tests (that we left in Javascript), giving us a little over 80% coverage.&lt;/p&gt;
&lt;h2&gt;The Importance of our Test Suite&lt;/h2&gt;
&lt;p&gt;During the conversion, we found surprisingly few defects in the existing code.  It was common for a single developer to be working on conversion full time and not find any defects at all in a week.&lt;/p&gt;
&lt;p&gt;I probably converted over 10% of the code myself and never personally ran up against any defect that was user-facing.  We ultimately did find a handful of user-facing defects in the pre-conversion code though (maybe 5?) and most had to do with the  input validation not being strict enough.  Typescript was useful for helping us find those cases in a way that tests probably wouldn&#39;t be (It&#39;s rare for our automated tests to be testing bad input extensively).&lt;/p&gt;
&lt;p&gt;The conversion process did in fact introduce test breakages quite regularly though (that would have been bugs).  We used the &amp;quot;noImplicitAny&amp;quot; compiler flag to help us enforce using types everywhere.  At the file-level, this is an all-or-nothing conversion strategy, so on a large or complicated file, conversion could take hours before you could run the tests again, and continually I was finding that even with a successful build, the tests would fail in dozens of different unexpected ways, all indicating new defects.&lt;/p&gt;
&lt;p&gt;Let me repeat that for emphasis: the act of changing existing working code to add types introduced defects that only the tests caught.  This probably happened in more than half the files that I converted.&lt;/p&gt;
&lt;p&gt;Conversely, what we&#39;ve accomplished with tests (and no type-checking) on this codebase over the last 5 years is pretty mind-boggling to me.  We converted:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From callbacks to promises&lt;/li&gt;
&lt;li&gt;From express 2.0 to express 3.0 to koa.&lt;/li&gt;
&lt;li&gt;From mongodb to Amazon Aurora for core data.&lt;/li&gt;
&lt;li&gt;From coffeescript to javascript&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And throughout each of these conversions, we deployed multiple times per day.  None of the conversions were &amp;quot;big bang&amp;quot;.&lt;/p&gt;
&lt;h2&gt;What I like (because I like Typescript):&lt;/h2&gt;
&lt;p&gt;Well I&#39;m using VS Code now, instead of just vim, as one does when switching to Typescript.  It&#39;s more sluggish of course, but it comes with better in-editor support for Typescript and that means that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I can see a bunch of potential defects in-editor without running the tests at all.  That&#39;s fast feedback.&lt;/li&gt;
&lt;li&gt;Autocomplete is a lot smarter than what I&#39;ve seen in any vim plugins.&lt;/li&gt;
&lt;li&gt;Documentation about different function interfaces or object shapes is available right in the editor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last one is really key for me and ties into a larger improvement than just those in the IDE.  Typescript encourages us toward standardizing object &amp;quot;shapes&amp;quot;.  With Typescript interfaces, we can say things like &amp;quot;Alright a &#39;user&#39; will always look like this.  It will always have these fields.&amp;quot;  If some other representation has less fields, or more fields, and we really need that, we&#39;ll have to face the pressure of adding an additional type.  That&#39;s pretty powerful and I really appreciate it.  Before, just reading application code, I&#39;d have to consult tests to see exactly what shapes and interfaces were supported or returned and there was no pressure to simplify and consolidate on just one shape.  That hurts learnability and maintainability.&lt;/p&gt;
&lt;p&gt;There are of course a bunch of places where defining types is a productivity drag.  It&#39;s certainly more code to write and more code to read, and for certain types of work, it can amount to just noise.  When writing new code though, I do really appreciate how easily I can call on file-external classes/methods/functions/properties without having to jump around from file-to-file and figure out the proper way to do that.&lt;/p&gt;
&lt;h2&gt;Static Types and Quality&lt;/h2&gt;
&lt;p&gt;It&#39;s pretty clear to me that we&#39;re not really catching many more defects with Typescript compared to the effort that we&#39;ve put into it.&lt;/p&gt;
&lt;p&gt;We&#39;re catching defects faster though with faster feedback, right?  Well I don&#39;t know about that either.  We definitely are for certain classes of bugs.  If a function that adds 1 and 1 together returns the string &amp;quot;2&amp;quot;, that will get caught much faster.  There are definitely lots of typos and misspellings that are caught more quickly too.  I&#39;m enjoying that immensely and it&#39;s a real productivity boost.&lt;/p&gt;
&lt;p&gt;It&#39;s not free though.  Compile time is around 40 seconds for me (and worse for others).  So if I want to actually test runtime behaviour I&#39;d say I&#39;m now at a disadvantage.  Firing the server up and manually testing locally now takes almost a minute when it used to take less than 10 seconds.  Even with incremental compilation and a warmed cache, there’s a ~10 second compile time, which makes doing TDD (my usual way of writing code) a lot slower because of the slower feedback cycle.  So, many types of defects are faster to detect, but many types are also slower.++++&lt;/p&gt;
&lt;p&gt;But I don&#39;t have to write as many tests, right?  I have no idea why anyone would think static-typing replaces certain kinds of tests.  I was never testing types.  Does anyone ever do that?  I still write exactly the same number and types of tests.  Testing hasn&#39;t changed a bit.&lt;/p&gt;
&lt;p&gt;If it sounds like you&#39;re working in a scenario that is close to ours (a multi-year SaaS product), my recommendation is that if you have to choose between static-typing and tests, choose tests.  To forego tests in this type of codebase is not only lazy but lazy in a way that actually leads to more work.  It&#39;s hard to watch developers avoid the tiny upfront investment of tests when I can see what it&#39;s given us over the lifetime of this codebase.&lt;/p&gt;
&lt;p&gt;You don&#39;t have to choose either, so if you&#39;re sure you want a statically-typed codebase, feel free to do that too.  Typescript is not going to be a silver bullet though.  The if-it-compiles-it-works approach is a recipe for long-term pain.&lt;/p&gt;
&lt;p&gt;Additionally, if you don&#39;t have tests and you want to do a conversion from Javascript to Typescript on a large codebase, I&#39;m fairly certain that you will go much slower than we did, and you will have a tonne of bugs.  Of course our conversion is just one data-point, so your mileage may vary.&lt;/p&gt;
&lt;p&gt;
&lt;br /&gt;
&lt;sup&gt;&lt;b&gt;endnotes&lt;/b&gt;&lt;/sup&gt;&lt;br /&gt;
&lt;sup&gt;+ ...so it&#39;s not strictly true that 60 K LOC of Javascript converts to 85 K LOC of Typescript.  I&#39;m sure there are better sources of information for how many LOC conversion adds. &lt;/sup&gt;&lt;br /&gt;
&lt;sup&gt; ++ I&#39;m pretty confident in that estimate because around 80% of the conversion was done by one engineer fully tasked with the effort. &lt;/sup&gt;&lt;br /&gt;
&lt;sup&gt; +++ eg Most middleware stacks in node.js web frameworks rely heavily on monkey-patching which does not easily translate to Typescript.  Also we were doing a bunch of sequential mutations of objects in Javascript that are really tedious to simply translate to Typescript because of the necessary proliferation of types. &lt;/sup&gt;&lt;br /&gt;
&lt;sup&gt; ++++ I can&#39;t really totally blame Typescript for this.  Our Typescript-to-JsonSchema converter is included in this compile stage, and it takes a significant chunk of the time.  We really want to ensure that type-safety holds at run-time as well though.  Additionally, I do think we should be relying on incremental compilation (with a watcher) more.  It&#39;s possible with more effort we can fix most of the delay. &lt;/sup&gt;&lt;br /&gt;
&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Dynamic-Typing for Static-Typists</title>
		<link href="/posts/2018-11-05-dynamic-typing-for-static-typists/"/>
		<updated>2018-11-05T17:54:37Z</updated>
		<id>/posts/2018-11-05-dynamic-typing-for-static-typists/</id>
		<content type="html">&lt;p&gt;I&#39;ve always worked most heavily with dynamically-typed languages. They&#39;re a great choice for me and the teams that I&#39;ve worked on because of the kinds of work that we&#39;re doing. It&#39;s pretty normal though for these teams to add team-members that are completely unaccustomed to working with dynamically-typed languages because they come from backgrounds where they worked mainly in statically-typed languages.&lt;/p&gt;
&lt;p&gt;There are a few things about working with dynamically-typed languages that generally seem to blow the minds of new-comers that are accustomed to statically-typed languages, and I&#39;ll talk about a bunch of those things here. There&#39;s a huge amount of hype these days around type-systems too, and so I&#39;d like to dispel any connotations that they&#39;re necessary in &lt;em&gt;all&lt;/em&gt; cases, or that they&#39;re sufficient in &lt;em&gt;any&lt;/em&gt; situation.&lt;/p&gt;
&lt;h2&gt;Get a Linter&lt;/h2&gt;
&lt;p&gt;Just because you&#39;re disconnected from static types, doesn&#39;t mean there aren&#39;t static analysis tools. Every dynamic language I know has a linter that can be integrated with most common editors or IDEs, and the linters are quite good at telling you in real-time about a bunch of common typos and mistakes you can be making. Make them part of your CI build too, instead of the compile step you&#39;re used to in order to keep them out of your codebase.&lt;/p&gt;
&lt;h2&gt;Write a Tonne of Tests&lt;/h2&gt;
&lt;p&gt;I know a bunch of people in statically-typed languages already write a tonne of tests, but if you&#39;re one of those ones that thinks that the static type-checker negates the needs for tests, you&#39;re reeeeeeeeally going to have to get over that and start writing some tests if you&#39;re going to be successful with dynamically-typed languages (and it&#39;d almost certainly improve your statically-typed codebases as well).&lt;/p&gt;
&lt;p&gt;It&#39;s pretty normal to write more test code than application code in dynamically-typed systems. There are no quality efforts that I&#39;ve ever seen that have a higher pay-off than an extensive test suite though.&lt;/p&gt;
&lt;p&gt;I&#39;ve sometimes heard the argument that static-typing can mitigate the need for a whole tonne of test-writing but I&#39;ve never found this to be remotely true. If you&#39;re testing output types and not the actual output values, you&#39;re doing it wrong. Just test the values; it&#39;s much easier and much more valuable.&lt;/p&gt;
&lt;p&gt;I&#39;ll be brutally honest with you: If you find yourself on your first project that uses a dynamically-typed language and it doesn&#39;t have an extensive test-suite, you&#39;re almost certainly in for a very rough time as the codebase or the team gets larger. I generally have the same opinion about statically-typed codebases as well though.&lt;/p&gt;
&lt;h2&gt;Don&#39;t try to validate types at runtime on every internal method or function.&lt;/h2&gt;
&lt;p&gt;Of course you need runtime &amp;quot;type&amp;quot; validations. Just like in statically-typed codebases, you still need to verify user input, or that your data sources or 3rd-party services are giving you data in the format that you expect. You should absolutely do these validations that I&#39;m going to call &amp;quot;edge validations&amp;quot; because they&#39;re on the boundary between your application and the outside world.&lt;/p&gt;
&lt;p&gt;With that said, there&#39;s usually no good reason to sprinkle input-type validations on every internal function and method to try to replicate what you&#39;ve had in the past with a statically-typed codebase. I agree that it&#39;s nice to assure quality internally (and I heavily use micro-tests for that), but 90% of the time a function will throw appropriately when it gets an argument type that it doesn&#39;t expect as soon as it tries to use it. Dynamically-typed languages employ &lt;a href=&quot;https://en.wikipedia.org/wiki/Duck_typing&quot;&gt;Duck-typing&lt;/a&gt;, so that problems with input arguments are detected when and only when a function or method tries to interact with the argument in a way that&#39;s not expected. It happens at runtime, and the stack comes from somewhere deeper in function, but it&#39;s generally got all the information you need to debug it. Of course on its own debugging a problem like this would be much easier in a statically-typed language, but you&#39;ve got a huge suite of tests not only to mitigate the problem of run-time-only detection but also to add validation of the actual &lt;em&gt;values&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;And with &lt;em&gt;that&lt;/em&gt; said, I&#39;ll still sometimes (though very seldomly) add some assertions at the top of a function or method to ensure that the input arguments are valid. Often it&#39;s to check things about the input that most type-systems aren&#39;t much help with either, eg: &amp;quot;Is the number a &lt;em&gt;positive&lt;/em&gt; one?&amp;quot; &amp;quot;Does the string start with &#39;http://&#39;?&amp;quot;. etc, etc.&lt;/p&gt;
&lt;h2&gt;Use the tests as (one form) of documentation&lt;/h2&gt;
&lt;p&gt;I&#39;ve always loved the way that statically-typed systems enforce a certain type of code documentation. The type annotations make it easier for me to understand how to consume the functions and methods in the codebase and also what to expect inside the function or method if I&#39;m making internal changes. The great thing about the type annotations too is that they&#39;re gauranteed by the type-checker to be correct whereas regular old source-code comments seem to always quickly go out of date (not that you shouldn&#39;t still try to use comments appropriately).&lt;/p&gt;
&lt;p&gt;I&#39;m probably going to sound like a broken record here, but again the extensive test suite can be quite useful for this. A test shows you how to call those functions and methods and what they&#39;ll return. I often find the tests more valuable than types too when I have both because the tests will show me argument and return &lt;em&gt;values&lt;/em&gt; and not just the types (ie, It&#39;s more valuable to know that &lt;code&gt;add1(1)&lt;/code&gt; returns &lt;code&gt;2&lt;/code&gt; and not just a number type.)&lt;/p&gt;
&lt;p&gt;Microtesting is specifically useful here too, because if you only do large black-box-style tests, your tests won&#39;t be very useful for internal documentation. It&#39;s also important to organize your tests in such a way that the relevant ones are very easy to find. For a microtest suite, you&#39;ll probably want to mirror your application file structure as much as possible. I&#39;ll certainly admit that statically-typed application code is better at putting that documentation right in your face as you&#39;re reading source code and that&#39;s really powerful, so at least try to make sure relevant tests are as easy to find as possible. (I haven&#39;t got any experience with &lt;a href=&quot;https://en.wikipedia.org/wiki/Doctest&quot;&gt;Python&#39;s doctest&lt;/a&gt;, but it sure looks cool too.)&lt;/p&gt;
&lt;p&gt;But most of all, when looking for valuable sources of code documentation, get used to considering tests and try to read them when you have questions.&lt;/p&gt;
&lt;h2&gt;Get the Right Attitude&lt;/h2&gt;
&lt;p&gt;Sometimes the most important thing that&#39;s required is an attitude adjustment. You&#39;re working with a different programming paradigm; you&#39;re going to have to do some things differently.&lt;/p&gt;
&lt;p&gt;The fact of the matter is that static types are not necessary to...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;...build certain types of software, and in some cases they&#39;re even a poor choice.&lt;/li&gt;
&lt;li&gt;...avoid defects; they&#39;re just one possible tool, and not always the best one. (Try more automated testing!)&lt;/li&gt;
&lt;li&gt;...build large systems or work with a large team. There are in fact many large successful companies built largely on dynamically-typed languages, and there are many large open-source software projects that build on dynamically-typed languages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These dynamic languages have accomplished a hell of a lot in computing. You shouldn&#39;t need much more evidence than that.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Effective Technical Improvement</title>
		<link href="/posts/2018-10-14-effective-technical-improvement/"/>
		<updated>2018-10-14T20:23:13Z</updated>
		<id>/posts/2018-10-14-effective-technical-improvement/</id>
		<content type="html">&lt;p&gt;One of my favourite ways to tackle tech debt is to fix it as I work through product requirements. There are some great advantages to it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It automatically prioritizes tech debt burndown in areas that you’re probably going to touch again soon, which is where it’s most valuable.&lt;/li&gt;
&lt;li&gt;It doesn’t require blocking any product development flow. It just slows it down (probably imperceptibly).&lt;/li&gt;
&lt;li&gt;It doesn’t even require conversations outside of engineering.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;d hazard to say this is probably considered a best-practice, so people making technical improvements this way are in good company. I call this &amp;quot;the organic method&amp;quot; because improvements are happening naturally, or &amp;quot;organically&amp;quot; as other changes occur.&lt;/p&gt;
&lt;p&gt;There are some downsides though (especially with large codebases with many affected developers):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It hides the actual cost. Is it really better for product development to be imperceptibly slower? Wouldn’t it be nicer if costs were more explicit and obvious?&lt;/li&gt;
&lt;li&gt;It’s a lot easier to do tech improvement and product development separately. Doing two things at once is almost always more complicated.&lt;/li&gt;
&lt;li&gt;It’s easier to find patterns, better solutions and shortcuts for even fairly mechanical technical improvement work if you’re focusing only on that technical improvement work for some period of time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Usually the biggest downside is that it’s slower.&lt;/p&gt;
&lt;p&gt;In practice, I always find that it’s much much slower than you’d think. Here&#39;s a graph of a Javascript to Typescript conversion effort that I&#39;ve been tracking for the past 11 months:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/organicTechDebtBurnDown-600w.webp 600w, /images/organicTechDebtBurnDown-900w.webp 900w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;/images/organicTechDebtBurnDown-600w.jpeg 600w, /images/organicTechDebtBurnDown-900w.jpeg 900w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;organic tech debt burn down&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/organicTechDebtBurnDown-600w.jpeg&quot; width=&quot;900&quot; height=&quot;309&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;There are 2 small steep declines here that show the efforts of single individuals for short periods of time, but otherwise this graph (spanning almost a year) is a 64-file improvement out of 223 files in 11 months. At that rate, the effort will take 3.5 years.&lt;/p&gt;
&lt;p&gt;I&#39;ve tracked a number of similar efforts over the last year and the results are similar. My previous experience with organic improvement in large codebases feels pretty similar too: Without specific mechanisms to keep the conversion going, it naturally slows (or worse, stops).&lt;/p&gt;
&lt;h2&gt;Why does it matter if it’s slower?&lt;/h2&gt;
&lt;p&gt;Maintaining the incomplete state of the conversion is sneakily expensive:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&#39;s harder for newcomers to learn the right patterns when multiple exist&lt;/li&gt;
&lt;li&gt;Engineers need to remember all the ongoing efforts that are underway and always be vigilant in their work and in their code reviews of others work&lt;/li&gt;
&lt;li&gt;Diffs are easier to understand when they don’t try to do too many things at once&lt;/li&gt;
&lt;li&gt;Copy/pasta programming, forgetfulness, and uneducated newcomers lead to contagiousness; propagation of the wrong pattern instead of the right pattern&lt;/li&gt;
&lt;li&gt;When you’re really slow, you’re even more likely to have multiple of these efforts underway at once, compounding the complexity of fixing them&lt;/li&gt;
&lt;li&gt;If you’re slow enough and not actually doing cost-benefit analysis, patterns can be found that are “even better” than the ones underway. This is how you end up with even more ways to do the same thing and a smaller number of engineers that find joy in working in that codebase.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most importantly though, if there’s really value in paying for that technical improvement, why not pay it sooner rather than later? Ironically, most of the least productive (and least fun) codebases I’ve seen are because of people making numerous actual improvements but then leaving them only partially applied. Good intentions without successful follow-through can easily make the code worse.&lt;/p&gt;
&lt;p&gt;For larger technical improvements (ones that affect too many files to pull off in a week or less) you want to make sure that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have a vague idea of the cost and you’re actually making an improvement that you think will be worth the cost.&lt;/li&gt;
&lt;li&gt;The timing for doing it now is right (and there isn’t something higher value you could do instead)&lt;/li&gt;
&lt;li&gt;You actually have a plan that converges on total conversion in a reasonable amount of time instead of something that just leaves the codebase in an inconsistent state for an extended period of time.&lt;/li&gt;
&lt;li&gt;The goal, the timing and the plan are generally approved by your teammates (even if unanimity is impossible)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you&#39;ve got those 4 factors in place, you&#39;re probably better off in the long run if you capitalize on the improvement as quickly as possible. You probably don&#39;t want to cease all product development for a huge amount of time to do it, or &lt;a href=&quot;/posts/2018-09-20-no-heroes-in-tech-debt/&quot;&gt;send one developer hero off to fix it all&lt;/a&gt;, but you&#39;ll probably want to come up with something better than organic improvement too, if you really care about that improvement.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Cross-functionality is a Secret Weapon for Product Development Teams</title>
		<link href="/posts/2018-10-03-cross-functionality-is-a-secret-weapon-for-product-development-teams/"/>
		<updated>2018-10-03T22:14:59Z</updated>
		<id>/posts/2018-10-03-cross-functionality-is-a-secret-weapon-for-product-development-teams/</id>
		<content type="html">&lt;p&gt;In my experience, cross-functional teams align people to business goals best, and so they can get to real results much faster and much easier than teams made up of a single function. They really don&#39;t seem to be that popular, so I thought I&#39;d talk about them a bit.&lt;/p&gt;
&lt;p&gt;Here&#39;s some common chatter across mono-functional teams:&lt;/p&gt;
&lt;h3&gt;The Engineering team:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;We should never be taking on tech debt. Tech debt slows us down!&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;We should stop everything and clean up all our tech debt, regardless of cost or current business goals&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;We should convert all our code to use this new framework everywhere because it has [INSERT TODAY&#39;S LATEST DEVELOPMENT FAD]&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;It&#39;s the testers&#39; job to test, not mine&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;Works on my machine!&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;Let ops know that I used the latest version of the database client library, so they&#39;ll have to upgrade all the databases&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Testing team:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;Let me see if I can find a reason to stop this release&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;We need X more days to test before the release&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Frontend/Mobile/Ios/Android team:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;That bug is on the backend.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Backend Team&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;That bug is on the frontend.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Operations Team&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;We haven&#39;t got time to do the release today. Let&#39;s schedule something for early next week.&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;Engineering doesn&#39;t need access to that. Just tell us what you need.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Design Team&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;We don&#39;t want to help with a quick and dirty design for that feature experiment. It doesn&#39;t fit into our vision&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;We&#39;ve got the new total redesign for this month specced out.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Product Management Team&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;That technical debt burndown can wait, right?&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;We should do this the fastest way possible.&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;Here are the detailed specs of what I want you to build. Don&#39;t worry about what problem we&#39;re trying to solve.&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;I&#39;ve finally finished our detailed roadmap for the year.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Do you see the patterns?&lt;/h2&gt;
&lt;p&gt;These teams...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;optimize for the areas of their specialization, not for the business&#39; goals or for other teams&#39; goals.&lt;/li&gt;
&lt;li&gt;defend their area of specialization by hoarding power and information&lt;/li&gt;
&lt;li&gt;constantly try to expand their area of specialization at the expense of the business&#39; goals&lt;/li&gt;
&lt;li&gt;focus more on looking busy than getting real business results&lt;/li&gt;
&lt;li&gt;push blame to others&lt;/li&gt;
&lt;li&gt;too willingly take on expensive projects where others pay the majority of the costs or where the value isn&#39;t aligned with company goals.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;So what to do instead?&lt;/h2&gt;
&lt;p&gt;Well you get these mono-functional teams because someone talking about a specialty or discipline once said something like &amp;quot;X is important. We should have a team for X.&amp;quot;&lt;/p&gt;
&lt;p&gt;My suggestion instead is simply to start saying &amp;quot;X is important. We should have X on every team.&amp;quot;&lt;/p&gt;
&lt;p&gt;This leads to a team with a bunch of different but cooperating specialties. The only thing they all have in common is their team&#39;s portion of the business&#39; goals.&lt;/p&gt;
&lt;p&gt;Think of it this way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the members of a team don&#39;t share their goals can they really even be called a team?&lt;/li&gt;
&lt;li&gt;Why would you give goals to a team without also empowering them with all the specialist skillsets and ability to also deliver on those goals?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general I&#39;ve found that only a cross-functional team can make the proper trade-offs on its own, react quickly to changes in the world, and execute with minimal communication overhead. Once it has all the specialties it needs to autonomously deliver on its goals, you&#39;re set up for a whole new level of speed of execution.&lt;/p&gt;
&lt;p&gt;I&#39;m not saying that cross-functional teams solve all the issues above, but they make the conversations happen on-team where it&#39;s much cheaper than across teams, and the conversations are much easier because people don&#39;t have to guess each other&#39;s motives nearly as much.&lt;/p&gt;
&lt;p&gt;It&#39;s not any easy transition either if you&#39;re currently on mono-functional teams. In my experience though, cross-functional teams can really make mono-functional teams look like like a morass of endless disagreements and easily avoidable meetings.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>No Heroes in Tech Debt</title>
		<link href="/posts/2018-09-20-no-heroes-in-tech-debt/"/>
		<updated>2018-09-20T13:04:35Z</updated>
		<id>/posts/2018-09-20-no-heroes-in-tech-debt/</id>
		<content type="html">&lt;p&gt;Too often when I see a team trying to replace a bad/old/deprecated pattern that is widespread in a codebase, they default to what I call &lt;strong&gt;The Hero Solution&lt;/strong&gt;: One person on the team goes through and fixes every case of it themselves.&lt;/p&gt;
&lt;p&gt;This can work for very small efforts, but it&#39;s almost always a terrible solution in larger efforts for a few reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When the bad pattern is widespread this is the slowest way to fix it and the slowest way to get to value from the new pattern.&lt;/li&gt;
&lt;li&gt;There&#39;s nothing in this policy that stops other people from continuing to add the bad pattern. Indeed there will often be code with the bad pattern that they want to copy/paste/modify, making the bad pattern almost contagious.&lt;/li&gt;
&lt;li&gt;Teammates may be working in the same areas of the codebase causing merge conflicts that slow both the teammate and the hero down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are a few tips that will see better results:&lt;/p&gt;
&lt;h2&gt;Track the bad pattern&lt;/h2&gt;
&lt;p&gt;Find a way to track instances of that bad pattern over time. Often a simple &lt;code&gt;git grep &amp;quot;whatever&amp;quot; | wc -l&lt;/code&gt; will tell you how many cases of it you have in the codebase. Check often and record the values. Whatever your strategy is, if it&#39;s not trending toward 0 in a reasonable timeframe, your strategy is not good enough. Come up with something else.&lt;/p&gt;
&lt;p&gt;I can&#39;t tell you how many cases I&#39;ve seen of efforts trending toward multiple years (sometimes as much as 10 years) as soon as I started measuring over time, determining the rate of change, and extrapolating the completion date.&lt;/p&gt;
&lt;p&gt;If you do nothing else, do this. You&#39;ll quickly be able to see the cost (in time) and be able to reassess the value propsition.&lt;/p&gt;
&lt;h2&gt;Stop the spreading!&lt;/h2&gt;
&lt;p&gt;Agree with the team on a policy that no new instances of the bad pattern will be added without a team-wide discussion. Add pre-commit hooks that look for new cases (&lt;code&gt;git grep&lt;/code&gt; is awesome again) and reject the commit. Look for new cases in Pull Requests. Get creative! Without this, you&#39;re basically bailing a leaking boat without patching the leak and you will have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;People that want to copy/paste/modify some existing code that has the bad pattern&lt;/li&gt;
&lt;li&gt;People that don&#39;t even know the pattern is now considered bad&lt;/li&gt;
&lt;li&gt;People that knowingly implement the bad pattern because they don&#39;t know about the good pattern.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you can&#39;t get your team mates on board, your effort is doomed. I&#39;ve seen bad patterns actually trend upwards toward infinity when no efforts have been taken to get consensus or stop the bad pattern.&lt;/p&gt;
&lt;p&gt;NB: Because of the regular human effort involved in maintaining consensus and educating and re-educating people about the goals, one of the best ways to stop the spreading is to concentrate on faster total conversion to the new pattern. Having bad examples all over your codebase works against you on a daily basis. Bad patterns are contagious.&lt;/p&gt;
&lt;h2&gt;Get your team mates involved in the conversion!&lt;/h2&gt;
&lt;p&gt;Here are a few ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have a rule where no modified files (or functions or modules or whatever doesn&#39;t feel too aggressive for your team) can contain the bad pattern anymore. Figure out ways to enforce this automatically if possible, or in code reviews if not.&lt;/li&gt;
&lt;li&gt;Break the work into chunks and schedule those pieces within other product work on a regular basis. This is sort of a nuclear option, but if the chunks are small enough (yet still encompass the entire scope of the conversion), you can show regular and reliable progress without stopping production work for any extended period of time.&lt;/li&gt;
&lt;li&gt;Get other people to help with the conversion! If people are bought into it, there&#39;s no reason one person should be doing it alone. Multiple people working on it (in a coordinated fashion) will reduce merge conflicts with product work, and increase knowledge sharing about the proper pattern. You may even get better ideas about how to convert.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Don&#39;t do things that don&#39;t work.&lt;/h2&gt;
&lt;p&gt;Stuff that doesn&#39;t work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Efforts that the team as a whole doesn&#39;t find valuable / worth the cost.&lt;/li&gt;
&lt;li&gt;Efforts that are ill-timed. Should you really do it now? Is this really the most important thing?&lt;/li&gt;
&lt;li&gt;Efforts that are not tracking toward 0 in a reasonable amount of time. Partial conversions are &lt;em&gt;really&lt;/em&gt; hard to manage. They may not be a strictly technical concern, but they are a concern for on-boarding, managing, complexity/mental-overhead, knowledge-sharing, etc. Come up with a strategy that doesn&#39;t prolong them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Big problems need smarter solutions!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Mathematics Behind Experience</title>
		<link href="/posts/2018-07-15-the-mathematics-behind-experience/"/>
		<updated>2018-07-15T23:41:53Z</updated>
		<id>/posts/2018-07-15-the-mathematics-behind-experience/</id>
		<content type="html">&lt;p&gt;I always try to think about what exactly it is about experience that makes a software developer better.  Are there aspects of experience that are teachable, but we don&#39;t understand them yet well enough to teach them? Can we do better to pass on &amp;quot;experience&amp;quot; rather than have every developer suffer through the same mistakes that we suffered through?&lt;/p&gt;
&lt;p&gt;I know I&#39;ve had a couple of hard-won lessons over the years that really helped me be more successful in software engineering. I&#39;ve been able to see the warning signs of mistakes to avoid for a long time, but I think only recently I figured out the reasons behind those warning signs. And I think some of the reasons can be explained mostly in terms of probability math, which can then be taught right?&lt;/p&gt;
&lt;p&gt;Before I go into this, I&#39;d like to preface this by saying I&#39;ve failed many many math classes. I hardly ever use any advanced math in my work, and doubt many other programmers do. I wish I had more patience and learned more math (especially how to apply it) too. So with that said, here goes...&lt;/p&gt;
&lt;h2&gt;Lesson: The Certainty of Possibility at Scale or over Time&lt;/h2&gt;
&lt;p&gt;The first piece of experience I&#39;d like to pass on is that your &amp;quot;flawless&amp;quot; solution to a problem, at scale, over time, will fail.&lt;/p&gt;
&lt;p&gt;I don&#39;t know how many times I&#39;ve heard an engineer say something like &amp;quot;This solution is basically bulletproof. There&#39;s only a 1 in a million chance that that corner case you just mentioned will occur&amp;quot;, and then promptly put the solution into an environment that does 1 billion transactions a month.&lt;/p&gt;
&lt;p&gt;Here&#39;s how the math looks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1B transactions/month * 1/1M probability of failure per transaction
= 1B / 1M failures per month
= 1000 failures per month.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, the mathematics of probability are telling us that that particular solution will fail roughly 1000 times a month. This is probably a &amp;quot;duh&amp;quot; conclusion for anyone with a computer science degree, but I see developers (yes even ones with computer science degrees) failing to apply this to their work all the time.&lt;/p&gt;
&lt;p&gt;At scale and over time, pretty much everything converges on failure. My favourite thing to tell people is that &amp;quot;At this scale, our users could find themselves in an  &lt;code&gt;if (false) {&lt;/code&gt;  statement.&amp;quot;.&lt;/p&gt;
&lt;p&gt;So what does this mean? Well it doesn&#39;t mean everything you do has to be perfect. The downsides of failure could be extremely small or completely acceptable (In fact actually pursuing perfection can get really expensive really quickly). What this tells you though is how often to expect failure. For any successful piece of software, you should expect it often. Failure is not an exceptional case. You have to build observable systems to make sure you know about the failures. You have to build systems that are resilient to failure.&lt;/p&gt;
&lt;p&gt;Often I hear people talking about solution designs that have high downsides in the case of failure with no back-up plan and defending them with &amp;quot;But what could go wrong?&amp;quot;. This is a tough one for an experienced developer to answer, because having experience doesn&#39;t mean that you can see the future. In this case all the experienced developer knows is that something will go wrong. Indeed when I&#39;m in these conversations, I can sometimes even find one or two things that can go wrong that the other developer hadn&#39;t considered and their reaction is usually something like &amp;quot;Yeah, that&#39;s true, but now that you mentioned those cases I can solve for them. I guess we&#39;re bulletproof now, right?&amp;quot;.&lt;/p&gt;
&lt;p&gt;The tough thing about unknown unknowns is that they&#39;re unknown. You&#39;re never bulletproof. Design better solutions by expecting failure.&lt;/p&gt;
&lt;p&gt;Understanding this lesson is where ideas like &lt;a href=&quot;https://github.com/Netflix/SimianArmy/wiki/Chaos-Monkey&quot;&gt;chaos monkey&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Crash-only_software&quot;&gt;crash-only architecture&lt;/a&gt;, and &lt;a href=&quot;https://codeascraft.com/2012/05/22/blameless-postmortems/&quot;&gt;blameless post mortems&lt;/a&gt; come from. You can learn it from the math above, or you can learn it the hard way like I did.&lt;/p&gt;
&lt;h2&gt;Lesson: Failure Probability Compounds&lt;/h2&gt;
&lt;p&gt;Here&#39;s the second piece of mathematically-based wisdom that I also learned the hard way instead: If you have a system with multiple parts relying on one another (basically the definition of a system, and any computer program written ever), then the failure rate of the system is a &lt;em&gt;multiple&lt;/em&gt; of the failure rates of the individual components.&lt;/p&gt;
&lt;p&gt;Here&#39;s an almost believable example: Let&#39;s pretend that you&#39;ve just released a mobile app and you&#39;re seeing a 0.5% crash rate (let&#39;s be wildly unrealistic for simplicitly and pretend that all the bugs manifest as crashes). That means you&#39;re 99.5% problem-free right? Well what if I told you the backend has an error rate of 99.5% too and it&#39;s either not reporting them properly or your mobile app is not checking for those error scenarios properly?&lt;/p&gt;
&lt;p&gt;Probability says that you compute the total probability of error by multiplying the two probabilities, ie:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;99.5% X 99.5% = 99%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What if you&#39;re running that backend on an isp and that&#39;s got a 99.5% uptime? And your load balancer has a 99.5% success rate? And the user&#39;s wifi has 99.5% uptime? And your database has a 99.5% success rate?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;99.5% X 99.5% X 99.5% X 99.5% X 99.5% X 99.5% = 97%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you&#39;ve got a 3% error rate! 3 out of every 100 requests fails now. If one of your users makes 50 requests in their session, there&#39;s a good chance that at least one of them will fail. You had all these 99&#39;s and still an unhappy user because you&#39;ve got multiple components and their combined rate of error is the product of each component&#39;s error rate.&lt;/p&gt;
&lt;p&gt;This is why it&#39;s so important when ISPs and Platforms-as-a-service talk about uptime with &amp;quot;5 nines&amp;quot; or 99.999%. They know they&#39;re just one part of your entire system, and every component you have in addition has a failure rate that compounds with their baseline failure rate. Your user doesn&#39;t care about the success rate of the components of the system -- the user cares about the success rate of the system as a whole.&lt;/p&gt;
&lt;p&gt;If there&#39;s anything at all that you should take from this, it&#39;s that the more parts your system has, the harder it is to keep a high rate of success. My experience bears this out too; I don&#39;t know how many times I&#39;ve simplified a system (by removing superfluous components) only to see the error rate reduce for free with no specific additional effort.&lt;/p&gt;
&lt;h2&gt;Lesson: When faced with high uncertainty and/or few data, the past is the best predictor of the future.&lt;/h2&gt;
&lt;p&gt;We saw in the last lesson one example of how surprising complexity can be. The inexperienced developer is generally unaware of that and will naively try to predict the future based on their best understanding of a system, but the stuff we work on is often complex and so frequently defies prediction. Often it&#39;s just better to use past data to predict the future instead of trying to reason about it.&lt;/p&gt;
&lt;p&gt;Let&#39;s say you&#39;re working on a really tough bug that only reproduces in production. You&#39;ve made 3 attempts (and deployments) to fix it, all of which you thought would work, but either didn&#39;t or just resulted in a new issue. You could think on your next attempt that you&#39;ve absolutely got it this time and give yourself a 100% chance of success like you did the other 3 times. Or you could call into question your command of the problem entirely and assume you&#39;ve got a 50/50 chance, because there are two possible outcomes; success or heartache. I personally treat high complexity situations like low data situations though. If we treat the situation like we don&#39;t have enough information to answer the problem (and we&#39;ve got 3 failed attempts proving that that&#39;s the case), we can use Bayesian inference to get a more realistic probability. Bayesian inference, and more specifically, &lt;a href=&quot;https://en.wikipedia.org/wiki/Sunrise_problem&quot;&gt;Laplace&#39;s Law&lt;/a&gt; tells us that we should consider the past. Laplace&#39;s Law would say that since we&#39;ve had 0 successes so far in 3 attempts, the probability for the next deployment to be a success is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  = (successes + 1) / (attempts + 2)
  = (0 + 1) / (3 + 2)
  = 1 / 5
  = 20 %
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the statistical approach I use to predict too.  With no additional information, if I&#39;ve failed at something a number of times, the chances of me succeeding in the future are reduced. I don&#39;t use this data in a depressingly fatalistic way though -- I use it to tell myself when it&#39;s time to make more drastic changes in my approach. Something with a 20% chance of success probably needs a much different, more powerful approach. I also stop telling people &amp;quot;I&#39;m sure I&#39;ve definitely got it this time&amp;quot;.&lt;/p&gt;
&lt;p&gt;Similarly, if there&#39;s an area of the codebase that has received a comparatively large number of bug-fixes, I&#39;m going to lean towards it being more likely to have bugs than the areas having less bugfixes.  This may now seem obvious, but if you&#39;re the person that did all those bugfixes, you may be biased towards believing that after all those fixes, it must be less-likely to still be buggy.  I&#39;d happily bet even money against that, and I&#39;ve actually won a lot of money that way.&lt;/p&gt;
&lt;p&gt;I think it&#39;s fair to say that this is extremely counter-intuitive and may on its face look like a form of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Gambler%27s_fallacy&quot;&gt;Gambler&#39;s fallacy&lt;/a&gt;, but remember it&#39;s for use in low-information scenarios, and I would say that numerous defects are clear evidence you didn&#39;t have enough information about the system to predict this bug in the first place.&lt;/p&gt;
&lt;p&gt;Relatedly, Extreme Programming has a simplified statistical method of estimating how much work a team can handle in a sprint called &lt;a href=&quot;http://www.agilenutshell.com/yesterdays_weather&quot;&gt;&amp;quot;Yesterday&#39;s Weather&amp;quot;&lt;/a&gt;. Instead of having a huge complicated formula for how much work a team can handle in a given timeframe, they simply look at what the team was able to accomplish last sprint. It&#39;s going to be wrong a lot of course, but so is whatever huge complicated formula you devise.&lt;/p&gt;
&lt;p&gt;If there&#39;s a more generalized lesson that you should take from this, it&#39;s that we work with complex systems, they&#39;re notoriously difficult for humans to predict, and predicting statistically can often get you a clearer picture of the reality of a situation.  Resist prediction from first principles or through reasoning.  You don&#39;t have enough data, and software systems are normally elusively complex.&lt;/p&gt;
&lt;p&gt;With all this said, I know it&#39;s pretty hard to really get a feel for the impact of probabilities until you&#39;ve had the prerequisite defects, failed deployments, and product outages.  I sure wish someone had at least taken a shot on telling me in advance though. It also makes me wonder what I&#39;ve still got left to learn.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Zero Defect Policy</title>
		<link href="/posts/2018-03-27-zero-defect-policy/"/>
		<updated>2018-03-28T00:32:11Z</updated>
		<id>/posts/2018-03-27-zero-defect-policy/</id>
		<content type="html">&lt;p&gt;The 4th criteria of &lt;a href=&quot;https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/&quot;&gt;the Joel Test&lt;/a&gt; of quality on a software team is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Do you have a bug database?&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;You probably do.  The test was written almost 20 years ago and if I recall correctly almost everyone had one anyway.  Joel was even &lt;em&gt;selling&lt;/em&gt; one.&lt;/p&gt;
&lt;p&gt;On the surface it seems like common sense.  Quality is something you want to manage.  So naturally you&#39;ll also tend to want to log things... measure things... track things.&lt;/p&gt;
&lt;p&gt;I want to propose a better way for most situations though.  It&#39;s simpler, your long-term speed will be faster, and your product quality will be higher:&lt;/p&gt;
&lt;h2&gt;The Zero Defect Policy&lt;/h2&gt;
&lt;p&gt;Simply put: &lt;strong&gt;Prioritize every defect above feature work or close the issue as a WONTFIX&lt;/strong&gt;.  I&#39;m not suggesting you interrupt any work already in progress, but once that&#39;s done, burn your defect list down to 0.&lt;/p&gt;
&lt;h2&gt;Why in the world?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Bugs are much cheaper to fix immediately.  You know the product requirements most clearly at that time.  You were touching that code most recently at that time and it&#39;s still fresh in your mind.  You might even remember a related commit that could have been the cause.  The person who wrote it is still on the team.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Most things we&#39;d classify as bugs are really some of the most obvious improvements you could make.  You probably don&#39;t need to a/b test a typo fix.  If your android app is crashing on the latest Samsung phone, you don&#39;t need a focus group.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Managing bugs is a huge effort.  If you&#39;re not going to immediately fix them, you have to tag them, categorize them, prioritize them, deduplicate them, work around them, do preliminary investigations on them, revisit them, and have meetings about them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The development team needs the proper immediate feedback and back-pressure to know when to speed up and when to slow down.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Say What now?&lt;/h2&gt;
&lt;p&gt;Defects are perfectly normal.  If you don&#39;t have them, you&#39;re either NASA or you&#39;re developing too slowly.  However, if you have too many, or if they&#39;re particularly costly, you absolutely need to slow down and turn them into learning opportunities.  In those times, the fix isn&#39;t enough.  The fix with an automated test isn&#39;t even enough.  You&#39;ll want to look into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;other prevention measures&lt;/li&gt;
&lt;li&gt;faster detection measures&lt;/li&gt;
&lt;li&gt;faster ways to fix&lt;/li&gt;
&lt;li&gt;better ways to limit impact&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the REAL definition of Quality Assurance.  If you do this &lt;a href=&quot;/posts/2015-03-08-reclaiming-value-from-bugs-and-outages/&quot;&gt;thoughtfully&lt;/a&gt;, and don&#39;t try to make an army of manual testers the best solution you could come up with, over the long term you&#39;ll be much much faster.  You&#39;ll be the kind of product development team that the company actually believes when you say something is &amp;quot;done&amp;quot;.&lt;/p&gt;
&lt;h2&gt;What about the low value, high cost bugs?&lt;/h2&gt;
&lt;p&gt;Delete them.  If they become worthwhile later, you&#39;ll hear about them again.  If you can&#39;t bring yourself to delete it, you probably value it too much to not fix it.  Just fix it.&lt;/p&gt;
&lt;h2&gt;What about when my team ends up with a week&#39;s worth of defects and can&#39;t get any feature work through?&lt;/h2&gt;
&lt;p&gt;There will definitely be dark times.  Slow down and learn from them.  It&#39;s the best time to talk about speed improvements, because speed and quality are interdependent.  You can move much faster in mistake-proof environments.  In most cases, &lt;a href=&quot;/posts/2014-06-03-quality-is-the-constraint/&quot;&gt;nobody cares how fast you ship broken software.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Sounds great, but what about our existing bug database of hundreds of bugs?&lt;/h2&gt;
&lt;p&gt;Many are probably not even bugs anymore if you&#39;ve been collecting long enough to get hundreds.  How many of those old things can you even reproduce?  How many have clear enough descriptions that you can even still understand the problem?  Is the original submitter still around?  Here&#39;s my solution: delete all but the highest priority ones and immediately schedule the high priority ones above other features.  Allow people to file reports again if they really care about a particular defect and the defect still exists.&lt;/p&gt;
&lt;p&gt;The bug database is great in theory, but in practice, it&#39;s often an aging garbage heap of ignored customer frustrations and a /dev/null for opportunities for improvement.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Enterprise Iffing 3.0 for 10x Rockstar Programmers</title>
		<link href="/posts/2017-10-27-enterprise-iffing-3-dot-0-for-10x-rockstar-programmers/"/>
		<updated>2017-10-27T14:57:02Z</updated>
		<id>/posts/2017-10-27-enterprise-iffing-3-dot-0-for-10x-rockstar-programmers/</id>
		<content type="html">&lt;p&gt;I&#39;ve had a chance to get back to coding after a couple of months&#39; hiatus so I thought I&#39;d write about something a bit more fun and way down in the details.&lt;/p&gt;
&lt;p&gt;Conditionals add complexity -- they seem like a tiny bit of complexity in the singular case, but they really do add up quickly to make code unpredictable and difficult to follow.&lt;/p&gt;
&lt;p&gt;Your debugger and your unit tests are probably great at managing that complexity, but they&#39;re really kind of a crutch.  You want to remove complexity, not manage it.&lt;/p&gt;
&lt;p&gt;As a result I have a bunch of rules around conditionals that I generally always try to follow.&lt;/p&gt;
&lt;h2&gt;Early-Return is Simpler&lt;/h2&gt;
&lt;p&gt;Probably my most important personal rule is to use early-returns wherever possible.  In general, it&#39;s not simpler to just have a single return at the bottom of a function when you can return earlier in some circumstances.  If you know a value shouldn&#39;t be changed after a certain point in a function you should just return right there.  There are two reasons it&#39;s simpler:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You don&#39;t have to try to reason about what might still happen later&lt;/li&gt;
&lt;li&gt;Subsequent reading of the code (by you or others) can be much faster because you can stop reading the code for a function as soon as the case you&#39;re investigating hits a return.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fizzMyBuzz&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; output&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    output &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;FizzBuzz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    output &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fizz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    output &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Buzz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    output &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; output&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;VS&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fizzMyBuzz&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;FizzBuzz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fizz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Buzz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&#39;s a visible difference in density here.  The second example just has less stuff, even though the number of lines are pretty similar.  Early returns mean that subsequent code has to worry a lot less about the effects of previous code.&lt;/p&gt;
&lt;p&gt;There&#39;s definitely a trade-off here.  Now when you&#39;re looking for where the function returns, it&#39;s not just at the end -- it could be in a bunch of places.  I think the trade-off makes sense though because even when I&#39;m tracing through function calls in a backward-fashion, I&#39;m usually reading functions from top to bottom.&lt;/p&gt;
&lt;h2&gt;Try to NOT use negation&lt;/h2&gt;
&lt;p&gt;Negation is complexity.  In my experience it probably even beats off-by-one errors in the category of &amp;quot;things that are too simple to possibly go wrong that go wrong all the time&amp;quot;.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Don&#39;t allow additional vegetables in this salad but avoid forbidding the addition of non-orange vegetables&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;So can this salad have carrots or not?!?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;VS&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;No orange vegetables&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Oh&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Something like...&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;specialCase&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;someStuff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;someOtherStuff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...should at the very least be changed to:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;specialCase&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;someOtherStuff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;someStuff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One exception to this rule: If negation will let you early-return, definitely do that!  Hopefully this non-non-negation exception is not too complex. ;)&lt;/p&gt;
&lt;h2&gt;Now you can pretty much deprecate &lt;code&gt;else&lt;/code&gt;.&lt;/h2&gt;
&lt;p&gt;Often when I can&#39;t return early, I just move the entire if..else block to a method where I &lt;em&gt;can&lt;/em&gt; return early.  Then I don&#39;t need else.&lt;/p&gt;
&lt;p&gt;Trying to restrict my use of &lt;code&gt;else&lt;/code&gt; is a great forcing function for creating smaller functions and using early-return more often.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;FizzBuzz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Fizz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Buzz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;VS&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fizzMyBuzz&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// We wrote this earlier in the post!&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Working Without Estimates</title>
		<link href="/posts/2017-10-21-working-without-estimates/"/>
		<updated>2017-10-22T01:17:00Z</updated>
		<id>/posts/2017-10-21-working-without-estimates/</id>
		<content type="html">&lt;p&gt;I&#39;ve been developing software for a few years without doing much estimation at all, and the estimation I&#39;ve been doing has been really vague, eg &amp;quot;You know that feature is a lot of work, right?&amp;quot;.  I&#39;ve recently been reading more and more from the &lt;a href=&quot;https://twitter.com/search?q=%23noestimates&amp;amp;src=typd&quot;&gt;#noestimates movement on The Twitter&lt;/a&gt;, so I thought I&#39;d chime in a bit with my rationale and experience as well.&lt;/p&gt;
&lt;h2&gt;&amp;quot;Is the company crazy?&amp;quot;&lt;/h2&gt;
&lt;p&gt;Yes, but I don&#39;t think the lack of estimation contributes to that.  Estimation has a bunch of downsides to it that make eschewing it pretty rational:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Teaching people estimation best practices takes a lot of time.  Without spending that time, the estimates are terrible.  Story points, planning poker, and other methods seem to blow people&#39;s minds.&lt;/li&gt;
&lt;li&gt;Estimation meetings take a lot of time.&lt;/li&gt;
&lt;li&gt;It&#39;s almost impossible to ensure that people (engineers or management) are not treating the estimates as deadlines and unnecessarily rushing work (creating unnecessary defects and technical debt that slow the team down more).&lt;/li&gt;
&lt;li&gt;A lot of estimates are still really terrible and therefore low-value and not worth the effort.  Decades of industry-wide software development thinking have not changed that.&lt;/li&gt;
&lt;li&gt;A lot of estimates don&#39;t actually matter.  A 1-week task that is off by 50% but still successful with users, is almost always still a huge success.  Sure being off by 50% on a 6 month plan is really bad, but my best recommendation for 6-month plans is &amp;quot;don&#39;t&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&amp;quot;But then how do people know when to stop working?&amp;quot;&lt;/h2&gt;
&lt;p&gt;You&#39;ve probably heard &lt;a href=&quot;https://en.wikipedia.org/wiki/Parkinson%27s_law&quot;&gt;Parkinson&#39;s Law&lt;/a&gt; that &amp;quot;work expands to fill the time available&amp;quot;.  In my opinion it&#39;s a super-cynical way of thinking about people but I&#39;ve known many people that believe it.  If it seems true to you in your organization consider these factors that might be contributing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Engineers almost always under-estimate (unless they&#39;re consciously trying to under-promise/over-deliver -- cynically called &amp;quot;sand-bagging&amp;quot;).  This is because they&#39;re estimating best-case scenarios, and life with complex socio-technical systems rarely falls in the best-case.&lt;/li&gt;
&lt;li&gt;The focus on how long things take often incentivizes engineers to take short-cuts and to just allow technical debt and complexity to pile up.  If they&#39;ve got extra time in an estimate for some reason (hard to believe because of the previous point), they actually start doing the refactoring that they would otherwise not consider doing.&lt;/li&gt;
&lt;li&gt;They may be gold-plating something because they don&#39;t know what the next most important thing to do is, they don&#39;t understand or believe in the value of it, or they don&#39;t think they&#39;ll get a chance to ever return to the current feature to tweak/improve it.  In this case, there are probably trust issues to solve.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instead...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure people are adequately incentivized to move on to the next thing.  Probably by making them care about the next thing.&lt;/li&gt;
&lt;li&gt;Have a clear definition of what it means to be done (ala Scrum&#39;s Definition of Done).&lt;/li&gt;
&lt;li&gt;Give them all the time in the world for the current thing.  Let them relax and do it right so it stays done instead of being a constant source of future interruption as the defects roll in.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have trust and the right people, the team will move really fast, especially over the long haul.&lt;/p&gt;
&lt;h2&gt;&amp;quot;Estimates can be a good forcing function though.  Otherwise how do people know when to cut functionality?&amp;quot;&lt;/h2&gt;
&lt;p&gt;Just cut it all immediately.  Decide the absolute essentials of the feature, and cut the rest immediately with no mercy.  Deliver those essentials first.  Then incrementally try to fit in the next most valuable aspects.&lt;/p&gt;
&lt;p&gt;This is the only sane way to ensure you&#39;re doing the highest value work first.  You don&#39;t need scheduling -- you just need prioritization.  The stuff that gets cut will be the low-priority stuff.&lt;/p&gt;
&lt;h2&gt;&amp;quot;I need some level of predictability in the software development process though!&amp;quot;&lt;/h2&gt;
&lt;p&gt;That doesn&#39;t mean you&#39;re going to get it.  If you&#39;ve been in software development for any length of time, you know that estimates are often wrong and you haven&#39;t figured out how to make them better.  In complex systems, prediction rarely leads to predictability.&lt;/p&gt;
&lt;p&gt;Instead of trying to predict, you should be aiming to try to mitigate risk as early and often as possible, by doing the riskiest, least clear, and highest value proposition efforts first in the leanest way possible.&lt;/p&gt;
&lt;p&gt;This allows you to incrementally move to the more proven, clear, and next-highest-value efforts over time, and have an effort that observably converges on completion.  It&#39;s a better shot at predictability, but without prediction.&lt;/p&gt;
&lt;h2&gt;&amp;quot;But everyone else does it!&amp;quot;&lt;/h2&gt;
&lt;p&gt;This is the worst of the arguments, in my opinion.  I love employing best practices when I don&#39;t have a better way but otherwise they&#39;re the enemy continuous improvement.  Estimates on their own deliver no user-value.  Any effort that isn&#39;t yielding comparable results should be axed.  Any goal that can be better served by other methods should just be solved by those methods.&lt;/p&gt;
&lt;h2&gt;If you&#39;re not a developer and you still don&#39;t buy my argument...&lt;/h2&gt;
&lt;p&gt;Let&#39;s flip the script.&lt;/p&gt;
&lt;p&gt;As an engineer I&#39;ve yet to meet anyone in management that is willing to give me estimates on the &lt;strong&gt;expected value&lt;/strong&gt; of a feature (preferrably in dollars, but I&#39;ll take whatever the proxy/vanity metric of the day is too!).  This would be super-valuable to ensure we&#39;re prioritizing the most impactful stuff first right?  And we could check the validity of these estimates after the feature is released right?&lt;/p&gt;
&lt;p&gt;I think this would be a hilarious way to turn the tables and see how management does with estimation of complex systems, but in the end I think it would be similarly fruitless for improving predictability.  Their estimates would be just as wrong, just as often.  They&#39;d be just as nervous about being confronted on their accuracy too.&lt;/p&gt;
&lt;h2&gt;Estimation is a linear process management tool in a non-linear world.&lt;/h2&gt;
&lt;p&gt;Estimation just doesn&#39;t really provide us with much predictability considering it&#39;s cost.&lt;/p&gt;
&lt;p&gt;That doesn&#39;t mean that no one should ever do it -- it will definitely make sense in some cases -- but I personally think it&#39;s overused, largely ineffective, and often destructive in most of the cases that it&#39;s used.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Why does Bad Waterfall Happen to Good People?</title>
		<link href="/posts/2017-07-20-why-does-bad-waterfall-happen-to-good-people/"/>
		<updated>2017-07-20T22:35:31Z</updated>
		<id>/posts/2017-07-20-why-does-bad-waterfall-happen-to-good-people/</id>
		<content type="html">&lt;p&gt;I&#39;ve recently seen a case of spontaneous waterfall-style development emerging where the team was generally empowered to avoid it or at least to correct against it, and certainly wanted to, and yet did not. From the outside it seemed like waterfall was a kind of steady-state for them that they&#39;d trended toward and didn&#39;t have the escape-velocity to move toward anything else. They weren&#39;t happy with it either. Most of them felt quite alienated from their work which is a common result of waterfall development. What could have happened?&lt;/p&gt;
&lt;p&gt;I think there are a bunch of properties that can lead to waterfall-style development and management is only one of them. Before I get into those, I&#39;d first like to propose a simplified explanation of what it means to be waterfall.&lt;/p&gt;
&lt;h2&gt;What’s This Waterfall Thing That They’re Talking About?&lt;/h2&gt;
&lt;p&gt;Waterfall development is development with varying degrees of one-way hand-offs between multiple disciplines. The best way to think of it is to imagine a sort of human assembly line where each homogenous set of disciplinarians pass the result of their discipline down to the next homogenous set of disciplinarians. More concretely, you&#39;ve got these hand-offs when the product managers tell the designers what to design and the designers tell the engineers what to build and the engineers give the testers the work to test and the testers give the release manager a release to release and the release manager gives the sysadmins a deployable to deploy. It&#39;s all very well organized and simple to explain and generally soul-sucking and totally inefficient in practice.&lt;/p&gt;
&lt;p&gt;It&#39;s soul-sucking for a few reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The downstream disciplines have very little power to make drastic changes, because of the tyranny of &lt;a href=&quot;https://youarenotsosmart.com/2011/03/25/the-sunk-cost-fallacy/&quot;&gt;sunk-cost fallacy&lt;/a&gt;. For example, if the testers find some behaviour that is terrible for the users, the engineers will shrug and say &amp;quot;not a bug... works as designed!&amp;quot;. Or if the engineers determine there&#39;s a performance problem with the fully completed hi-fi design mocks that make them infeasible, the designer is at best forced to go back to the drawing board to take another shot at getting an idea that the engineers might agree on.&lt;/li&gt;
&lt;li&gt;The downstream disciplines have no idea why they&#39;re designing/building/testing/releasing what they&#39;re designing/building/testing/releasing. Waterfall is set up as an assembly line in the name of efficiency and that means that downstream disciplines are on a need-to-know basis. The problem with this is that you suck the motivation out of everyone because knowing &amp;quot;why&amp;quot; is precisely where motivation comes from.&lt;/li&gt;
&lt;li&gt;The upstream disciplines are generally resented by the downstream disciplines for how they&#39;re always ignoring the important downstream concerns.&lt;/li&gt;
&lt;li&gt;The upstream disciplines are constantly pressured to do more and more flawless work &amp;quot;to minimize all that expensive back-and-forth&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&#39;s funny when people start to talk about &amp;quot;all that expensive back-and-forth&amp;quot; because trying to avoid that is precisely what makes it so expensive. The upstream disciplines are always expected to trend toward perfection in pursuit of the ideal one-way waterfall. When you hear the engineers asking for perfect hi-fi mocks before they start their work, you&#39;ll know you&#39;re approaching waterfall-land. Your product development flow is about to go into slow-motion.&lt;/p&gt;
&lt;h2&gt;The Role of Single-Discipline Teams&lt;/h2&gt;
&lt;p&gt;There&#39;s an idea too that similar disciplinarians should be the ones working and managed together as a unit; that&#39;s how you achieve consistency in the discipline and how you ensure these specialists are always pushing each other to greater heights in their respective crafts. Unfortunately these specialists never really get a full view of the entire process.  With neither broad understanding nor a holistic ownership mindset, the end result is that you’re paying a whole lot of smart people while simultaneously trying to avoid them thinking about the business&#39; problems. A specialist that doesn&#39;t fully understand the business goals or how software development works in general will always be a pretty weak specialist regardless of the depth of their specialization.&lt;/p&gt;
&lt;p&gt;This is how you get dysfunctional scenarios like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;QA personnel that feel like their primary goal is to try to find a way to block the release.&lt;/li&gt;
&lt;li&gt;Designers that feel like customers should wait for the perfect aesthetics before we can deliver new functionality.&lt;/li&gt;
&lt;li&gt;Engineers that can’t make good decisions about when to take on technical debt and when to pay it down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having individuals confined solely to their area of expertise &lt;i&gt;can&lt;/i&gt; make sense in the short term! For example, I&#39;m an engineer and I&#39;ve regularly had terrible product ideas. In the short term there&#39;s no sense in involving me further &amp;quot;upstream&amp;quot; in the process; I&#39;ll only drag it down.&lt;/p&gt;
&lt;p&gt;In the long term though, my terrible product sense is certainly a liability. And on a daily basis when I stand in the shower or on the subway thinking about work, I&#39;m just coming up with more terrible ideas. The better thing to do is to teach me about the business and its goals and make that investment in me. You&#39;ll occasionally get a worthwhile idea from me, and I&#39;ll always be more willing to go that extra mile because I know why I&#39;m building what I&#39;m building and that it&#39;s worthwhile work.&lt;/p&gt;
&lt;h2&gt;The Role of Product Management&lt;/h2&gt;
&lt;p&gt;Product management can play a significant role in whether or not that teaching and that context-sharing happens.  I’ve seen teams prioritize their own product backlog for multiple weeks of work without a product manager present -- That’s a team that the product manager has really invested in and the result is that the product manager is comfortable giving them agency.  There are some unexpected things that can happen here: the team will often have better ideas or prioritizations than the PM, or at the very least will have top-of-stream improvements on the PM’s ideas that would never happen otherwise.  When this is really working, the one brain of the PM will almost certainly not be able to beat the multiple brains on the team.  And when the PM considers themselves a contributing member of the team, the team will necessarily outperform the lone PM.&lt;/p&gt;
&lt;p&gt;There’s a simple but slow progression that a skillful PM can push the team through if they’re in waterfall-mode due to the product management stage:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Allow the team to own the solutioning.&lt;/strong&gt; Take the team from working on predetermined solutions and start to instead involve them in determining the solutions themselves.  Achieving this really takes a considerable amount of effort, but it usually pays for itself in spades later with the PM’s freed-up time, better work prioritizations, better product decisions, and less process churn (“expensive back-and-forth”).  It’s amazingly motivating for the team too.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allow the team to own the problem-selection.&lt;/strong&gt; Once you’re comfortable with their performance in determining the solutions, start to get their input on what the problems to solve are, and coach them to seek problems that meet the team’s goals and show them to independently collaborate with other sources of company/product/user information.  Give them access to the metrics they’re trying to improve.  In time, be open to letting them try some ideas that you might not think are great; at the very least it’ll be a learning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allow the team to have input into the mission.&lt;/strong&gt; Everything is easier when the team thinks it’s working towards the right goals.  The easiest way to get the team working on the right goals is to ensure that they have that context.  If you brought the team through steps 1 and 2 above, you can see that they’re much more bought-in to plans that they’re part of.  Involve them in actually determining the mission too!  The end result will be a team that is incredibly fast-moving and energized.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Not to be too deep, but even though this is framed here as a maturity progression for the team, it can also be a maturity progression for the PM.  The PM needs to be able to become the team’s guide to the market, the user’s needs, the company’s goals, etc, etc, instead of playing the part of puppeteer.  And we’ve seen that it absolutely doesn’t put the PM out of a job.  There’s definitely more than enough work in ensuring that you can be expert guide and a strong team mate.  The product manager on my current team was brave enough to engage with the rest of the team like this and the results are really amazing.  Instead of pushing product management on the team, he pulls the team into product management.&lt;/p&gt;
&lt;p&gt;Also it should be obvious that when the team is spending time on things that are not software production that they will almost certainly release less lines-of-code.  I’ve found instead though that the products developed this way are generally always delivering more value to the user, and doing so at a faster pace.  No user is asking for “more software”.&lt;/p&gt;
&lt;h2&gt;Product Management Is Just One Possible Contributing Factor Though&lt;/h2&gt;
&lt;p&gt;In fact any of the disciplines on the team has the ability to cause the emergence of a waterfall model of development. It’s a systematic problem that is really tough to solve because it emerges from the socio-technical complex system of the software, the team, the company, and the market.  As a result, there’s almost never just a single cause of it.&lt;/p&gt;
&lt;p&gt;So with the obvious influence of product management aside, these additional properties seem to make waterfall vastly more likely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Inability to see how traditionally downstream disciplines can actually occur simultaneously or even upstream.&lt;/li&gt;
&lt;li&gt;Perfectionism (release-o-phobia) due to the perception that a particular stage is very expensive or irreversible.&lt;/li&gt;
&lt;li&gt;An &amp;quot;Only specialists can do X&amp;quot; attitude (often due to perfectionism), sometimes worsened by an approval process requiring sign-off.&lt;/li&gt;
&lt;li&gt;Lack of will to collaborate across disciplines. There&#39;s an inertia to collaboration that sometimes is hard to overcome.&lt;/li&gt;
&lt;li&gt;Cargo cult adherence (eg &amp;quot;Such-and-such company does it this way&amp;quot;, &amp;quot;This is the way I&#39;ve always done it&amp;quot;, &amp;quot;My software engineering textbook from 1968 says this is how you do it&amp;quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;ve personally never seen waterfall-style development occur in the absence of these factors so I think about ways to stamp them out whenever I see them.&lt;/p&gt;
&lt;p&gt;For the team that just doesn&#39;t know how to defeat waterfall but wants to, there are a tonne of things to try:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create an environment of collaboration. Usually this involves collocated cross-discipline teams. When other companies are saying &amp;quot;Design is crucial. We should have a design team.&amp;quot;, try to instead say &amp;quot;Design is crucial. We should have a designer on every team.&amp;quot; It&#39;s this attitude that will have your team able to deliver software entirely on its own without endless meetings with other teams.&lt;/li&gt;
&lt;li&gt;Make sure the team is surrounded by the information that it needs to be to make the right decisions. They should have easy access to your user-researchers, data scientists, customer-support, subject-matter experts, etc, etc to easily learn everything that they have to about their problem space.  If you can put those specialists on the team as well, that’s even better.&lt;/li&gt;
&lt;li&gt;Try to get the team to focus on a very small number of things at once, ideally 1.  You want to focus on finishing instead of starting and getting each member of the team to do something different is the opposite of that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you&#39;ve achieved that proper environment, experiment with ways to disassemble the traditional waterfall order of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have many people involved in all manner of planning (&lt;em&gt;if&lt;/em&gt; they&#39;re interested... Some teammates may prefer to trust the others in their decisions and avoid all those meetings).&lt;/li&gt;
&lt;li&gt;Have a common set of standard UI components so engineers can assemble pretty good designs quickly on their own.&lt;/li&gt;
&lt;li&gt;Practice &lt;a href=&quot;https://en.wikipedia.org/wiki/DevOps&quot;&gt;devops&lt;/a&gt;! It&#39;s the ultimate collaboration of developers, release managers and sysadmins often with all 3 roles rolled into one person (and heavily automated!) but at least on the same team.&lt;/li&gt;
&lt;li&gt;Decouple release from deployment with &lt;a href=&quot;https://martinfowler.com/bliki/FeatureToggle.html&quot;&gt;feature flags&lt;/a&gt; and actually deploy before design is even complete. Often you can deploy all kinds of non-production-ready stuff constantly and only turn it on when it&#39;s ready. That&#39;s the essence of &lt;a href=&quot;https://continuousdelivery.com/&quot;&gt;Continuous Delivery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Do testing BEFORE engineering. &lt;a href=&quot;https://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;TDD&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Behavior-driven_development&quot;&gt;BDD&lt;/a&gt; are possibilities. If you have QA people, let them advise on what kinds of tests would be useful. That&#39;s what Quality Assurance &lt;a href=&quot;http://asq.org/learn-about-quality/quality-assurance-quality-control/overview/overview.html&quot;&gt;actually means&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If possible, have everyone own testing. If possible, have engineers own test automation and test their own/each other&#39;s stuff.&lt;/li&gt;
&lt;li&gt;Have lo-fi designs that are good enough to start engineering with. Let the hi-fi designs come later... maybe much later; Depending on your situation, you might be able to launch to 1% of your users with lo-fi designs and validate the product before investing in higher fidelity designs.&lt;/li&gt;
&lt;li&gt;Have engineers and testers think through the lo-fi versions of the designs with the designer. Treat the designer as the team&#39;s expert guide rather than putting all the design responsibility on them.&lt;/li&gt;
&lt;li&gt;Break up your work into smaller and smaller pieces. Even if you&#39;re doing some hand-offs, rework on small pieces is much cheaper.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The greater goal is to value results over effort, and to build the right software rather than the most software.  Getting as many efforts in progress at once is an anti-pattern.  Making sure everyone has something to do is a non-goal.&lt;/p&gt;
&lt;p&gt;Without that perspective, many of these practices will seem inefficient.  Sure sometimes you&#39;ve got multiple people working slightly outside of their specialty, but the resulting software is generally always better, and all that expensive back-and-forth and rework is virtually eliminated. People are generally happier and more engaged as well because they know how important the work is and why.&lt;/p&gt;
&lt;p&gt;&lt;sub&gt;Special thanks to &lt;a href=&quot;https://twitter.com/tayroga?lang=en&quot;&gt;Taylor Rogalski&lt;/a&gt; for feedback!&lt;/sub&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>So You Want to be a More Senior Engineer?</title>
		<link href="/posts/2017-06-04-so-you-want-to-be-a-more-senior-engineer/"/>
		<updated>2017-06-04T17:22:43Z</updated>
		<id>/posts/2017-06-04-so-you-want-to-be-a-more-senior-engineer/</id>
		<content type="html">&lt;p&gt;&amp;quot;Engineer&amp;quot; really is a very silly term for people that make software.  Engineering is supposed to be a predictable application of science toward predictable results.  Software development is really anything but that.  The biggest problem in our profession is and always has been getting predictable results.&lt;/p&gt;
&lt;p&gt;The key difference between a junior engineer and those that are more senior is that the more senior engineer realizes the inherent unpredictability of delivering working software and constantly works toward making that delivery more predictable.&lt;/p&gt;
&lt;p&gt;The junior, on the other hand, approaches the work with two key hinderances:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Being too intellectually challenged (or enamoured) with the details of programming in the small to be able to see the larger picture&lt;/li&gt;
&lt;li&gt;Having little experience with complex systems (and often not even understanding that they&#39;re working in one)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a result the more junior engineer will generally pursue solutions that risk predictability, frequently without realizing it.  What&#39;s worse is that often these solutions will be faster/better/cheaper, further reinforcing the approach.  Failures with risky approaches are often written off as fluke mistakes, technicalities, or the nebulous &amp;quot;human error&amp;quot; without reconsidering the methodology.  Often they&#39;re written off like this even when the cost of the failures vastly outweighs the riskiness of the approach.&lt;/p&gt;
&lt;p&gt;In software development, the details can seomtimes be really difficult.  This never really goes away with experience, but the Junior Engineer hasn&#39;t yet been faced with that enough times to know it.  And when the details are difficult, the junior engineer focuses primarily on the details, often to the detriment of the big picture -- predictability.  It&#39;s a pretty understandable choice; our brains are limited in how much they can consider at once, and for some reason engineers have a tendency to default to concentrating on the technical details.&lt;/p&gt;
&lt;p&gt;Conversely, the more senior engineer will be less encumbered by the technical details and will have been bitten a number of times by the nature of complex systems.  If that engineer has taken the opportunity to learn from those mishaps, there&#39;s a chance for a much higher level of engineering (and predictability).&lt;/p&gt;
&lt;p&gt;With that in mind, here are a bunch of examples that I think show the differences more plainly:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Finds a solution. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Finds the simplest solution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Finds a solution for right now. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Considers the longer term implications when finding a solution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Defaults to adding complexity/code with every requirements change. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Knows that changes often indicate a unifying concept and an opportunity to remove complexity/code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Finds ways to manage complexity &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Finds ways to remove complexity (because complexity management techniques are another form of complexity!)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Predicts results &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Embraces unpredictability and manages it&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Assumes that lack of evidence of problems is evidence of lack of problems. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Is aware that unknown unknowns almost always exist.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Can explain why their grand plan is flawless. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Ships as early and often as possible and judges solutions empirically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Believes that it&#39;s sufficient to achieve quality at the edges. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Knows that often you have to ensure quality of internal components separately to achieve quality at the edges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Believes that once the pieces are verified, the system is verified. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Knows there&#39;s still work to verify the system as a whole.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Will call &amp;quot;done&amp;quot; when the happy-path works, or the code is committed, or the code passes testing, or the code is in staging. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Realizes there are so many technicalities involved in actually solving real problems that one shouldn&#39;t call &amp;quot;done&amp;quot; until the user has used it and agrees.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Believes that once you get the software to work, it will work in perpetuity with no extra effort. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Realizes that maintenance always takes considerable time and effort.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Optimizes code that seems slow. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Measures for performance issues and optimizes only the bottleneck.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Writes code for the computer to understand. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Writes code for the computer and humans to understand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Focuses entirely on the technical aspects of the role. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Realizes the entire complex system is a socio-technical one that also necessarily involves people.  Constantly tries to also take the humans (managers, stakeholders, users, teammates, etc) into consideration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Works tirelessly and continuously to solve a critical and time-sensitive problem. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Understands that communication during critical times is also crucial, and that &amp;quot;I have no update&amp;quot; is still a highly valued update.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Can explain why a solution is good. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Can explain why a solution is better than the others for a given criteria.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Is learning to be critical of software designs choices.  &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Is always trying to understand the tradeoffs in software design choices and can see the good in imperfect solutions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Is learning new technology, design patterns, and practices and trying to apply them. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Judges technology solely on the basis of its ability to solve actual problems and skillfully avoids cargo-cult programming.&lt;/p&gt;
&lt;p&gt;Anyway... these are just examples and certainly don&#39;t form an exhaustive list.  I&#39;m not at the end of learning from experience either, so I couldn&#39;t even write an exhaustive list if I wanted to.&lt;/p&gt;
&lt;h2&gt;One more example of the meta-variety:&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Is starting to realize that predictability is valuable and is
learning how to achieve it. &lt;br /&gt;
&lt;strong&gt;Senior&lt;/strong&gt;: Realizes that different predictability approaches have different costs in different scenarios and makes choices accordingly after cost/benefit analysis.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The All-or-Nothing Principle</title>
		<link href="/posts/2017-04-09-the-all-or-nothing-principle/"/>
		<updated>2017-04-09T16:07:00Z</updated>
		<id>/posts/2017-04-09-the-all-or-nothing-principle/</id>
		<content type="html">&lt;p&gt;&lt;sup&gt;Special thanks to my friends Deepa Joshi and Sam DeCesare for input/feedback!&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;The 80/20 Rule, otherwise known as the &lt;a href=&quot;https://en.wikipedia.org/wiki/Pareto_principle&quot;&gt;Pareto Principle&lt;/a&gt; has wide-reaching implications for productivity.  If you can get 80% of the results you want for 20% of the effort in a given endeavour it really lets you consider an &lt;a href=&quot;https://en.wikipedia.org/wiki/Efficiency%E2%80%93thoroughness_trade-off_principle&quot;&gt;efficiency/thoroughness trade-off&lt;/a&gt; that&#39;s right for your desired results.  There&#39;s a real opportunity for saving a whole lot of effort and still raking in big results for that effort when you find a scenario that conforms to the 80/20 rule.  Unfortunately there are a bunch of scenarios in life that don&#39;t conform to this nice 80/20 distribution and so I&#39;d like to propose another one that I see pretty often.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The All-or-Nothing Principle: For many scenarios in life, there are 0% of the effects until there are 100% of the causes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So while a Pareto distribution looks something like this:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/paretodistribution-394w.webp 394w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;pareto distribution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/paretodistribution-394w.jpeg&quot; width=&quot;394&quot; height=&quot;269&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;...an All-or-Nothing distribution is much simpler; you&#39;ve either got the effect or you don&#39;t.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/aondistribution-377w.webp 377w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;all-or-nothing distribution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/aondistribution-377w.jpeg&quot; width=&quot;377&quot; height=&quot;294&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;It applies only to systems where results are binary which can also be found all over the place: everywhere from electronic examples like light switches or mouse-clicks, to the more biological -- like being pregnant or being dead.&lt;/p&gt;
&lt;p&gt;Like the Pareto Principle, the All-or-nothing Principle can have a huge effect on productivity if you recognize it and handle it appropriately.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/unfinishedbridge-419w.webp 419w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;By Flickr user Paul Mannix - https://www.flickr.com/photos/paulmannix/552103944, CC BY 2.0, https://commons.wikimedia.org/w/index.php?curid=46305687&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/unfinishedbridge-419w.jpeg&quot; width=&quot;419&quot; height=&quot;279&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s a simple example: Bridges are expensive to build.  Building a bridge even 99% of the way across a river gets you 0% of the results.  This isn&#39;t at all the type of distribution that the Pareto Principle describes and so you can&#39;t make the same efficiency/thoroughness trade-off with it.  You simply can&#39;t get 80% of the cars across with 20% of a bridge, so in order to extract maximum productivity from these scenarios, you have to approach the situation fundamentally differently.  The important thing to remember in these scenarios (assuming you&#39;ve identified one correctly) is that there is no difference at all in effect between 0% effort and 99% effort.  If all you can give is 99% effort, &lt;em&gt;you should instead give no effort at all&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Let&#39;s talk through the bridge example a little more: If you were a bridge-building company with 99% of the resources and time to build a bridge, you would be in a much better spot in general BEFORE you started at all than you&#39;d be at the 99% mark, even though the 99% mark is so much closer to being complete.  In fact, the almost-complete state is a sort of worst-case scenario where you&#39;ve spent the most money/time possible and reaped the least amount of benefit.  Where 80/20 distributions reap quite a lot of rewards for very little effort upfront, all-or-nothing scenarios reap no reward whatsoever until effort meets a specific criteria.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/aonwaste-377w.webp 377w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;all-or-nothing waste&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/aonwaste-377w.jpeg&quot; width=&quot;377&quot; height=&quot;284&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/triagecard-245w.webp 245w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;triage card&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/triagecard-245w.jpeg&quot; width=&quot;245&quot; height=&quot;207&quot; /&gt;&lt;/picture&gt;
There are lots of examples of this in the real world too.  Medical triage sometimes considers this trade-off especially when resources are constrained like in wars or other scenarios with massive casualties.  Medical professionals will prioritize spending their time not necessarily on the people closest to death, but the people that are close to death &lt;em&gt;that have a reasonable chance of being saved&lt;/em&gt;.  Any particular person&#39;s survival is an all-or-nothing proposition. It&#39;s a brutal trade-off, but of course the medical professionals know that if they don&#39;t think they can save a person, they should instead spend their efforts on the other urgent cases that have a better chance; the goal afterall is to maximize lives saved.  In the real world, probabilities about outcomes are never certain either so I&#39;m sure this makes these trade-offs even more harrowing.  (Interestingly, if a triage system like this allows 80% of the affected population to survive by prioritizing 20% of them, the effort on the population as a whole conforms to the Pareto Principle)&lt;/p&gt;
&lt;h2&gt;The All-or-Nothing Principle and Software Development&lt;/h2&gt;
&lt;p&gt;Fortunately for me, I work in software development where being inefficient (at least in the product areas I work in) doesn&#39;t cost anyone their life.  All-or-nothing scenarios actually exist in dozens of important software development scenarios though.&lt;/p&gt;
&lt;p&gt;Of all the scenarios, I don&#39;t think any has shaped the practices and processes of software development in the last 25 years as much as the all-or-nothing scenario of &amp;quot;shipping&amp;quot; or &amp;quot;delivering&amp;quot; product to actual users.  The reason for that is that software only gets results when it&#39;s actually put in front of users.  It really doesn&#39;t matter how much documenting, planning, development, or testing occurs if the software isn&#39;t put in front of users.&lt;/p&gt;
&lt;p&gt;This specific all-or-nothing scenario in software is particularly vicious because of gnarly problems on both sides of the &amp;quot;distribution&amp;quot;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Expectations of the effort required to get to a shippable state can be way off.  You never actually know until you actually ship.&lt;/li&gt;
&lt;li&gt;Expectations of the effectiveness of the software to meet our goals (customer value, learning, etc) can be way off.  Will users like it?  Will it work?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Where more linear effort-result distributions (including even 80/20 distributions) get you results and learning along the way, and a smoother feedback cycle on your tactics, all-or-nothing scenarios offer no such comforts.  It&#39;s not until the software crosses the threshold into the production environment that you truly know your efforts were not in vain.  With cost and expected value being so very difficult to determine in software development the prospects become so much more difficult/risky.  These are the reasons that a core principle of the agile manifesto is that &lt;a href=&quot;http://agilemanifesto.org/principles.html&quot;&gt;&amp;quot;Working software is the primary measure of progress.&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It should be no surprise then that one of the best solutions that we&#39;ve come up with is to try to get clarity on both the cost and expected value as early as possible by shipping as early as possible.  Ultimately shipping as early as possible requires shipping as little as possible, and when done repeatedly this becomes &lt;a href=&quot;https://continuousdelivery.com/&quot;&gt;Continuous Delivery&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pushing to cross the release threshold often leads us to massive waste reduction:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/limitedwaste-447w.webp 447w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;limited waste&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/limitedwaste-447w.jpeg&quot; width=&quot;447&quot; height=&quot;300&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Users get value delivered to them earlier, and the product development team gets learnings earlier that in turn lead to better more valuable solutions.&lt;/p&gt;
&lt;p&gt;All of this of course depends on how inexpensive releasing is.  In the above scenario, we&#39;re assuming it&#39;s free, and it can be virtually free in SaaS environments with comprehensive automated test suites.  In other scenarios, the cost of release weighs more heavily.  For example, mobile app users probably don&#39;t want to download updates more often than every 2-4 weeks.  Even in those cases, you probably want a proxy for production release, like beta users that are comfortable with a faster release schedule.&lt;/p&gt;
&lt;p&gt;We often find ways to release software to smaller segments of users (beta groups, feature toggles, etc) so we can both reduce some of the upfront effort required (maybe the software can&#39;t handle all the users under full production load, isn&#39;t internationalized for all locales or doesn&#39;t have full brand-compliant polish) but also get us seeing some value immediately so we can extrapolate as to what kind of value to ultimately expect.  The criteria of even releasing to one user has a surprising ability to force the unveiling of most of the unknown unknowns that must be confronted for releasing to all users, and so it&#39;s a super-valuable way of converging on discovering the actual cost for delivering to all users.  I&#39;ve personally found these practices to be absolutely critical to setting the proper expectations about cost/value of a software project and delivering reliably.&lt;/p&gt;
&lt;p&gt;Furthermore, there is a lot more to learning early than just the knowledge gained.  Learning early means you have the opportunity to actually change what you expected to deliver based on things you learned.  It means that the final result of all this effort is actually closer to the ideal solution than the one that loaded more features into the release without learning along the way.&lt;/p&gt;
&lt;h2&gt;Navigating All-or-Nothing Scenarios&lt;/h2&gt;
&lt;p&gt;Again, the benefit of identifying All-or-Nothing scenarios is that there are particular ways of dealing with them that are often more effective than solutions that would be common with other types of scenarios (like 80/20 scenarios).  I&#39;ll try to dig into a few in more detail now.&lt;/p&gt;
&lt;h3&gt;Try to make them less all-or-nothing&lt;/h3&gt;
&lt;p&gt;We&#39;ve seen from above how continuous delivery breaks up one all-or-nothing scenario into many, thereby reducing the risk and improving the flow of value.&lt;/p&gt;
&lt;p&gt;More theoretically, it&#39;s best to try to change unforgiving all-or-nothing scenarios into more linear scenarios where possible.  That completely theoretical bridge builder could consider building single lane bridges, or cheaper, less heavy-duty bridges that restrict against heavier traffic, or even entirely different river crossing mechanisms.  These are just examples for the sake of example though... it&#39;s probably pretty obvious by now that I know nothing about building bridges!&lt;/p&gt;
&lt;p&gt;Software is much more malleable and forgiving than steel and concrete, so us software developers get a much better opportunity to start with much lighter (but shippable) initial passes and to iterate into the better solution later.  Continuous delivery, the avoidance of &lt;a href=&quot;http://svpg.com/big-bang-releases/&quot;&gt;Big-Bang releases&lt;/a&gt;, is an example of this.&lt;/p&gt;
&lt;h3&gt;Minimize everything except quality&lt;/h3&gt;
&lt;p&gt;In all-or-nothing scenarios, reducing the scope of the effort is the easiest way to minimize the risk and the ever-increasing waste.  It can be tempting sometimes to consider also reducing quality efforts as part of reducing the scope, but I&#39;ve personally found that reducing the quality unilaterally often results in not actually releasing the software as intended.  The result is that you leave a lot of easy value on the table, don&#39;t capture the proper learnings early, and set yourself up to be interrupted by your own defects later on as they ultimately need to be addressed.  If you don’t really care about the quality of some detail of a feature, it’s almost always better to just cut that detail out.&lt;/p&gt;
&lt;h3&gt;Realize that time magnifies waste&lt;/h3&gt;
&lt;p&gt;For the types of work that need to be complete before the core value of an endeavour can be realized, there&#39;s not only a real cost to how long that endeavour remains incomplete, but the more it becomes complete without actually being completed, the more it costs.  In classical &lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_manufacturing&quot;&gt;Lean&lt;/a&gt; parlance, this is called &amp;quot;inventory&amp;quot;.  Like a retail shoe store holding a large unsold shoe inventory in a back storeroom (it turns out that selling a shoe is generally an all-or-nothing scenario too!), effort in an all-or-nothing scenario has costs-of-delay.  A shoe store&#39;s costs-of-delay include paying rent for a back store-room and risking buying shoes it can&#39;t sell.  It&#39;s for this reason that &lt;a href=&quot;http://www.toyota-global.com/company/vision_philosophy/toyota_production_system/just-in-time.html&quot;&gt;Toyota employs a method called &amp;quot;Just-in-time&amp;quot; production&lt;/a&gt;.  It&#39;s the cornerstone of &lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_manufacturing&quot;&gt;Lean manufacturing&lt;/a&gt; (that has coincidentally also had a huge influence on software development!).&lt;/p&gt;
&lt;p&gt;In the case of software, larger releases mean more effort is unrealized for longer.  This results in less value for the user over time and less learning for the company.  If you can imagine a company that only releases once a week, high-value features (or bug fixes) that are completed on Monday systematically wait 4 days before users can get value from them.  Any feature worth building has a real cost of delay.&lt;/p&gt;
&lt;p&gt;Similarly, more parallel work in progress at once means there&#39;s multiple building inventories of unfinished work.  If a team can instead collaborate to reduce the calendar time of a single most-valuable piece of work, this waste is greatly reduced.&lt;/p&gt;
&lt;h3&gt;Stay on the critical path&lt;/h3&gt;
&lt;p&gt;In all-or-nothing scenarios, it&#39;s crucial to be well aware of the critical path, the sequence of things necessary to get you to the &amp;quot;all&amp;quot; side of an all-or-nothing scenario.  These are the things that will affect calendar time and affect how quickly you learn from users and deliver value.  In software engineering, this is often called the &lt;a href=&quot;http://www.agiledevelopment.org/agile-talk/111-defining-acceptance-criteria-using-the-steel-thread-concept&quot;&gt;steel thread&lt;/a&gt; solution.  If you find yourself prioritizing non-critical path work over critical path work (which is common if you&#39;re not ever-vigilant), you&#39;d do well to stop and get yourself back on track.&lt;/p&gt;
&lt;h3&gt;Pick your battles!&lt;/h3&gt;
&lt;p&gt;If you&#39;re faced with an all-or-nothing scenario, and you know or come to realize that you can&#39;t make the 100% effort required, the most productive thing you can do is to not even try.  Like the 99% complete bridge, your efforts will just be pure waste.&lt;/p&gt;
&lt;p&gt;Sometimes this can be extremely hard.  It&#39;s why the term &lt;a href=&quot;https://en.wikipedia.org/wiki/Death_march_(project_management)&quot;&gt;death march&lt;/a&gt; exists for software projects and project management in general.  People just have a really hard time admitting when a project cannot succeed, even when they know so intellectually.  It can be particularly difficult when the project has already had effort spent on it, due to &lt;a href=&quot;https://en.wikipedia.org/wiki/Sunk_cost#Loss_aversion_and_the_sunk_cost_fallacy&quot;&gt;sunk cost fallacy&lt;/a&gt;, but that doesn&#39;t change the proper course of action.&lt;/p&gt;
&lt;p&gt;If you find yourself in a truly unwinnable all-or-nothing scenario, it&#39;s best to forgive yourself for not pursuing that project anymore and to put your efforts/resources somewhere with better prospects.  It&#39;s not quitting -- it&#39;s focusing.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>So You Want to be a Manager?</title>
		<link href="/posts/2017-03-06-so-you-want-to-be-a-manager/"/>
		<updated>2017-03-06T19:56:05Z</updated>
		<id>/posts/2017-03-06-so-you-want-to-be-a-manager/</id>
		<content type="html">&lt;p&gt;&lt;sup&gt;Special thanks to my colleagues Sam Chaudhary, Lexi Ross and Stuart
Reavley for feedback/criticism!&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I’m not a management guru, and I’ve never taken a management class.  I have done some management, and a hell of a lot more coaching (which is often more powerful than traditional management) though, and I’ve worked with and for managers of varying degrees of effectiveness and I’ve picked up a few things that I’ve seen work really well.&lt;/p&gt;
&lt;p&gt;While I’ve got a lot of experience with management of technical systems, I’m really just going to talk about the management of people here as if it’s the only type of management.  It certainly isn’t, but it’s important enough to attempt to discuss separately.&lt;/p&gt;
&lt;p&gt;Management is sometimes a title, but it’s more important that you think of it as a responsibility.  It’s the responsibility to be effective in the larger organization.&lt;/p&gt;
&lt;p&gt;Let’s break that down further: being effective means achieving the desired results for a given endeavour.  When you’re not a manager, you can often get away with just trying hard and waiting for someone else to correct your course when the results aren’t sufficient (though I hope it’s obvious later that I don’t suggest this).  Conversely, managing requires watching results tirelessly and changing tactics that aren’t working until they work.&lt;/p&gt;
&lt;h2&gt;Congratulations, You’re Hired!&lt;/h2&gt;
&lt;p&gt;You’re already in a management position: No matter who you are, you’re in charge of managing yourself, and the world is constantly deciding how it values you based on your ability to be an effective person.  Even if you were to become a hermit living on a remote island somewhere, you have to constantly be considering your effectiveness at how you spend your day in order to survive on a daily basis.  When you see your shoelace untied and you tie it back up, that’s self-management.  Before you can manage endeavours that involve other people, you’ll want to make sure you’re reasonably good at managing yourself.&lt;/p&gt;
&lt;h2&gt;Managing Without Being a Manager&lt;/h2&gt;
&lt;p&gt;A team can successfully be self-managing in varying degrees, or a team can be managed by a single individual.  My preference has always been to lean as hard on the team as possible to be self-managing but regardless, “management” as a responsibility (ensuring effectiveness) must happen.&lt;/p&gt;
&lt;p&gt;It is also possible to manage sideways and to manage up.  This means that you are ensuring that management is happening regardless of your title.  At any company I’ve seen, people that do this successfully (they’re effective and not an asshole) are the natural choices for management roles, and they get them much more often.  You have to constantly pick high-value problems, and work within your organization to solve them.&lt;/p&gt;
&lt;p&gt;The easiest way to start trying to manage up is to be part of your own solutions.  When you find a problem that you can’t solve yourself and want to bring it to your manager, bring some potential solutions too.&lt;/p&gt;
&lt;p&gt;Part of managing is finding your own high-value problems to solve.  More commonly this is called “taking initiative”.  If you’re waiting for someone else to give you the opportunity to “take initiative”, you’ve got a fundamental misunderstanding of what “taking initiative” means.&lt;/p&gt;
&lt;p&gt;People that “want to be a manager” without having previously managed sideways or up are continuously overlooked for that role.  If you can’t be successful at this without a title, you’re probably not going to be successful at it with a title either.  Management isn’t for everyone; it often means a bunch of administration, bureaucracy, and conflict.&lt;/p&gt;
&lt;h2&gt;7 Core Principles&lt;/h2&gt;
&lt;p&gt;There are 7 principles that I think are important to pursue constantly and relentlessly to achieve effective management.  Theoretically none of these are actually necessary for delivering results, but I’ve never seen a team consistently deliver results without them.&lt;/p&gt;
&lt;h3&gt;Integrity&lt;/h3&gt;
&lt;p&gt;Help the team identify and adhere to team values and goals.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Do what you say and say what you do.  Relentlessly change what you’re doing to match what you’re saying you’re doing, or change what you’re saying you’re doing to match what you’re doing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Be trustworthy and internally consistent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure that the entire team is acting as a cohesive unit.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reliability&lt;/h3&gt;
&lt;p&gt;Reliability means rejecting responsibilities that you can&#39;t be successful at.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When you find you’ve got a responsibility that you can’t fulfill, raise the issue externally immediately.&lt;/li&gt;
&lt;li&gt;If you find this is happening repeatedly, figure out why and stop it.&lt;/li&gt;
&lt;li&gt;When you find that the organization is exerting pressures on the team that are counter-productive, defend the team by fighting to create space for it to be productive and happy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Alignment&lt;/h3&gt;
&lt;p&gt;Ensure the company and product vision, mission, and the strategy to achieve them are unambiguous, well known and widespread.&lt;/p&gt;
&lt;p&gt;Work tirelessly to ensure buy-in from team-members, whether that involves changing minds or changing goals.&lt;/p&gt;
&lt;p&gt;Two important tips for easier buy-in:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make sure people know WHY the goals are what they are.  Even if they’re happy to work on any goals, the reasoning behind them can make them much more effective.&lt;/li&gt;
&lt;li&gt;Getting people’s input on goals is the easiest way to get buy-in, and a great way to get better goals.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Transparency&lt;/h3&gt;
&lt;p&gt;Ensure progress and status on the goals are well known and widespread.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ALWAYS keep interested parties up-to-date.  Saying “I have no update” is almost always a crucial update.&lt;/li&gt;
&lt;li&gt;Don&#39;t be surprising.  ALWAYS ask yourself &amp;quot;Would the current state of our progress be a surprise to interested parties?&amp;quot;.&lt;/li&gt;
&lt;li&gt;Favour processes, practices, systems where transparency is built in, so it is less tedious (Nobody wants to do manual status reports, and that dislike is often an impediment to achieving transparency).&lt;/li&gt;
&lt;li&gt;Make failures or difficulties transparent to the larger organization, including your efforts to solve them.&lt;/li&gt;
&lt;li&gt;Effective communication is the key.  Ensuring that the audience has actually understood it as easily as possible is critical.  Do not waste your time writing documents/memos that people don’t read or don’t understand.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Continuous Improvement&lt;/h3&gt;
&lt;p&gt;Support continuous improvement in processes and practices.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regularly revisit the current practices and processes and look for ways to improve.&lt;/li&gt;
&lt;li&gt;Throw out practices and processes that cost more than you get from them.&lt;/li&gt;
&lt;li&gt;Revisit practices and processes after large projects or new problems.&lt;/li&gt;
&lt;li&gt;Consider ways to double down on successes and reduce failures.&lt;/li&gt;
&lt;li&gt;Consider not only prevention of failures, but also mitigation of failures when they occur anyway.&lt;/li&gt;
&lt;li&gt;Find ways to measure success and failure and make it more constantly obvious to everyone so they can adjust faster.&lt;/li&gt;
&lt;li&gt;In general “try harder next time” is a recipe for repeated failure.  Think of ways to try &lt;em&gt;differently&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Empowerment&lt;/h3&gt;
&lt;p&gt;Ensure that the team is set up for success and motivated.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Often this includes absolutely crucial human issues like staffing, team composition, interpersonal conflicts, and individual compensation.&lt;/li&gt;
&lt;li&gt;Happy, well-supported teams are effective teams.  Continuously poll the team to find out how to better support them.&lt;/li&gt;
&lt;li&gt;You’ll need social and emotional intelligence to tackle this, and there’s no shortcut around it.&lt;/li&gt;
&lt;li&gt;People are set up for failure when their responsibility in a given situation exceeds their ability and control in that situation.  Root out these situations and rectify them immediately.&lt;/li&gt;
&lt;li&gt;Be gracious, thankful, and celebratory where warranted.  Genuine appreciation is a powerful motivator.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Autonomy&lt;/h3&gt;
&lt;p&gt;Avoid being a bottleneck by delegating all possible responsibilities back to the teams.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It’s exceedingly difficult for one person to beat the ideas and efforts of an entire team, so it’s foolish to not promote as much shared-responsibility and autonomy as possible for the capabilities of the team.  Coaching (as opposed to command-and-control management) is the extreme logical conclusion of this.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fix things within your realm of capability. Raise all other issues (ideally with possible solutions) where possible.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;And with all that said...&lt;/h2&gt;
&lt;p&gt;Usually when I’ve been ineffective (which occurs to some degree on a daily basis), I’ve found that it’s because I’ve failed to achieve one of the above principles.  I still struggle with all of these quite regularly myself, and I’m not sure there’s ever a point where they’re “mastered”.&lt;/p&gt;
&lt;p&gt;Most of these principles can and should be applied to sideways or upward management as well.  Also, see how many you can apply to yourself; at the very least you’ll be a better teammate.&lt;/p&gt;
&lt;p&gt;Ultimately there are no points awarded for effort.  Effectiveness requires actual results, so even if these principles aren’t getting success for you, it’s your responsibility to throw them out and come up with better ones.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Quality Feedback Loop</title>
		<link href="/posts/2017-01-04-the-quality-feedback-loop/"/>
		<updated>2017-01-15T05:22:07Z</updated>
		<id>/posts/2017-01-04-the-quality-feedback-loop/</id>
		<content type="html">&lt;p&gt;A lot of engineering management and product development process conversation tends to be based on a fundamental assumption that product quality and development speed are always opposing forces.  Time and again however I find myself learning and relearning that speed and quality can instead be symbiotic and improving one can also improve the other.  These win-win scenarios are actually everywhere as long as you&#39;ve got your mind open to the fact that they&#39;re possible.&lt;/p&gt;
&lt;p&gt;One place where I think that this is obvious is the multiple feedback loops around quality.  New features go through these loops over and over and so it&#39;s hugely important to optimize them if you want to ship software quickly.&lt;/p&gt;
&lt;p&gt;There is also a sometimes argued axiom in software development that bugs found sooner are often the cheapest / fastest to fix.  I do agree that the empirical data on the subject is a little light, but I think it follows naturally from the fact that longer feedback loops make systems harder to manage and reason about.  For example, if your only quality measure for anything you do is customer reports and you do nothing else for quality whatsoever, solving issues is extremely time-consuming and error-prone.&lt;/p&gt;
&lt;p&gt;So lets start with that outer loop and list a bunch of other common quality feedback loops:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Customer reported bug&lt;/li&gt;
&lt;li&gt;Logged error seen during regular inspection&lt;/li&gt;
&lt;li&gt;Error alert happening when a defect occurs&lt;/li&gt;
&lt;li&gt;Defect Found by testers before launch&lt;/li&gt;
&lt;li&gt;Broken CI build&lt;/li&gt;
&lt;li&gt;Broken test suite&lt;/li&gt;
&lt;li&gt;In-Editor error&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Customer reported bugs&lt;/h3&gt;
&lt;p&gt;These are of course the most expensive; The feedback loop is largest here.  If you&#39;re maintaining a large feature set, it&#39;s possible that you don&#39;t remember the details of how a feature works, or even that the software has that feature at all.  These defects also come back at inopportune times and interrupt you while you&#39;re working on other tasks.  You&#39;re likely also on a team so the defect probably isn&#39;t even one that you had any hand in.  Lacking all of this context makes solving the defect all the more difficult and all the more time-consuming.&lt;/p&gt;
&lt;p&gt;There&#39;s the obvious cost to the user as well.  Production defects can cost you customers, or in extreme cases can even lead to lawsuits.&lt;/p&gt;
&lt;p&gt;Ultimately you want to find a way to shorten the feedback loop, which usually means trying to move this to an early feedback loop.&lt;/p&gt;
&lt;p&gt;As long as the measure that tightens the feedback loop is cheaper effort-wise than the defect, you&#39;ve got improved speed and quality.  It almost always is cheaper though because these loops are run many times for each feature (though there are some common types of loops that are especially expensive, like manual human regression testing).&lt;/p&gt;
&lt;h3&gt;Logged errors and metrics seen by regular log inspection&lt;/h3&gt;
&lt;p&gt;Production logs are a critical part of making an application self-reporting.  If you&#39;re regularly checking your logs (and keeping the signal to noise ratio in them high) there&#39;s a good chance of finding production defects before users do.&lt;/p&gt;
&lt;p&gt;That&#39;s great because it can catch things weeks or months before customer reports do sometimes, and that faster feedback loop means you&#39;re more likely to remember the affected area of code.&lt;/p&gt;
&lt;p&gt;Usually for these types of issues though, we can go one level deeper...&lt;/p&gt;
&lt;h3&gt;Error alert happening when a defect occurs&lt;/h3&gt;
&lt;p&gt;If you have a system set up where logged errors increment a metric, you can find a way to put an alert on a threshold for that metric.  There are a bunch of services you can integrate for this functionality, or you can run your own &lt;a href=&quot;https://www.elastic.co/products/kibana&quot;&gt;kibana &lt;/a&gt; service.  The point is that your production systems can be self-reporting: they can tell you when there are problems, thus tightening the feedback loop further.&lt;/p&gt;
&lt;p&gt;This is also super useful, because it really helps your mean-time-to-repair.  Minimizing the amount of time it takes to find a defect in production also helps minimize the amount of time a user is affected by that defect.&lt;/p&gt;
&lt;h3&gt;Defect Found by testers before launch&lt;/h3&gt;
&lt;p&gt;Unfortunately I think the most common way of finding defects is manual human inspection.  It&#39;s a natural choice of course, but it&#39;s by far the slowest and most error-prone.  It&#39;s a valid method if you can&#39;t solve your issues otherwise, but the repeated compounded cost including the time to test, and the way it affects your ability to quickly deliver software shouldn&#39;t be ignored.  When a good automated test is possible, it&#39;ll be both faster and less error-prone.  I work on a production system that has ~4500 automated tests that run dozens of times per day.  Having humans do that is impossible.&lt;/p&gt;
&lt;p&gt;With all that said, these are still defects that are found earlier than in production and so they save your customers from the defect, and they lead to a tighter feedback loop.  It&#39;s just that this feedback loop is so expensive that as a developer you really shouldn&#39;t be relying on it the way you can rely on even tighter feedback loops.&lt;/p&gt;
&lt;h3&gt;Broken CI build&lt;/h3&gt;
&lt;p&gt;The first line of defence after your work leaves your machine is the CI build.  Any quality measures you have in your build process (which I&#39;ll get into shortly) should be part of this build and they&#39;ll verify that what you&#39;ve got in the main branch is ready to move on to.  If the main branch doesn&#39;t pass the same barrage of quality measures as the local machine build is supposed to, it certainly shouldn&#39;t move past this step on its way to production.  It could be that this is your last line of defence before affecting customers, or it could be that you have a human tester that can at least know not to bother testing a broken build (Ideally, passing your quality measures is necessary for any build-artifact to exist at all so that testing a broken a build isn&#39;t even an option).&lt;/p&gt;
&lt;p&gt;Of course this is an easy savings to your users and any human testers you might have, but it&#39;s still not the tightest feedback loop you can have.  It&#39;s also an expensive measure to your team-mates; it means there&#39;s a period of time where the main branch is unusable, blocking their work.&lt;/p&gt;
&lt;p&gt;CI builds really should be doing the same thing
as a local developer machine&#39;s build so that developers have a
reasonable assurance that if they run the build locally and it works, it
should pass in CI as well.  Let&#39;s talk about some of the quality measures
that should go into a build.&lt;/p&gt;
&lt;h3&gt;Broken test suite&lt;/h3&gt;
&lt;p&gt;Automated tests can make up a feedback loop that is almost instant.  On most platforms that I&#39;ve worked, testing is fast enough that a single test almost always takes less than a second.  I work on a codebase with around ~4500 automated tests that runs in about 2 minutes (albeit due to herculean efforts at parallelization).  The speed of these is super important because it makes the feedback loop short and helps prevent developers from relying on CI as a personal build machine.&lt;/p&gt;
&lt;p&gt;Comprehensive test suites are expensive!  We spent a lot of time maintaining ours, adding to it, and ensuring it stays fast.  It&#39;s almost certainly our most effective quality measure too though.&lt;/p&gt;
&lt;p&gt;Integration tests tend to be faster to write, because they test more things at
once, but when they do fail, you&#39;ve usually got some extensive debugging
to do.  Unit tests tend to take more time to write if you want the same
level of coverage, but when they fail, you usually know exactly where
the issue is.  These are things to factor into your feedback loop
considerations.&lt;/p&gt;
&lt;p&gt;There are still tighter feedback loops that are cheaper to maintain though and those should be relied on where possible.&lt;/p&gt;
&lt;h3&gt;In-editor error&lt;/h3&gt;
&lt;p&gt;Any type of static analysis that can be performed in your editor/ide, like linting or
static type-checking is an even tighter feedback loop still.  Any problems are evident instantly while you&#39;re still in the code and it indicates to you exactly where.  This is an extremely fast feedback loop that you&#39;ll probably want to employ where it&#39;s possible and it makes sense.&lt;/p&gt;
&lt;p&gt;I don&#39;t have a tighter feedback loop than this, but in some cases you
can still do better...&lt;/p&gt;
&lt;h3&gt;Abstraction that simply makes the error impossible&lt;/h3&gt;
&lt;p&gt;If it&#39;s possible to use tools/abstractions that make the defect impossible, that beats all the feedback loops.&lt;/p&gt;
&lt;p&gt;Some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Avoid off-by-one errors in for loops by using iterator functions, or functional paradigms that give you filter(), map() and reduce().&lt;/li&gt;
&lt;li&gt;Avoid SQL injection by using prepared statements.&lt;/li&gt;
&lt;li&gt;Avoid Cross-site scripting attacks by using an html template language that automatically escapes output.&lt;/li&gt;
&lt;li&gt;Avoid bugs from unexpected changes in shared objects by using immutable data structures.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Working through the levels&lt;/h2&gt;
&lt;p&gt;These levels all form a sort of &amp;quot;onion&amp;quot; of quality feedback loops where
the closer you get to the middle, the cheaper the defect is.&lt;/p&gt;
&lt;p&gt;Thinking this way, you can easily see how if your users are reporting an issue caused by a sql injection attack, you would ideally work to push that problem to tighter and tighter feedback loops where possble.  If you can make it show up in logs or alerts, you can fix it before users report it.  If you can have testers test for it, you can fix it before users are subjected to it.  If you can write some unit tests for it, you can save your testers from having to bother.  If you can use the right level of abstraction (prepared statements / parameterized queries in this case), you can eliminate the class of error entirely.&lt;/p&gt;
&lt;p&gt;Delivering high-quality software quickly means looking at the most expensive, time-consuming or frequent classes of errors and systematically pushing them to a lower-rung in this onion of quality feedback loops.  With a little situational awareness and a little creativity it&#39;s almost always possible and leads to huge cost and time-savings over the long haul.&lt;/p&gt;
&lt;p&gt;This is just one of the many ways that I think the speed vs quality dichotomy in software engineering is a false one.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Atomic Team Pattern</title>
		<link href="/posts/2016-11-16-the-atomic-team-pattern/"/>
		<updated>2016-11-16T18:11:16Z</updated>
		<id>/posts/2016-11-16-the-atomic-team-pattern/</id>
		<content type="html">&lt;p&gt;One pattern that I&#39;ve seen work well in software development management is one I call The Atomic Team pattern.  Basically what it means is that ideally the smallest indivisible unit for management is the team.  I think it&#39;s a cornerstone of healthy service-oriented architecture, but it&#39;s rarely talked about because it&#39;s on the more touchy-feely and less-technical side.&lt;/p&gt;
&lt;p&gt;Management of such a team ends up primarily involving:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Communicating expectations and objectives&lt;/li&gt;
&lt;li&gt;Ensuring the team has what it needs to be successful&lt;/li&gt;
&lt;li&gt;Handling (ideally) infrequent interpersonal issues that the team can&#39;t handle themselves.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Disadvantages&lt;/h2&gt;
&lt;p&gt;There are a few disadvantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Teams can take some time to form.&lt;/li&gt;
&lt;li&gt;Some developers don&#39;t have the interpersonal skills for this.&lt;/li&gt;
&lt;li&gt;There are always interpersonal issues to consider.&lt;/li&gt;
&lt;li&gt;Teams are not resilient to reorganization.&lt;/li&gt;
&lt;li&gt;Will individuals on the team be happy with their role on the team and the type of work that the team takes on?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Advantages&lt;/h2&gt;
&lt;h3&gt;Requires less management&lt;/h3&gt;
&lt;p&gt;Let the team self-organize around tasks instead of being command-and-control orchestrated.  Drop prioritized work into the team work queue and they can figure out who does what and when based on their own availabilities and skillsets.  Team members can hold each other accountable for the team objectives.&lt;/p&gt;
&lt;h3&gt;Lowered &lt;a href=&quot;https://en.wikipedia.org/wiki/Bus_factor&quot;&gt;Bus-Factor&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Cross-functional teams often have more than one person capable of doing a given task.  This keeps the queue moving even when someone is sick or on vacation.&lt;/p&gt;
&lt;h3&gt;Less Stress for Team Members&lt;/h3&gt;
&lt;p&gt;On a well-formed team, team members can count on one another for help and support.  Vacations and sick days rarely affect a delivery timeline much at all.  No one needs to be the only one responsible for stressful issues, outages, deadlines, or un-fun work.  The increased autonomy in &lt;em&gt;how&lt;/em&gt; the team executes on its objectives is highly motivating.&lt;/p&gt;
&lt;h3&gt;Better cross-pollination of knowledge and skills&lt;/h3&gt;
&lt;p&gt;Team members can teach each other skills and organizational knowledge so that they level each other up.  My best career development has come from working with brilliant peers.&lt;/p&gt;
&lt;h3&gt;Better solutions&lt;/h3&gt;
&lt;p&gt;Put simply, two heads are better than one.  The best solutions that I&#39;ve seen in software development are most often devised by a team riffing off each others&#39; ideas with a whiteboard.&lt;/p&gt;
&lt;h3&gt;Long-term group ownership of codebases and services&lt;/h3&gt;
&lt;p&gt;In reality, software doesn&#39;t just get deployed and run in perpetuity without engineering intervention.  Even if there aren&#39;t any new features to add, there are hardware issues, bugs, security issues, and software upgrades.  When teams own the software they write forever, they write better software, they monitor it better, and they manage it more easily.  Without team-ownership, you&#39;re often left looking for someone to work on some long forgotten service when it inevitably needs work.&lt;/p&gt;
&lt;p&gt;The result of these advantages is an software development organization that scales much more easily.&lt;/p&gt;
&lt;h2&gt;Anti-patterns when Managing Teams&lt;/h2&gt;
&lt;h3&gt;Team-Busting&lt;/h3&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;adding / removing the members of the team often&lt;/li&gt;
&lt;li&gt;loaning out team-members for other non-team objectives&lt;/li&gt;
&lt;li&gt;holding individuals responsible for results of team objectives&lt;/li&gt;
&lt;li&gt;creating competition within the team&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These types of activities remove the mutual trust and comradery from the team and stop the team from forming beyond &amp;quot;just a group of people&amp;quot;.  This stops the members from working as closely together as they could otherwise and undermines a lot of the advantages of having a team.&lt;/p&gt;
&lt;h3&gt;Over-Management / Micro-Management&lt;/h3&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dictating who on the team does what&lt;/li&gt;
&lt;li&gt;becoming a communication conduit for two team members when they can just talk to each other&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These types of activities are mostly unnecessary except in extreme situations so they&#39;re a time-sink and create a bottleneck that makes scaling your organization harder.  Additionally, a manager can often make much worse decisions in these areas than the team members because they&#39;re the people closest to the team and the work.&lt;/p&gt;
&lt;h3&gt;Not Respecting Communication Overhead&lt;/h3&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Choosing teams of similarly skilled individuals (eg &amp;quot;The Frontend Team&amp;quot;).  Teams that are not cross-functional often can&#39;t deliver their own solutions without a lot of communication with other teams.&lt;/li&gt;
&lt;li&gt;Choosing teams that are too large.  Teams that are too large spend too much time coordinating efforts and coming to consensus on issues.&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>We&#39;re in the Stone Age of Software Engineering Management</title>
		<link href="/posts/2015-06-14-were-in-the-stone-age-of-software-engineering-management/"/>
		<updated>2015-06-15T03:20:37Z</updated>
		<id>/posts/2015-06-14-were-in-the-stone-age-of-software-engineering-management/</id>
		<content type="html">&lt;p&gt;Obviously from the title, I think software engineering management is in a Stone Age.  Before I get into my arguments though, I&#39;d like to say that this isn&#39;t really about any particular manager or managers that I&#39;ve had in the past.  It&#39;s really about counter-productive patterns that I&#39;ve seen that I really think we need to evolve from.  I&#39;ve also been responsible for some of these mistakes myself as a manager or technical lead over my years in software engineering, so if this comes off preachy, that&#39;s not the intention.&lt;/p&gt;
&lt;p&gt;There are a few common problems in engineering management that keep us in the Stone Age though, and I&#39;d like to detail some of them.&lt;/p&gt;
&lt;h2&gt;The longer you manage, the less technically competent you become.&lt;/h2&gt;
&lt;p&gt;&amp;quot;Technology is dominated by two types of people: those who understand what they do not manage, and those who manage what they do not understand.&amp;quot; -- &lt;a href=&quot;https://en.wikipedia.org/wiki/Putt&#39;s_Law_and_the_Successful_Technocrat&quot;&gt;Putt&#39;s Law&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s undeniable that knowledge work has some fundamental differences from factory work: there&#39;s never a point where you&#39;ve completely learned how to do your job, and in fact the knowledge required around your job is constantly changing.  For this reason, the longer you&#39;re not developing software, the worse you get at it.  Being able to type code is only tangentially necessary for software development.  The real job is making decisions about how the software should work.&lt;/p&gt;
&lt;p&gt;This is one of the few cases in industrialized production where the worker quite regularly knows more about their job than their manager.  And if the manager does happen to know more, the gap between them will be constantly narrowing.&lt;/p&gt;
&lt;p&gt;The impact of this fact is pretty wide-reaching.  It means that a manager is generally not going to be useful for their technical competence, or at least that their usefulness will be waning.  In my career I have rarely met exceptions to this rule.&lt;/p&gt;
&lt;h2&gt;Management is viewed as a promotion and not a distinct role with a separate set of skills.&lt;/h2&gt;
&lt;p&gt;I&#39;d like to propose instead that management is a distinct role that requires a different set of skills, none of which require the ability to make technical decisions (and I&#39;ll get to those later).&lt;/p&gt;
&lt;p&gt;Unfortunately management in the software development industry is looked at much like management in other industrialized production.  Management is widely considered to be &amp;quot;a promotion&amp;quot; that developers should aspire to.  It&#39;s a common expectation that developers at a certain level of seniority (or age) should be moving into management.  There&#39;s a very real pressure from the rest of the world too because they view management as a &amp;quot;higher&amp;quot; position, so you often see developers pushing for this &amp;quot;promotion&amp;quot;, even though they have not acquired the disparate skill-set required of a manager.  The result is that often companies trade excellent developers for terrible managers, and often to the detriment of those developers as well.&lt;/p&gt;
&lt;h2&gt;Management is viewed as an imperative to command and control.&lt;/h2&gt;
&lt;p&gt;It&#39;s common to move people into management based on technical ability, because surely we must need a technical person to make the important technical decisions, right?  That&#39;s certainly the argument that&#39;s most often made to support the management-as-promotion mindset.&lt;/p&gt;
&lt;p&gt;There are huge drawbacks to the manager being &amp;quot;The Decider&amp;quot; in technical matters though (notwithstanding their continually eroding technical ability):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Even extremely technical managers are less likely to have better ideas than their entire team.&lt;/li&gt;
&lt;li&gt;This is not a scalable solution.  Even on a small team, the manager will not have time to make all the decisions because aside from typing, all software development is fundamentally about making decisions.  As the team grows, the manager will be capable of making an ever decreasing number of decisions.  Some managers try to mitigate this by carving out which decisions they will make (the important ones!), but this makes them a process choke-point, and increasingly a productivity net-negative.&lt;/li&gt;
&lt;li&gt;With decision-making being the developer&#39;s primary job, a manager that tries to make decisions is taking away the most interesting part of the job for the developer, and with this their feeling of autonomy, responsibility, accountability and ownership.  The result is that this type of manager is actively and powerfully demotivating their team.  Ironically, command and control managers seem to be the ones most irritated when their team doesn&#39;t self-organize in their absence.  In reality it&#39;s quite a long and difficult cultural change for a &amp;quot;controlled&amp;quot; team to become a self-organizing team and I&#39;ve only seen the presence of a command-and-control manager to be an insurmountable impediment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It certainly doesn&#39;t have to be this way, but many view management not just as a chance to command and control, but also as a &lt;em&gt;responsibility&lt;/em&gt; to command and control.  If the team is allowed to make technical decisions together though, on their own, all of these particular problems can just disappear.  And I would argue that if a manager doesn&#39;t have a team that can be trusted with this responsibility, it is the manager&#39;s responsibility to transform that team.&lt;/p&gt;
&lt;p&gt;Interestingly, it&#39;s a pretty normal refrain from engineers that they want their manager to be technical.  I believe that much of that sentiment comes from an assumption that management is command-and-control by definition, and of course the worst of both worlds would be a non-technical command-and-control manager  (and I whole-heartedly agree).  I also think that if management would instead trust technical decisions to those most close to the work, engineers would be far less likely to care about their manager&#39;s technical competence.&lt;/p&gt;
&lt;h2&gt;Management focuses on enforcing the predictability of software development rather than on mitigating its undeniable unpredictability.&lt;/h2&gt;
&lt;p&gt;Software development is development of complex systems that are, by definition, extremely difficult to predict.  Typically management tries to predict, control, and reprimand.  Given the fact that complex systems are resistant to those types of actions, the effort is largely fruitless and often counter-productive.&lt;/p&gt;
&lt;p&gt;Some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Deadlines are one such mechanism of control.  Despite the fact that engineers are the best people from which to get accurate estimates, it is extremely common for managers to dictate deadlines for fixed-sized projects, and to repeatedly find their team failing to meet them.  For some reason, this repeated failure is not an indication that something has gone wrong management-wise.  Often the team is chastized, over-worked, or reprimanded instead.  Of course the real world will have dates after which delivery of software greatly diminishes its value, but deadlines are simply a thoughtless and reckless way to enforce either minimizing a feature or lowering the level of quality that goes into it (usually the latter).  When a business uses deadlines with a fixed scope of work and quality, it&#39;s willfully ignoring the reality of its team&#39;s capability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Estimation is an example of attempting prediction.  Complex systems are inherently difficult to predict as well, and we&#39;ve all seen evidence of this in our own inaccurate estimates.  The best success we&#39;ve had with improving estimation is to limit the amount of work we bundle up in an estimate which is to say we&#39;ve improved estimation by estimating less.  The sum of a project&#39;s timeframe often ends up being greater than the sum of the timeframes of its parts though, because we often even fail to predict all the pieces of work that are necessary.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Estimates from developers, when treated as self-imposed deadlines, are really no better than deadlines, because prediction of how long a software project will take is so incredibly difficult and developers are rarely given the training or time to do better estimates.  Estimates like this end up being another mechanism of control, but a somewhat more insidious one, because developers will feel like they have no one to blame but themselves for &amp;quot;missed estimates&amp;quot;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reprimanding developers for defects or service outages is another often counter-productive mechanism of control.  As with many complex systems, there is never a single root cause, and the humans and the technology are so inseparably intertwined in the system that it means nothing to conclude &amp;quot;human failure&amp;quot; and reprimand the human.  That&#39;s just not a results-oriented path to improved quality.  I&#39;d never suggest that post-mortems are a waste of time, but they are when conducted in a fashion that stops the investigation at &amp;quot;human failure&amp;quot; or even after a single cause.  Investigations like this result in the workers feeling terrible, and the process as a whole not actually improving.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these management efforts are time-consuming, stressful, and mostly counter-productive (in that they take away from the developer&#39;s time to write software).&lt;/p&gt;
&lt;p&gt;Of course you might reasonably ask how the feasibility of a proposed feature can be assessed without some estimation of its costs, which is a fair question, but an effective manager must realize that the estimate (as well as the scope of the work being estimated) must be continually revisited and revised and the stake holders need to have their expectations continually managed/adjusted.&lt;/p&gt;
&lt;h2&gt;The complex system that the developers create &lt;em&gt;includes&lt;/em&gt; all the people involved.&lt;/h2&gt;
&lt;p&gt;Anytime something happens in the system, it can&#39;t realistically be viewed solely from a technical perspective.  The technical aspects exist in large part because of what developers did or did not do to make them happen.  The interdependencies between people and the technology forms in such a way that most mental models that separate them are not grounded in reality.  There are a few results of this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Developers can&#39;t simply be swapped in and out of the team without significant costs.  They form relationships and interdependencies with both the technology and the other people on the team that are time-consuming and difficult to reform.  This cost can be minimized by having the team regularly push to make itself pan-functional (usually via intra-team mentoring).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Conversely, a developer can have real negative impact on this socio-technological system in many ways, the most detrimental of which is by not acting in a way that&#39;s worthy of the team&#39;s trust.  If a team member regularly refuses (explicitly or implicitly) to act in accordance with the team&#39;s general wishes, that developer must be removed, regardless of some abstract notion of &amp;quot;technical skill level&amp;quot; or how &amp;quot;indispensable&amp;quot; they&#39;ve made themselves.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The team itself requires maintenance.  They need to be encouraged and allowed to regularly take the time to look at their process and practices and decide what steps they should take to improve them.  They need to be supported in their efforts to take those steps.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A high performing engineering team is more valuable than the sum of its highly performing individuals.  A team needs to be cultivated carefully with an eye on creating the desired culture of collaboration and trust.  This is extremely difficult and takes a great deal of time and effort, but it pays off wildly with much smarter decisions and much faster development.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Software development cannot be broken into an assembly line with specification, coding, and testing stages.  All of these things occur and reoccur as necessary.  They are all &amp;quot;development&amp;quot; and there&#39;s nothing to gain by pretending that the task is divisible.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The complex system that the developers create has a lifetime.&lt;/h2&gt;
&lt;p&gt;As a piece of software is used more and more over time, the chances of a user finding a way to put the software in an unexpected state increases.  It&#39;s even common for new bugs to arise in narrowly scoped software that&#39;s over 20 years old.&lt;/p&gt;
&lt;p&gt;Ultimately the only software that doesn&#39;t require maintenance is software that no one uses anymore.  Otherwise, there&#39;s no such thing as completion of a piece of software.  At best you can get a convergence toward completion, assuming the project is narrowly scoped and you can resist feature-creep.&lt;/p&gt;
&lt;p&gt;Unfortunately management typically looks at software development as a series of projects or features with definite endings where there is an expectation that no more work will be necessary at the completion of the &amp;quot;project&amp;quot;, and that the team will be 100% available for the next project.&lt;/p&gt;
&lt;p&gt;This fallacy may or may not lead to completely unrealistic expectations on the first project or two, but as the number of projects &amp;quot;completed&amp;quot; increases over time, the team will become busier and busier maintaining those projects and the team will necessarily get slower and slower.&lt;/p&gt;
&lt;p&gt;There are innumerable counter-measures that can be taken to ease the maintenance of software over time of course, but most of these require management to first realize that this reality exists, and to allow the team to spend the time to take these counter-measures.&lt;/p&gt;
&lt;p&gt;Management that doesn&#39;t realize this often misses the point of spending time on anything that doesn&#39;t yield value immediately.  For example, automated tests are in many scenarios a super valuable way of ensuring regressions don&#39;t creep in.  They often don&#39;t provide enough value to offset their immediate up-front costs, but I&#39;ve rarely seen them not be a net positive over time as they eliminate the need for slower manual testing forever after.  Short-sighted management will be reluctant to make investments like this, and therefore doom the team to lower productivity over the long haul.&lt;/p&gt;
&lt;h2&gt;Goals and priorities are rarely clearly and intelligently set.&lt;/h2&gt;
&lt;p&gt;Goal and priority setting is the absolute number one deliverable that management has for the team.  Unfortunately it is common for management to busy itself with other less productive tasks, often involving micro-management, and to actively disrupt the team&#39;s effort to ensure that goals and priorities are clear.&lt;/p&gt;
&lt;p&gt;Some common ways that management fails at this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;interrupting the team working on the top priority goal to talk about or pursue a lower priority goal&lt;/li&gt;
&lt;li&gt;not ensuring that the team is shielded from lower priority goals from other parts of the organization.&lt;/li&gt;
&lt;li&gt;failing to ensure that work is constantly presented in priority order&lt;/li&gt;
&lt;li&gt;failing to ensure that there is some semblance of reasoning behind the order of priority&lt;/li&gt;
&lt;li&gt;quickly oscillating between priorities frequently keeping a team starting new things, and rarely finishing anything.&lt;/li&gt;
&lt;li&gt;failing to coordinate priorities between teams that have dependencies on one another.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most common failure I&#39;ve seen here is management&#39;s unwillingness to choose a more important goal between two top goals.  It&#39;s fine for management to ask for help from the team in that prioritization, or even for management to pick one randomly (if they&#39;re really so equal, it shouldn&#39;t matter), but what is unacceptable is for management to say &amp;quot;These are our two #1 goals&amp;quot;.  In that case, the team is forced to take over this management responsibility, because any one person can only do one thing at a time.  If the team has not learned to manage that responsibility themselves, they will often be terrible at it.  Some members will be working on one thing and others will be working on the other when just a touch of management could have had them coordinating to get one thing done first and delivering value as soon as possible.  Instead the manager in these scenarios has ensured that value will be delivered in a slower way than what&#39;s optimal.&lt;/p&gt;
&lt;h2&gt;Efforts and Practices are rarely critically examined with any attention to the results.&lt;/h2&gt;
&lt;p&gt;It&#39;s unfortunately extremely uncommon for managers today to pay much attention to the actual results of the team&#39;s effort and the practices that it follows.&lt;/p&gt;
&lt;p&gt;I think that a lot of the reason behind this is that it&#39;s extremely difficult to admit that things aren&#39;t going well when we&#39;ve tied those results to our self-image.  The only thing worse than mistakes though are mistakes that go uncorrected.  Unfortunately the first step to correcting a mistake is to admit it exists.&lt;/p&gt;
&lt;p&gt;Ego can also get in the way and take management off into more interesting (or brag-worthy) endeavours than what&#39;s best for the business.  I&#39;ve seen this happen countless times where teams deliver absolutely nothing while working on the latest in tech.  If the same ego-driven management style reaches high enough into the organization, and the company is profitable enough to support it, it&#39;s easy for a team to get away with this blunder for years (which I&#39;ve also seen).&lt;/p&gt;
&lt;p&gt;Copy-cat or Cargo-cult management is probably the next most common excuse for not examining results.  Often I&#39;ve heard &amp;quot;google does x&amp;quot; or &amp;quot;y is an industry best practice&amp;quot; or even &amp;quot;that&#39;s not Agile&amp;quot; without any discussion of whether a particular practice makes sense for the team&#39;s own particular goals, scenario, or needs.  Often these managers feel that they&#39;re adhering to &amp;quot;best practices&amp;quot; and so the actual results will necessarily be optimal and won&#39;t need to be examined.  I&#39;m definitely a proponent of agile methodologies in general, but saying whether or not something is &amp;quot;Agile&amp;quot; explains nothing about it&#39;s utility to the organization.  There are no sacred practices that should be allowed to escape scrutiny.  Any practice that can&#39;t be shown to be adding value should be canceled immediately.&lt;/p&gt;
&lt;p&gt;It&#39;s common as well when a manager does manage to pay attention to results that his/her methods are extremely flawed.  Probably the most infamous example of this is how managers used to count lines of code to judge the productivity of a developer.  Counting the number of commits is also ridiculously flawed in the same way: they&#39;re missing what it means to be productive in an engineering context entirely.  The least productive engineers are doing things like building needlessly elaborate architectures and suffering from &lt;a href=&quot;https://en.wikipedia.org/wiki/Not_invented_here&quot;&gt;NIH&lt;/a&gt; when they could just use a far better 3rd party library.  Yes, you do need to be able to determine if a developer is productive or not, but that doesn&#39;t mean that that determination can be quantified.  There will be some very important things that you need to measure that aren&#39;t quantifiable, so managers need to be comfortable with qualitative measurements.&lt;/p&gt;
&lt;p&gt;In short, I think it&#39;s pretty common for engineering management to be actively harmful to their team&#39;s speed and their product&#39;s quality.  Because uncorrected management mistakes impact entire teams, it&#39;s quite easy for a manager to have an overall net negative contribution to the organization.  Of course it doesn&#39;t need to be like this, but a lot of the common expectations of management will really need to change first.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Reclaiming Value from Bugs and Outages: Thoughts on Post-Mortems</title>
		<link href="/posts/2015-03-08-reclaiming-value-from-bugs-and-outages/"/>
		<updated>2015-03-08T16:12:23Z</updated>
		<id>/posts/2015-03-08-reclaiming-value-from-bugs-and-outages/</id>
		<content type="html">&lt;p&gt;&lt;sub&gt;(Thanks to Chris Frank and Sam Decesare for the feedback!)&lt;/sub&gt;&lt;/p&gt;
&lt;p&gt;Bugs and outages happen.  If the team can learn from them though, it&#39;s possible to reclaim some of that lost effectiveness, sometimes even to the point that the learning is more valuable than the effectiveness lost.&lt;/p&gt;
&lt;p&gt;The best mechanism I&#39;ve seen to drive that learning is for the team to meet after the outage or defect is no longer an immediate problem and for the team to try to learn from what happened.  This meeting is often called the &lt;a href=&quot;https://codeascraft.com/2012/05/22/blameless-postmortems/&quot;&gt;Blameless Post-mortem&lt;/a&gt;.  These meetings have been the biggest agents of improvement that I&#39;ve ever seen on an engineering team, so if you think you&#39;ll save time by skipping them, you&#39;re probably make a huge mistake.&lt;/p&gt;
&lt;h2&gt;Institute Blamelessness&lt;/h2&gt;
&lt;p&gt;It&#39;s crucial to assume that everyone involved in the issue would&#39;ve avoided it if possible, given the chance again.  It&#39;s natural for people to want to point the finger (sometimes even at themselves) but if the team allows this, it&#39;ll quickly lead to a culture of cover-ups where nothing can be learned because real information about what happened can&#39;t be extracted.&lt;/p&gt;
&lt;p&gt;What&#39;s worse than this is that when you decide who&#39;s responsible, you have no reason to continue to investigate what there is to learn.  It seems obvious that since that person is to blame, if they&#39;re either removed or coerced to try harder next time, the issue won&#39;t reoccur.&lt;/p&gt;
&lt;p&gt;This reminds me of reading about airplane crashes in the news when the airline concludes the cause was &amp;quot;human error&amp;quot;.  That was really the best that that airline could do?  They decided to either ask that human to be better next time, or replaced that human with another human.  There&#39;s really nothing to learn?  No way to improve the aircraft?  No way to improve the process?  No way to improve the environment?  No way to improve the human&#39;s understanding of these?  This is an airline I&#39;d be afraid to fly with.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sidneydekker.com/books/&quot;&gt;Sidney Dekker&#39;s The Field Guide to Understanding Human Error&lt;/a&gt;, an absolutely genius book on the subject, sums it up nicely: &amp;quot;Human error is not the conclusion of an investigation.  It is the starting point.&amp;quot;&lt;/p&gt;
&lt;h2&gt;Look for all the Causes&lt;/h2&gt;
&lt;p&gt;Often these meetings are called RCAs or &lt;a href=&quot;http://en.wikipedia.org/wiki/Root_cause_analysis&quot;&gt;Root-Cause Analysis&lt;/a&gt; meetings, but I try not to call them that anymore, because there never really ever seems to be a single root cause.  Computer systems are complex systems, and so usually multiple things have gone wrong in order for a defect to appear.  &lt;a href=&quot;http://www.kitchensoap.com/2012/02/10/each-necessary-but-only-jointly-sufficient/&quot;&gt;John Allspaw&lt;/a&gt; explains it more succinctly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Generally speaking, linear chain-of-events approaches are akin to viewing the past as a line-up of dominoes, and reality with complex systems simply don’t work like that. Looking at an accident this way ignores surrounding circumstances in favor of a cherry-picked list of events, it validates hindsight and outcome bias, and focuses too much on components and not enough on the interconnectedness of components.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Also make sure you&#39;ve validated your assumptions on these causes.  There&#39;s a powerful tendency to fall prey to &lt;a href=&quot;http://www.sciencedirect.com/science/article/pii/S0925753509000137&quot;&gt;What-you-look-for-is-what-you-find&lt;/a&gt; principle for the sake of expediency and simplicity.&lt;/p&gt;
&lt;h2&gt;Dig deeper&lt;/h2&gt;
&lt;p&gt;It&#39;s usually a good idea to dig deeper than you&#39;d expect when determining how a problem occurred.  One practice that forces a deeper investigation is &lt;a href=&quot;http://en.wikipedia.org/wiki/5_Whys&quot;&gt;The 5 Whys&lt;/a&gt;.  Basically you just ask &amp;quot;why?&amp;quot; for each successive answer until you&#39;ve gone at least 5 levels deep, attempting to find a precursor for any problem and its precursors.  Often in the deeper parts of this conversation, you end up investigating bigger picture problems, like the company&#39;s values, external pressures, and long-standing misconceptions.  These deeper problems often require internal or external social conflicts to be resolved, which often makes them tough, but also high-value.&lt;/p&gt;
&lt;p&gt;A few caveats though:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It can quickly become &amp;quot;The 5 Whos&amp;quot;.  You still want to remain blameless.&lt;/li&gt;
&lt;li&gt;It assumes that there&#39;s a single chain of cause and effect leading to the defect (and there rarely is).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This second reason is the reason I don&#39;t really care for The 5 Whys practice anymore.  John Allspaw&#39;s got some great further discussion about that problem   &lt;a href=&quot;http://www.kitchensoap.com/2014/11/14/the-infinite-hows-or-the-dangers-of-the-five-whys/&quot;&gt;here&lt;/a&gt; as well.&lt;/p&gt;
&lt;h2&gt;Decide on Next Actions as a Team&lt;/h2&gt;
&lt;p&gt;One common yet major mistake I&#39;ve seen is that a manager hears the description of the defect/outage and says &amp;quot;well we&#39;ll just do x then&amp;quot; without soliciting the input of the team.  This is usually a huge mistake because the manager usually doesn&#39;t have the intimate knowledge of the system that the developers do, and even if he/she did, it is extremely unlikely that any single person can consistently decide a better course of action than a team.  Also, the more a manager does this, the less likely the team is to feel that it&#39;s their place to try to solve these problems.&lt;/p&gt;
&lt;p&gt;With that said, your team should still be conscious that some of the causal factors are not technical at all.  Some examples that I&#39;ve personally seen are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The team is over-worked.&lt;/li&gt;
&lt;li&gt;The team has been under too much pressure to move quickly or to meet unrealistic deadlines.&lt;/li&gt;
&lt;li&gt;The team wants more training in certain areas.&lt;/li&gt;
&lt;li&gt;Management is constantly changing priorities and forcing work to be left partially finished.&lt;/li&gt;
&lt;li&gt;The team&#39;s workflow is too complicated and merges keep leading to undetected defects.&lt;/li&gt;
&lt;li&gt;Management won&#39;t allow time to be spent on quality measures.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&#39;s a common mistake for developers to focus only on the technical problems, probably because they&#39;re the most easily controlled by the development team, but I would say for a team to be truly effective, it must be able to address the non-technical factors as well, and often manage up.  Great management will pay very close attention to the team&#39;s conclusions.&lt;/p&gt;
&lt;h2&gt;Resist &amp;quot;Try Harder Next Time&amp;quot;&lt;/h2&gt;
&lt;p&gt;Hand-in-hand with blamelessness should almost always be a rule that no improvement should involve &amp;quot;Trying harder next time&amp;quot;.  That would be assuming someone didn&#39;t try hard enough the last time, and it&#39;s assuming that only effort needs to change in order for the team to be more effective next time.  People will either naturally want to try harder next time, or they won&#39;t.  Saying &amp;quot;try harder next time&amp;quot; usually won&#39;t change a thing.&lt;/p&gt;
&lt;p&gt;In fact you&#39;d usually be more successful, not just by not trying solutions that don&#39;t require more human discipline, but to additionally take that one step further and reduce the level of discipline already required.  There&#39;s a great blog post on this by Marco Ament  &lt;a href=&quot;http://www.marco.org/2012/02/25/right-vs-pragmatic&quot;&gt;here&lt;/a&gt;, and I can tell you, the results in real life are often amazing.&lt;/p&gt;
&lt;p&gt;Humans are great at conserving their energy for important things, or things that are likely to cause issues, but the result of that is that unlikely events are often not given much effort at all.  This is a common trade-off in all of nature that Erik Hollnagel calls the &lt;a href=&quot;http://erikhollnagel.com/ideas/etto-principle/index.html&quot;&gt;ETTO (Efficiency Thoroughness Trade-Off)  principle&lt;/a&gt;.  You don&#39;t want your solutions to be fighting an uphill battle against nature.&lt;/p&gt;
&lt;p&gt;There&#39;s another kind of strange result of this (I think, anyway) called &lt;a href=&quot;http://en.wikipedia.org/wiki/Bystander_effect&quot;&gt;&amp;quot;the bystander effect&amp;quot;&lt;/a&gt;, where often if a problem is the responsibility of multiple people, it&#39;s less likely that any single person will take responsibility for it.  This is a real phenomenon and if you&#39;ve worked on a team for any length of time, you&#39;ve seen it happen.  You&#39;ll want to try to make sure that whatever solutions you come up with, they won&#39;t fall victim to this bystander effect.&lt;/p&gt;
&lt;h2&gt;Consider Cost-to-fix vs. Cost-to-endure&lt;/h2&gt;
&lt;p&gt;It should go without saying that the cost of your solutions for issues should be less than the cost of the issue itself.  Sometimes these costs are really hard to estimate given the number of variables and unknowns involved, but it&#39;s at least worth consideration.  An early-stage start-up is unlikely to care about being multi-data-center for the sake of redundancy, for instance.  It would be ridiculous, on the other hand, for a bank to not seek this level of redundancy.&lt;/p&gt;
&lt;h2&gt;Consider Process Costs&lt;/h2&gt;
&lt;p&gt;The second most naive reaction to a bug or outage (after &amp;quot;Try harder next time&amp;quot;) is also usually to add some more human process to the team&#39;s existing process, like more checks, or more over-sight.  While you may well conclude that this is the best measure for a given issue, keep in mind that it&#39;s probably also the slowest, most expensive and most error-prone.  These sorts of solutions are often the ones that are the simplest to conceive, but if they&#39;re your team&#39;s only reaction to issues, they will build up more and more over time dooming the team to move really slowly while it works its way repeatedly through these processes.&lt;/p&gt;
&lt;h2&gt;Improve Defect Prevention&lt;/h2&gt;
&lt;p&gt;There are a tonne of possible ways to try to prevent bugs from reaching production that are too numerous to get into here, but there are two really important ways to evaluate them:&lt;/p&gt;
&lt;h3&gt;(1) Does the method find bugs quickly and early in development?&lt;/h3&gt;
&lt;p&gt;The shortness of your feedback loop in detecting bugs is hugely important in making sure that your prevention methods don&#39;t slow the team down so much that their cost outweighs their benefit.  Manual human testing by a separate testing team is probably the slowest and most late way to find bugs, whereas syntax highlighters may be both the fastest and earliest for the class of issue that they can uncover (Of course these methods each test completely different things, but they&#39;re mentioned to give an idea of both extremes of feedback loops).&lt;/p&gt;
&lt;h3&gt;(2) Does the method give you enough information to fix the problem quickly/easily?&lt;/h3&gt;
&lt;p&gt;This criteria is important though admittedly probably less so than the previous one.  You will want to judge your prevention measures on this criteria though, because it&#39;s another criteria that can cost you a lot of time/efficiency.  Incidentally, manual human testing is probably the worst by this criteria as well, because testing at that level generally just lets you know that something is broken in a particular area.  Unit-testing beats integration-testing in this particular area as well, because unit-testing does a better job of helping you pin-point the issue down to a particular unit (though they don&#39;t actually test for the same types of bugs at all, so it&#39;s a bit of an unfair comparison).&lt;/p&gt;
&lt;p&gt;With these two criteria in mind, it&#39;s useful to look at a number of defect prevention measures critically : &lt;a href=&quot;http://c2.com/cgi/wiki?TestDrivenDevelopment&quot;&gt;TDD&lt;/a&gt;, &lt;a href=&quot;http://martinfowler.com/bliki/UnitTest.html&quot;&gt;unit testing&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Integration_testing&quot;&gt;integration testing&lt;/a&gt;, manual testing, beta testing, &lt;a href=&quot;https://www.owasp.org/index.php/Fuzzing&quot;&gt;fuzz-testing&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Mutation_testing&quot;&gt;mutation testing&lt;/a&gt; , staging environments, &lt;a href=&quot;http://en.wikipedia.org/wiki/Eating_your_own_dog_food&quot;&gt;dog-fooding&lt;/a&gt;, automated screen-shot diffing, &lt;a href=&quot;http://stackoverflow.com/questions/49716/what-is-static-code-analysis&quot;&gt;static analysis&lt;/a&gt;, &lt;a href=&quot;http://stackoverflow.com/questions/1517582/what-is-the-difference-between-statically-typed-and-dynamically-typed-languages&quot;&gt;static typing&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Lint_%28software%29&quot;&gt;linting&lt;/a&gt;, &lt;a href=&quot;http://c2.com/cgi/wiki?PairProgramming&quot;&gt;pair programming&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Code_review&quot;&gt;code reviews&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Formal_verification&quot;&gt;formal proofs&lt;/a&gt;, 3rd-party auditing, checklists etc.  I&#39;ve tried to be a bit exhaustive in that list, and while I&#39;ve added some options that have never been useful to me, I&#39;ve probably also forgotten a few.  There are new preventative measures popping up all the time too.&lt;/p&gt;
&lt;p&gt;An amazing example of preventative measures is probably the extremely popular SQLite project.  &lt;a href=&quot;https://www.sqlite.org/testing.html&quot;&gt;Their discussion of the measures that they take&lt;/a&gt; is fascinating.&lt;/p&gt;
&lt;h2&gt;Remove Human Processes with Automation&lt;/h2&gt;
&lt;p&gt;So I&#39;ve hinted at this a few times so far, but it should be reiterated that automating otherwise manual human processes can bring a level of speed and consistency to them that humans can&#39;t compete with.  Often times this is tricky and it&#39;s not worth it, but these scenarios are getting fewer as technology progresses.  There are two huge risks in automation though:&lt;/p&gt;
&lt;h3&gt;(1) Automation also involves software that can fail.  Now you have two systems to maintain and try to keep defect-free.&lt;/h3&gt;
&lt;p&gt;Often this second system (the automation of the primary system) doesn&#39;t get engineered with the same rigor as the primary system, so it&#39;s possible to automate in a way that is less consistent and more error-prone than a human.&lt;/p&gt;
&lt;h3&gt;(2) If you&#39;re really going to replace a manual human task, make sure the automation really does outperform the human.&lt;/h3&gt;
&lt;p&gt;I&#39;ve seen many attempts at automation not actually meet the goal of doing the job as well as a human.  It&#39;s not uncommon at all to see examples like teams with 90+% automated test coverage releasing drop-everything defects as awesome as &amp;quot;the customer can&#39;t log in&amp;quot; because some CSS issue makes the login form hidden.  A team that sees bugs like this often is almost certainly not ready to remove humans from the testing process, regardless of how many tests they&#39;ve written.&lt;/p&gt;
&lt;h2&gt;Eliminate Classes of Bugs&lt;/h2&gt;
&lt;p&gt;When you think about preventing defects without succumbing to &amp;quot;Try Harder Next Time&amp;quot; thought-patterns, one of the most powerful tools is to try to consider how you could make that defect impossible in the future.  Often it&#39;s possible to avoid defects by working at levels of better abstraction.  Here are a few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Avoid &lt;a href=&quot;http://en.wikipedia.org/wiki/Off-by-one_error&quot;&gt;off-by-one&lt;/a&gt; errors in for loops by using iterator functions, or functional paradigms that give you filter(), map() and reduce().&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid SQL injection by using &lt;a href=&quot;http://stackoverflow.com/questions/8263371/how-prepared-statements-can-protect-from-sql-injection-attacks&quot;&gt;prepared statements&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid &lt;a href=&quot;https://owasp.org/www-community/attacks/xss/&quot;&gt;Cross-site scripting&lt;/a&gt; attacks by using an html template language that automatically escapes output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid bugs from unexpected changes in shared objects by using &lt;a href=&quot;http://en.wikipedia.org/wiki/Persistent_data_structure&quot;&gt;immutable data structures&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may need some creativity here for your own particular defects, but in many cases eliminating the opportunity for a bug to arise is better than trying to catch it when it happens.&lt;/p&gt;
&lt;p&gt;For example, I once worked on a team that would occasionally forget to remove console.log() calls from our client-side javascript, which would break the entire site in IE 8.  By putting a check for console.log() calls in the build (and breaking it when they exist), we eliminated this class of defect entirely.&lt;/p&gt;
&lt;h2&gt;Go Beyond Prevention&lt;/h2&gt;
&lt;p&gt;Defect and outage prevention is only one side of the quality coin as well, though it&#39;s usually the side people naturally try to employ when trying to figure out how to handle defects better in the future.  You should of course investigate better prevention measures, but you should also consider solutions that will improve your situation when defects do occur, because failures will always happen.&lt;/p&gt;
&lt;p&gt;I personally think it&#39;s entirely unrealistic for all your measures to be preventative.  A focus entirely on preventative measures has a tendency to slow down your team&#39;s ability to deliver while at the same time not delivering the level of quality that you could.&lt;/p&gt;
&lt;p&gt;With that said, here are a few classes of mitigating measures:&lt;/p&gt;
&lt;h3&gt;Improve your &amp;quot;Time to Repair&amp;quot;&lt;/h3&gt;
&lt;p&gt;There&#39;s an interesting metric called &lt;a href=&quot;http://blog.fosketts.net/2011/07/06/defining-failure-mttr-mttf-mtbf/&quot;&gt;MTTR&lt;/a&gt; which stands for &amp;quot;Mean Time to Repair/Recovery&amp;quot;, and is basically the average time it takes you to fix a defect/outage.  It&#39;s an important metric, because the cost of a defect must include how long that defect was affecting customers.  The speed at which you can deliver a fix is going to be a major factor in how defect mitigation.  You&#39;ll want to ask questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How can we pinpoint problems faster?&lt;/li&gt;
&lt;li&gt;How can we create fixes faster?&lt;/li&gt;
&lt;li&gt;How can we verify our fixes faster?&lt;/li&gt;
&lt;li&gt;How can we deliver fixes faster?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Practices like Continuous Delivery can help here greatly.  If you have a 20 minute manual deployment that involves a number of coordinated activities from a number of team members, you will be leaving customers exposed for much longer than a team practicing Continuous Delivery.&lt;/p&gt;
&lt;p&gt;Automated testing on its own can be a huge help.  If the bulk of your tests is manual, then a fix will take some time to verify (including verifying that it doesn&#39;t break anything else).  Teams that rely heavily on manual testing will usually test much less thoroughly on a &amp;quot;hot fix&amp;quot;, which occasionally can lead to worsening of the situation.&lt;/p&gt;
&lt;p&gt;In my experience though, nothing affects MTTR as much as the speed at which you can &lt;em&gt;detect&lt;/em&gt; defects/outages...&lt;/p&gt;
&lt;h3&gt;Improve Detection Time&lt;/h3&gt;
&lt;p&gt;Talk about how quickly you discovered the issue compared to when it was likely to have started.  If your customers are discovering your issues, try figuring out if there&#39;s a way that you can beat them to it.  Instrumentation (metrics &amp;amp; logging) has been a huge help for me in different organizations for knowing about problems before customers can report them.  &lt;a href=&quot;http://c2.com/cgi/wiki?InformationRadiator&quot;&gt;Information radiators&lt;/a&gt; can help keep those metrics ever-present and always on the minds of the team members.&lt;/p&gt;
&lt;p&gt;Threshold-based alerting systems (that proactively reach out to the team to tell them about issues) in particular are valuable because they don&#39;t rely on the team to check metrics themselves, and they can short circuit that &amp;quot;human polling loop&amp;quot; and alert the team much faster, or during times that they ordinarily would not be looking (at night, on weekends, etc).  It&#39;s pretty easy to see that an alerting system that alerts about an outage on a Friday night can save the customer days of exposure.&lt;/p&gt;
&lt;h3&gt;Lessen the Impact of Failures&lt;/h3&gt;
&lt;p&gt;If you can figure out ways for failures to have less impact, that&#39;s a huge win as well.  Here are a few examples of ideas I&#39;ve seen come out of one of these meetings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have deployments go to only a 5% segment of users first for monitoring before going out to 100% of the users.&lt;/li&gt;
&lt;li&gt;Speed up builds and deployments, so hot-fixes can go out faster.&lt;/li&gt;
&lt;li&gt;Have an easy way to display a message to users during an outage&lt;/li&gt;
&lt;li&gt;Improve metrics and logging to speed-up debugging around that particular issue.&lt;/li&gt;
&lt;li&gt;Set-up off-hours alerting.&lt;/li&gt;
&lt;li&gt;Have a one-click &amp;quot;revert deployment&amp;quot; mechanism that can instantly revert to a previous deployment in case something goes wrong.&lt;/li&gt;
&lt;li&gt;Create &amp;quot;&lt;a href=&quot;http://en.wikipedia.org/wiki/Bulkhead_(partition)&quot;&gt;bulkheads/partitions&lt;/a&gt; &amp;quot; in your applications so that if one part fails, the rest can still function properly.  There are many common examples of this in software, including PHP&#39;s request partitioning model, or the browser&#39;s ability to continue despite a javascript exception, even on the same page.  Service-oriented architectures often have this quality as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may or may not need some creativity here to come up with your own, but it&#39;s worth the effort.&lt;/p&gt;
&lt;h2&gt;Be Realistic with Plans For Improvement&lt;/h2&gt;
&lt;p&gt;Whatever you say you will do as a result of this meeting, make sure that it&#39;s actually realistic, and there&#39;s a realistic plan to get it into the teams future work (eg Who will do it? When?).  The best way to have completely useless meetings is to not actually do what you plan to do.&lt;/p&gt;
&lt;h2&gt;Write Up a Report for the Rest of the Company&lt;/h2&gt;
&lt;p&gt;The report should say honestly how bad the problem was, in what way (and for how long) customers were affected, and generally what events lead up to it (blamelessly!).  Additionally you&#39;ll want to declare the next steps that the team plans to take, so that the company knows you&#39;re a professional engineering team that cares about results as much as the other people in the organization.  You should be ready and willing to take questions and comments on this report, and send it to as many interested parties as possible.  Often other people in the company will have additional ideas or information, and the transparency makes them feel like these are welcome any time.&lt;/p&gt;
&lt;p&gt;The real value in this is that you show that the entire team is uniformly holding itself accountable for the problem, and that any propensity that the rest of organization has for blaming a single person is not in accordance with the engineering team&#39;s views.  The engineering team and management should be willing and able to defend any individuals targeted for blame.&lt;/p&gt;
&lt;h2&gt;Decide What Types of Defects/Outages Necessitate These Meetings&lt;/h2&gt;
&lt;p&gt;Some organizations are more meeting-tolerant than others, so there&#39;s no hard-fast rule here.  If you had one of these meetings for &lt;em&gt;every&lt;/em&gt; production defect, you&#39;d probably very quickly have a bunch of solutions in place that greatly reduces the number of defects though (and therefore reduces the number of these meetings!).  These meetings are all &lt;em&gt;investments&lt;/em&gt;.  The more you have, the more they start to pay off, both with quality of product and with speed of delivery (if you stay conscious of that!).&lt;/p&gt;
&lt;p&gt;One thing I will recommend though is that you look for recurrences and patterns in these defects/outages.  The team will usually benefit disproportionately from more time invested in solving repeated problems.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Continuous Testing</title>
		<link href="/posts/2015-01-29-continuous-testing/"/>
		<updated>2015-01-30T04:40:51Z</updated>
		<id>/posts/2015-01-29-continuous-testing/</id>
		<content type="html">&lt;p&gt;Last week I had the pleasure of being on a &lt;a href=&quot;http://electric-cloud.com/blog/2015/01/c9d9-recap-continuous-testing-and-test-acceleration/&quot;&gt;panel about Continuous Testing&lt;/a&gt; put on by &lt;a href=&quot;http://electric-cloud.com/&quot;&gt;Electric Cloud&lt;/a&gt;.  There&#39;s video of the discussion if you&#39;re interested, &lt;a href=&quot;https://www.youtube.com/watch?x-yt-ts=1422503916&amp;amp;x-yt-cl=85027636&amp;amp;v=lqGd378spH0&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, I posted a blog post on the subject on the ClassDojo
Engineering blog &lt;a href=&quot;http://engineering.classdojo.com/blog/2015/01/20/continuous-testing-at-classdojo/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For posterity, I&#39;ll x-post here as well:&lt;/p&gt;
&lt;h2&gt;Continuous Testing at ClassDojo&lt;/h2&gt;
&lt;p&gt;We have thousands of tests and regularly deploy to production multiple times per day.  This article is about all the crazy things we do to make that possible.&lt;/p&gt;
&lt;h3&gt;How we test our API&lt;/h3&gt;
&lt;p&gt;Our web API runs on &lt;a href=&quot;http://nodejs.org/&quot;&gt;node.js&lt;/a&gt;, but a lot of what we do should be applicable to other platforms.&lt;/p&gt;
&lt;p&gt;On our API alone, we have ~2000 tests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We have some wacky automated testing strategies:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We actually integration test against a database.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We actually do api tests via http and bring up a new server for each test and tear it down after.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We mock extremely minimally, because there&#39;s little to gain performance-wise in our case, and we want to ensure that integrations work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When we do more unit-type tests, it&#39;s for the sake of convenience of testing a complicated detail of some component, and not for performance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;All ~2000 tests run in under 3 minutes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s also common for us to run the entire suite dozens of times per day.&lt;/p&gt;
&lt;p&gt;With that said, I usually do TDD when a defect is found, because I want to make sure that the missing test actually exposes the bug before I kill the bug.  It&#39;s much easier to do TDD at that point when the structure of the code is pretty unlikely to need significant changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We aim for ~100% coverage:&lt;/strong&gt;  We find holes in test coverage with the &lt;a href=&quot;https://github.com/gotwarlost/istanbul&quot;&gt;istanbul code coverage tool&lt;/a&gt;, and we try to close those holes.  We&#39;ve got higher than 90% coverage across code written in the last 1.5 years.  Ideally we go for 100% coverage, but practically we fall a bit short of that.  There are some very edge-case error-scenarios that we don&#39;t bother testing because testing them is extremely time-consuming, and they&#39;re very unlikely to occur.  This is a trade-off that we talked about as a team and decided to accept.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We work at higher levels of abstraction:&lt;/strong&gt;  We keep our tests as &lt;a href=&quot;http://c2.com/cgi/wiki?DontRepeatYourself&quot;&gt;DRY&lt;/a&gt; as possible by extracting a bunch of test helpers that we write along the way, including our api testing library &lt;a href=&quot;http://github.com/cainus/verity&quot;&gt;verity&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Speeding up Builds&lt;/h3&gt;
&lt;p&gt;It&#39;s critical that builds are really fast, because they&#39;re the bottleneck in the feedback cycle of our development and we frequently run a dozen builds per day.  Faster builds mean faster development.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We use a linter:&lt;/strong&gt; We use &lt;a href=&quot;http://jshint.com/&quot;&gt;jshint&lt;/a&gt; before testing, because node.js is a dynamic language.  This finds common basic errors quickly before we bother with running the test suite.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We cache package repository contents locally:&lt;/strong&gt; Loading packages for a build from a remote package repository was identified as a bottleneck.  You could set up your own npm repository, or just use a cache like &lt;a href=&quot;https://github.com/mixu/npm_lazy&quot;&gt;npm_lazy&lt;/a&gt;.  We just use npm_lazy because it&#39;s simple and works.  We recently created &lt;a href=&quot;https://www.npmjs.com/package/weezer&quot;&gt;weezer&lt;/a&gt; to cache compiled packages better as well for an ultra-fast &lt;code&gt;npm install&lt;/code&gt; when dependencies have not changed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We measured the real bottlenecks in our tests:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Loading fixtures into the database is our primary bottleneck, so we load fixtures only once for all read-only tests of a given class.  It&#39;s probably not a huge surprise to people that this is our bottleneck given that we don&#39;t mock-out database interaction, but we consider this an acceptable bottleneck given that the tests still run extremely fast.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We used to use one of Amazon EC2&#39;s C3 compute cluster instances for jenkins, but switched to a much beefier dedicated hosting server when my laptop could inexplicably run builds consistently faster than EC2 by 5 minutes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;We fail fast:&lt;/strong&gt; We run full integration tests first so that the build fails faster.  Developers can then run the entire suite locally if they want to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We notify fast:&lt;/strong&gt; Faster notification of failures/defects leads to diminished impact.  We want developers to be notified ASAP of a failure so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We bail on the build at the first error, rather than running the entire build and reporting all errors.&lt;/li&gt;
&lt;li&gt;We have large video displays showing the test failure.&lt;/li&gt;
&lt;li&gt;We have a gong sound effect when it happens.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;We don&#39;t parallelize tests:&lt;/strong&gt; We experimented with test suite parallelization, but it&#39;s really complicated on local machines to stop contention on shared resources (the database, network ports) because our tests use the database and network.  After getting that to work, we found very little performance improvement, so we just reverted it for simplicity.&lt;/p&gt;
&lt;h3&gt;Testing Continues after Deployment&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;We run post-deployment tests:&lt;/strong&gt; We run basic smoke tests post-deployment as well to verify that the deployment went as expected.  Some are manually executed by humans via a service called &lt;a href=&quot;https://www.rainforestqa.com/&quot;&gt;Rainforest&lt;/a&gt;.  Any of those can and should be automated in the future though.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We use logging/metrics/alerts:&lt;/strong&gt; We consider logging and metrics to be part of on-going verification of the production system, so it should also be considered as part of our &amp;quot;test&amp;quot; infrastructure.&lt;/p&gt;
&lt;h3&gt;Our Testing Process&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;We do not have a testing department or role.&lt;/strong&gt;  I personally feel that that role is detrimental to developer ownership of testing, and makes continuous deployment extremely difficult/impossible because of how long manual testing takes.  I also personally feel that QA personnel are much better utilized elsewhere (doing actual &lt;a href=&quot;http://en.wikipedia.org/wiki/Quality_assurance&quot;&gt;Quality Assurance&lt;/a&gt;, and not testing).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Continuous Testing requires &lt;a href=&quot;http://www.thoughtworks.com/continuous-integration&quot;&gt;Continuous Integration&lt;/a&gt;.&lt;/strong&gt;  Continuous Integration doesn&#39;t work with &lt;a href=&quot;http://martinfowler.com/bliki/FeatureBranch.html&quot;&gt;Feature Branches&lt;/a&gt;.  Now we all work on master (more on that &lt;a href=&quot;/posts/2014-06-03-your-team-probably-doesnt-have-the-same-dvcs-requirements-as-linus/&quot;&gt;here!&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We no longer use our staging environment.&lt;/strong&gt;  With the way that we test via http, integrated with a database, there isn&#39;t really anything else that a staging server is useful for, testing-wise.  The api is deployed straight to a small percentage ~5% of production users once it is built.  We can continue testing there, or just watch logs/metrics and decide whether or not to deploy to the remaining ~95% or to revert, both with just the click of a button.&lt;/p&gt;
&lt;p&gt;We deploy our frontends against the production api in non-user facing environments, so they can be manually tested against the most currently deployed api.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When we find a defect, we hold blameless post-mortems.&lt;/strong&gt;  We look for ways to eliminate that entire class of defect without taking measures like &amp;quot;more manual testing&amp;quot;, &amp;quot;more process&amp;quot;, or &amp;quot;trying harder&amp;quot;.  Ideally solutions are automatable, including more automated tests.  When trying to write a test for a defect we try as hard as possible to write the test first, so that we can be sure that the test correctly exposes the defect.  In that way, we &lt;em&gt;test the test&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Lessons learned:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Our testing practices might not be the best practices for another team.  Teams should decide together what their own practices should be, and continually refine them based on real-world results.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Find your actual bottleneck and concentrate on that instead of just doing what everyone else does.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hardware solutions are probably cheaper than software solutions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Humans are inconsistent and less comprehensive than automated tests, but more importantly they&#39;re too slow to make CD possible.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Remaining gaps:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;We&#39;re not that great at client/ui testing (mobile and web), mostly due to lack of effort in that area, but we also don&#39;t have a non-human method of validating styling etc.  We&#39;ll be investigating ways to automate screenshots and to look for diffs, so a human can validate styling changes at a glance.  We need to continue to press for frontend coverage either way.&lt;/li&gt;
&lt;li&gt;We don&#39;t test our operational/deployment code well enough.  There&#39;s no reason that it can&#39;t be tested as well.&lt;/li&gt;
&lt;li&gt;We have a really hard time with thresholds and anomaly detection and alerts on production metrics such that we basically have to watch a metrics display all day to see if things are going wrong.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The vast majority of our defects/outages come from these three gaps.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>I Don&#39;t Miss The Sprint</title>
		<link href="/posts/2014-12-02-i-dont-miss-the-sprint/"/>
		<updated>2014-12-02T19:00:23Z</updated>
		<id>/posts/2014-12-02-i-dont-miss-the-sprint/</id>
		<content type="html">&lt;p&gt;It&#39;s been over a year since I&#39;ve been on a team that does Sprints as part of its engineering process, and I&#39;ve really changed my mind on their usefulness.  I&#39;m probably pretty old-school &amp;quot;agile&amp;quot; by most standards, so I still think Scrum is better than what most teams out there are doing, but I think it&#39;s lost me as a proponent for a few reasons, with the most surprising reason (to me) being its use of sprints.&lt;/p&gt;
&lt;p&gt;The sprint, for those few engineers that might not have ever developed this way, is simply a &lt;a href=&quot;http://en.wikipedia.org/wiki/Timeboxing&quot;&gt;time  box&lt;/a&gt; where you plan your work at the beginning, usually estimating what work will fit within that time box, and then do some sort of review afterward to assess is efficacy, including the work completed, and the accuracy of the estimates.&lt;/p&gt;
&lt;p&gt;I&#39;ve been involved in sprints as short as a week and as long as a month, depending on the organization.  The short timespan can have an amazingly transformative effect on organizations that are releasing software less often than that: it gets them meeting regularly to re-plan, it gets them improving their process regularly, and it gets a weekly stream of software released so that the rest of the company can get a sense of what is happening and at what pace.  These are huge wins:  You get regular course-correction, improvement and transparency, all helping to deliver more working software, more reliably.  What&#39;s not to love?&lt;/p&gt;
&lt;p&gt;Well I&#39;ve always ignored a couple of major complaints about Sprints because I&#39;ve felt that those complaints generally misunderstood the concept of the time box.  The first complaint is that a Sprint is just another deadline, and one that looms at a more frequent pace so it just adds more pressure.  If your scrummaster or manager treats them like weekly deadlines, he/she is just plain &amp;quot;doing it wrong&amp;quot;.  Time boxes are just meant to be a regular re-visiting and re-assessment of what&#39;s currently going on.  It&#39;s supposed to be a realistic, sustainable pace so that when observed, the speed that the team is delivering at can start to be relied upon for future projections.  Treating it like a deadline has the opposite effect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Developers work at unsustainable paces, inherently meaning that at some point in the future, they will fail to maintain that pace and generally will not be as predictable to the business as they otherwise could be.&lt;/li&gt;
&lt;li&gt;Developers cut corners, leading to defects, which lead to future interruptions, which leads to the team slowing more and more over time.  I&#39;ve been on a team that pretty much &lt;em&gt;only&lt;/em&gt; had time for its own defects, so I&#39;ve seen this taken to the absolute extreme.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s the thing though, if it&#39;s supposed to encourage a reliable, sustainable pace, why would you ever call it a &amp;quot;sprint&amp;quot;?  &amp;quot;What&#39;s in a name?&amp;quot;, right?  Well it turns out that when you want to get people to change the way they work, and you want them to understand the completely foreign concepts you&#39;re bringing to them, it&#39;s absolutely crucial that you name the thing in a way that also explains what it is not.&lt;/p&gt;
&lt;p&gt;In Scrum, it&#39;s also common to have a &amp;quot;sprint commitment&amp;quot; where the team &amp;quot;commits&amp;quot; to a body of work to accomplish in that time frame.  The commitment is meant to be a rough estimate for the sake of planning purposes, and if a team doesn&#39;t get that work done in that time, it tries to learn from the estimate and be more realistic in the next sprint.  Developers are not supposed to be chastized for not meeting the sprint commitment -- it&#39;s just an extra piece of information to improve upon and to use for future planning.  Obviously naming is hugely important here too, because in every other use of the word, a &amp;quot;commitment&amp;quot; is a pledge or a binding agreement, and this misnomer &lt;em&gt;really&lt;/em&gt; influences the way people (mis)understand the concept of sprints.  Let&#39;s face it: if people see sprints as just more frequent deadlines (including those implementing them), the fault can&#39;t be entirely theirs.&lt;/p&gt;
&lt;h3&gt;Sooo... The naming is terrible, but the concept is a good one, right?&lt;/h3&gt;
&lt;p&gt;Well &amp;quot;iteration&amp;quot; is definitely a much better name, and I hope people use that name more and more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;More importantly though, I&#39;d like to argue that time boxes for planning and delivery are fundamentally flawed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&#39;ve personally found that sprint commitments are entirely counter-productive:  A team can just gauge its speed for planning purposes based on past performance instead, which is really what the sprint commitment is meant to be.  We should be forecasting entirely based on past performance, and adjusting constantly rather than trying to predict, and trying to hold people to predictions.&lt;/p&gt;
&lt;p&gt;Also, with planning happening at the beginning of the sprint and software delivery happening at the end, in a regular cadence, the team is much less likely to do things more frequently than this schedule.&lt;/p&gt;
&lt;p&gt;Instead of planning and releasing on the schedule of a sprint, we&#39;ve had a lot more success practicing just-in-time planning and &lt;a href=&quot;http://en.wikipedia.org/wiki/Continuous_delivery&quot;&gt;continuous delivery&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Just-In-Time Planning&lt;/h3&gt;
&lt;p&gt;Planning should happen on-demand, not on a schedule.  Planning on a schedule often has you planning for things too far ahead, forcing people to try to remember the plan later.  I&#39;ve seen an hour&#39;s worth of planning fall apart as soon as we tried to execute the plan, so I really don&#39;t see the point of planning for particular time-spans (especially larger ones).  Teams should simply plan for the work they&#39;re currently starting, the natural way, not based on time, but based on the work they have to do.  They should plan and re-plan a particular task as frequently as is necessary to deliver it, and they should plan for as long or as short as necessary to come up with a plan that everyone is happy with.  Planning naturally like this leads to more frequent situations where developers will say &amp;quot;hold on, we should sit down and talk about this before we continue the current plan&amp;quot;, which is good for everybody involved.&lt;/p&gt;
&lt;h3&gt;Continuous Delivery&lt;/h3&gt;
&lt;p&gt;The cadence of delivering software at the end of a sprint almost always means an organization does not deploy the software more often than that cadence.  I&#39;ve worked on teams that tried to make &amp;quot;deployment day&amp;quot; somewhere in the middle of the sprint to emphasize that the sprint boundary is just an arbitrary time box, decoupled from deployment, but we never managed to deploy more often than once per sprint, and it really only resulted in a de facto change in the sprint schedule for our QA personnel.  The very existence of a time-box puts people in the mindset that releasing software, deploying software and calling software &amp;quot;done&amp;quot; are all the same event and there&#39;s a scheduled time for that.  Without the time-box, people start to think more freely about ways to decouple these events and how to safely improve the customer experience more often.  Today, free from sprints, I&#39;m safely deploying to production multiple times &lt;em&gt;per day&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now Scrum proponents will argue that Sprints can be exactly like this -- sprints do not preclude JIT planning or continuous delivery -- and the time-box just adds additional points of planning and review to ensure that the team is doing the necessary planning and reviewing.  While I wholeheartedly agree with this on a theoretical level, this is not what ends up happening in practice:  In reality, when you schedule time for particular aspects of work, people tend to wait until that schedule to do that type of work.&lt;/p&gt;
&lt;p&gt;And I realize that what I&#39;m suggesting sounds a bit more sloppy, and lacks the formality of a scheduled cadence, but it simply ends up being more natural and more efficient.  These concepts aren&#39;t new either -- any teams that have been using the venerable &lt;a href=&quot;http://en.wikipedia.org/wiki/Kanban_(development)&quot;&gt;kanban&lt;/a&gt; method will be familiar with them.&lt;/p&gt;
&lt;h3&gt;One additional Caveat&lt;/h3&gt;
&lt;p&gt;With all this said, if a team is going to continually improve, I haven&#39;t seen a better mechanism than the regular retrospective.  I just don&#39;t think Sprints are necessary to make that happen.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Production-Quality Node.js Web Apps : Part III, Preventing Defects</title>
		<link href="/posts/2014-06-22-production-quality-node-dot-js-web-apps-part-iii/"/>
		<updated>2014-06-23T05:56:10Z</updated>
		<id>/posts/2014-06-22-production-quality-node-dot-js-web-apps-part-iii/</id>
		<content type="html">&lt;p&gt;This is the last part of my 3-part series on production-quality node.js web applications.  I&#39;ve decided to leave error-prevention to the end, because while it&#39;s super-important, it&#39;s often the only strategy developers employ to ensure customers have the most defect-free experience as possible.  It&#39;s definitely worth checking out
&lt;a href=&quot;/posts/2014-06-02-production-quality-node-dot-js-web-apps-part-i/&quot;&gt;part I&lt;/a&gt; and &lt;a href=&quot;/posts/2014-06-02-production-quality-node-dot-js-web-apps-part-ii/&quot;&gt;part II&lt;/a&gt; if you&#39;re curious about other strategies and really interested in getting significant results.&lt;/p&gt;
&lt;h3&gt;Error Prevention&lt;/h3&gt;
&lt;p&gt;With that said, let&#39;s talk about a few error prevention tricks and tactics that I&#39;ve found extremely valuable.  There are a bunch of code conventions and practices that can help immensely, and here&#39;s where I&#39;ll get into those.  With that said I should add that I&#39;m not going to talk about &lt;a href=&quot;https://github.com/laverdet/node-fibers&quot;&gt;node-fibers&lt;/a&gt;, or &lt;a href=&quot;http://blogs.atlassian.com/2013/11/harmony-generators-and-promises-for-node-js-async-fun-and-profit/&quot;&gt;harmony-generators&lt;/a&gt;, or &lt;a href=&quot;https://github.com/Sage/streamlinejs&quot;&gt;streamline.js&lt;/a&gt;, which all have different solutions - ultimately because I haven&#39;t used them (which is because none of them are considered very &#39;standard&#39; (yet)).  There are people using them to solve a few of the issues I&#39;ll talk about though.&lt;/p&gt;
&lt;h4&gt;High test coverage, extensive testing&lt;/h4&gt;
&lt;p&gt;There should be no surprise here, but I think test coverage is absolutely essential in any dynamically typed app because so many errors can only happen at runtime.  If you haven&#39;t got heavy test coverage, (even coverage itself is valuable!), you will run into all kinds of problems as the codebase gets larger and more complex, and you&#39;ll be too scared to make sweeping changes (like change out your database abstraction, or how sessions are handled).  An untested/uncovered codebase will have you constantly shipping codepaths to production that have never been actually executed before anywhere.&lt;/p&gt;
&lt;p&gt;The simplest way I&#39;ve found to get code coverage stats (and I&#39;ve used multiple methods in the past) is to use &lt;a href=&quot;http://gotwarlost.github.io/istanbul/&quot;&gt;istanbul&lt;/a&gt;.  Here&#39;s istanbul&#39;s output on a file from one of my npm libraries:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/istanbul-600w.webp 600w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;istanbul output&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/istanbul-600w.jpeg&quot; width=&quot;600&quot; height=&quot;576&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The places marked in red are the places that my tests are not testing at all.  I use this tool all the time to see what I might have missed testing-wise, when I haven&#39;t been doing TDD, and then I try to close up the gaps.&lt;/p&gt;
&lt;h4&gt;Use a consistent error passing interface and strategy&lt;/h4&gt;
&lt;p&gt;Asynchronous code should &lt;strong&gt;always&lt;/strong&gt; take a callback that expects an Error object (or null) in the first parameter (the standard node.js convention).  This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Never create an asynchronous function that doesn&#39;t take a callback, no matter how little you care about the result.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Never create an asynchronous function that doesn&#39;t take an error parameter as the first parameter in its callback, even if you don&#39;t have a reason for it immediately.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Always use an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error&quot;&gt;Error object&lt;/a&gt; for errors, and not a string, because they have very handy &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack&quot;&gt;stacktraces&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Following these rules will make things much easier to debug later when things go wrong in production.&lt;/p&gt;
&lt;p&gt;Of course there are some cases where you can get away with breaking these rules, but even in those cases, over time, as you use these functions more often and change their internal workings, you&#39;ll often be glad that you followed these rules.&lt;/p&gt;
&lt;h4&gt;Use a consistent error-checking and handling strategy.&lt;/h4&gt;
&lt;p&gt;Always check the errors from a callback.  If you really don&#39;t care about an error (which should probably be rare), do something like this to make it obvious:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// do nothing.  we didn&#39;t need a user that badly&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even then, it&#39;s probably best to log the error at the very least.  It&#39;s extremely rare that you&#39;d bother writing code of which you don&#39;t care about the success/failure.&lt;/p&gt;
&lt;p&gt;In many cases you won&#39;t be expecting an error, but you&#39;ll want to know about it.  In those cases, you can do something like this to at least get it into your logs:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;unexpected error&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// TODO actually handle the error though!&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&#39;re going to want to actually handle the unexpected error there too of course.&lt;/p&gt;
&lt;p&gt;If you&#39;re in some nested callback, you can just pass it up to a higher callback for that callback to handle:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NB: I almost always use &lt;code&gt;return&lt;/code&gt; when calling callbacks to end execution of the current function right there and to save myself from having to manage a bunch of &lt;code&gt;if..else&lt;/code&gt; scenarios.  Early returns are just so much simpler in general that I rarely find myself using &lt;code&gt;else&lt;/code&gt; anywhere anymore.  This also saves you from becoming another &amp;quot;&lt;a href=&quot;https://www.google.com/search?q=headers+already+sent+node.js&amp;amp;oq=headers+already+sent+node.js&amp;amp;aqs=chrome..69i57.5322j0j7&amp;amp;client=ubuntu-browser&amp;amp;sourceid=chrome&amp;amp;es_sm=94&amp;amp;ie=UTF-8#q=can&#39;t+set+headers+after+they+are+sent&quot;&gt;can&#39;t set headers after they are sent&lt;/a&gt;&amp;quot; casualty.&lt;/p&gt;
&lt;p&gt;If you&#39;re at the top of a web request and you&#39;re dealing with an error that you didn&#39;t expect, you should send a 500 status code, because that&#39;s the appropriate code for errors that you didn&#39;t write appropriate handling for.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;unexpected error&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeHead&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Internal Server Error&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In general, you should always be handling or passing up every single error that could possibly occur.  This will make surfacing a particular error much easier.  Heavy production use has an uncanny ability to find itself in pretty much any codepath you can write.&lt;/p&gt;
&lt;h4&gt;Watch out for &lt;code&gt;error&lt;/code&gt; events.&lt;/h4&gt;
&lt;p&gt;Any EventEmitters in your code (including streams) that emit an &lt;code&gt;error&lt;/code&gt; event absolutely need to have a listener for those &lt;code&gt;error&lt;/code&gt; events.  Uncaught &lt;code&gt;error&lt;/code&gt; events will bring down your entire process, and usually end up being the main cause of process crashes in projects that I&#39;ve worked on.&lt;/p&gt;
&lt;p&gt;The next question will be how you handle those errors, and you&#39;ll have to decide on a case-by-case basis.  Usually you&#39;ll at least want to 500 on those as well, and probably log the issue.&lt;/p&gt;
&lt;h3&gt;Managing Errors at Runtime&lt;/h3&gt;
&lt;h4&gt;Domains&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://nodejs.org/api/domain.html&quot;&gt;Domains&lt;/a&gt; are without a doubt your best tool for catching errors in runtime that you missed at development time.  There are three places that I&#39;ve used them to great effect:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To wrap the main process.  When it dies, a domain catches the error that caused it.&lt;/li&gt;
&lt;li&gt;To wrap cluster&#39;s child processes.  If you use &lt;a href=&quot;https://github.com/isaacs/cluster-master&quot;&gt;cluster-master&lt;/a&gt; like I do, or if you use cluster.setupMaster() with a different file specified via &lt;code&gt;exec&lt;/code&gt; for child processes, you&#39;ll want the contents of the file to be wrapped in a domain as well.  This means that when a child process has an uncaught error, this domain catch it.&lt;/li&gt;
&lt;li&gt;To wrap the request and response objects of each http request.  This makes it much more rare that any particular request will take down your process.  I just use &lt;a href=&quot;https://github.com/brianc/node-domain-middleware&quot;&gt;node-domain-middleware&lt;/a&gt; to do this for me (This seems like it should work in any connect-compatible server as well, despite the name).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the case of catching an error with a domain on the main process, or a child process, you should usually just log the issue (and bump a restart metric), and let the process restart (via a process manager for the main process, or via cluster for the child process -- see &lt;a href=&quot;/posts/2014-06-02-production-quality-node-dot-js-web-apps-part-i/&quot;&gt;part I&lt;/a&gt; for details about this).  You probably do not want to the process to carry on, because if you knew enough about this type of error to catch it, you should have caught it before it bubble up to the process level.  Since this is an unexpected error, it could have unexpected consequences on the state of your application.  It&#39;s much cleaner and safer to just let the process restart.&lt;/p&gt;
&lt;p&gt;If you&#39;ve caught a an error from request or response object, it&#39;s probably safe and appropriate to send a 500 status code, log the error (and stack trace) and bump a &lt;code&gt;500&lt;/code&gt; metric.&lt;/p&gt;
&lt;p&gt;Also, I&#39;ve written a module that helps me test that my domains are correctly in place: &lt;a href=&quot;https://github.com/cainus/error-monkey&quot;&gt;error-monkey&lt;/a&gt;.  You can temporarily insert error-monkey objects in different places in your codebase to ensure that domains are catching them correctly.  This way, you&#39;re not tweaking the location of your domains and waiting for errors to happen in production to verify them.&lt;/p&gt;
&lt;h4&gt;Gracefully restarting&lt;/h4&gt;
&lt;p&gt;Now that domains have given you a place to catch otherwise uncaught exceptions and you can hook in your own restart logic, you&#39;ll want to think about gracefully restarting rather than just killing the process abruptly and dropping all outstanding requests in progress.  Instead you&#39;ll want tp restart only after all current requests have completed ( see : &lt;a href=&quot;http://nodejs.org/api/http.html#http_server_close_callback&quot;&gt;http://nodejs.org/api/http.html#http_server_close_callback&lt;/a&gt; ).  This way, the process can be restarted more gracefully.&lt;/p&gt;
&lt;p&gt;If you&#39;re running a bunch of node processes (usually with cluster), and a number of servers (usually behind a load-balancer), it shouldn&#39;t be that catastrophic to close one instance temporarily, as long as it&#39;s done in a graceful manner.&lt;/p&gt;
&lt;p&gt;Additionally, you may want to force a restart in the case that the graceful shutdown is taking an inordinate amount of time (probably due to hanging connections).  The right amount of time probably has a lot to do with what types of requests you&#39;re fulfilling, and you&#39;ll want to think about what makes sense for your application.&lt;/p&gt;
&lt;h2&gt;With that said...&lt;/h2&gt;
&lt;p&gt;These are just my notes on what I&#39;ve tried so far that achieved worthy results.  I&#39;d be interested to hear if anyone else has tried any other approaches for preventing, mitigating, and detecting defects.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Production-Quality Node.js Web Apps : Part II, Detecting Defects</title>
		<link href="/posts/2014-06-02-production-quality-node-dot-js-web-apps-part-ii/"/>
		<updated>2014-06-03T00:41:31Z</updated>
		<id>/posts/2014-06-02-production-quality-node-dot-js-web-apps-part-ii/</id>
		<content type="html">&lt;p&gt;This is the second part of a three part series on making node.js web apps that are (what I would consider to be) production quality.  The &lt;a href=&quot;/blog/2014/06/01/production-quality-node-dot-js-web-apps-part-i/&quot;&gt;first part&lt;/a&gt; really just covered the basics, so if you&#39;re missing some aspect covered in the basics, you&#39;re likely going to have some issues with the approaches discussed here.&lt;/p&gt;
&lt;p&gt;First, I&#39;m going to talk about a few major classes of defects and how to &lt;strong&gt;detect&lt;/strong&gt; them.&lt;/p&gt;
&lt;p&gt;I could go straight to talking about preventing/avoiding them, but detection is really the first step.  You&#39;re simply not going to get a low-defect rate by just using prevention techniques without also using detection techniques.  Try to avoid the junior engineer mindset of assuming that &amp;quot;being really careful&amp;quot; is enough to achieve a low defect rate.  You can get a much lower defect rate and move much faster by putting systems in place where your running application is actively telling &lt;em&gt;you&lt;/em&gt; about defects that it encounters.  This really is a case where working smart pays much higher dividends than working hard.&lt;/p&gt;
&lt;h2&gt;The types of defects you&#39;re most likely to encounter&lt;/h2&gt;
&lt;p&gt;I&#39;m a huge fan of constantly measuring the quality aspects that are measurable.  You&#39;re not going to detect all possible bugs this way, but you &lt;em&gt;will&lt;/em&gt; find a lot of them, and detection this way is a lot more comprehensive than manual testing and a lot faster than waiting for customers to complain.&lt;/p&gt;
&lt;p&gt;There are (at least) 4 types of error scenarios that you&#39;re going to want to eliminate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;restarts&lt;/li&gt;
&lt;li&gt;time-outs&lt;/li&gt;
&lt;li&gt;500s&lt;/li&gt;
&lt;li&gt;logged errors&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Restarts&lt;/h3&gt;
&lt;p&gt;Assuming you&#39;ve got a service manager to restart your application when it fails and a cluster manager to restart a chlid process when one fails (like I talked about in &lt;a href=&quot;/blog/2014/06/01/production-quality-node-dot-js-web-apps-part-i/&quot;&gt;Part I&lt;/a&gt;), one of the worst types of error-scenarios that you&#39;re likely to encounter will be when a child process dies and has to restart.  It&#39;s a fairly common mistke to believe that once you have automatic restarting working, process failure is no longer a problem.  That&#39;s really only the beginning of a solution to the problem though.  Here&#39;s why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Node.js is built to solve the &lt;a href=&quot;http://www.kegel.com/c10k.html&quot;&gt;C10K problem&lt;/a&gt;, so you should expect to have a high number of requests per process in progress at any given time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The node process itself handles your web-serving, and there&#39;s no built-in request isolation like you might find in other frameworks like PHP, where one request can&#39;t have any direct effects on another request.  With a node.js web application, any uncaught exception or unhandled &lt;code&gt;error&lt;/code&gt; event will bring down the entire server, including your thousands of connections in progress.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Node.js&#39;s asynchronous nature and multiple ways to express errors (exceptions, error events, and callback parameters) make it difficult to anticipate or catch errors more holistically as your codebase gets larger, more complex, and has more external or 3rd-party dependencies.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These three factors combine to make restarts both deadly and difficult to avoid unless you&#39;re very careful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Detection&lt;/strong&gt;: The easiest way to detect these is to put metrics and logging at the earliest place in both your cluster child code and your cluster master code to tell you when the master or child processes start.  If you want to remove the noise caused by new servers starting up, or normal deployments, then you may want to write something a little more complex that can specifically detect abnormal restarts (I&#39;ve got a tiny utility for that called &lt;a href=&quot;https://github.com/cainus/restart-o-meter&quot;&gt;restart-o-meter&lt;/a&gt; too).&lt;/p&gt;
&lt;p&gt;You might have an aggregated logging solution than can send you alerts based on substrings that it finds in the logs too, or that can feed directly into a time-series metrics system.&lt;/p&gt;
&lt;h3&gt;Time-outs&lt;/h3&gt;
&lt;p&gt;Time-outs are another type of failed request, where the server didn&#39;t respond within some threshold that you define.  This is pretty common if you forget to call &lt;code&gt;res.end()&lt;/code&gt;, or a response just takes too long.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Detection&lt;/strong&gt;:  You can just write a quick and dirty middleware like this to detect them:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  timeoutThreshold &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 10 seconds&lt;/span&gt;
  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timeoutCheck &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;slowRequest&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;slow request: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;method&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toUpperCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; timeoutThreshold&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;finish&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;clearTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timeoutCheck&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(or you can grab &lt;a href=&quot;https://www.npmjs.org/package/connect-settimeout&quot;&gt;this middleware I wrote&lt;/a&gt; that does basically the same thing).&lt;/p&gt;
&lt;h3&gt;500s&lt;/h3&gt;
&lt;p&gt;On a web application, one of the first things I want to ensure is that we&#39;re using proper status codes.  This isn&#39;t just HTTP nerd talk (though no one will say I&#39;m innocent of that), but rather a great system of easily categorizing the nature of your traffic going through your site.  I&#39;ve written about &lt;a href=&quot;/blog/2013/04/21/3-terrible-anti-patterns-for-error-handling-in-rest-apis/&quot;&gt;the common anti-patterns here&lt;/a&gt;, but the gist of it is:&lt;/p&gt;
&lt;h5&gt;Respond with 500-level errors if the problem was a bug in your app, and not in the client.&lt;/h5&gt;
&lt;p&gt;This lets you know that there was a problem, and it&#39;s your fault.  Most likely you only ever need to know &lt;code&gt;500 Internal Server Error&lt;/code&gt; to accomplish this.&lt;/p&gt;
&lt;h5&gt;Respond with 400-level errors if the problem was a bug in the client.&lt;/h5&gt;
&lt;p&gt;This lets you know that there was a problem and it was the client app&#39;s fault.  If you learn these 4 error codes, you&#39;ll have 90% of the cases covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;400 Bad Request  -- When it&#39;s a client error, and you don&#39;t have a better code than this, use this.  You can always give more detail in the response body.&lt;/li&gt;
&lt;li&gt;401 Not Authenticated -- When they need to be logged in, but aren&#39;t.&lt;/li&gt;
&lt;li&gt;403 Forbidden -- When they&#39;re not allowed to do do something&lt;/li&gt;
&lt;li&gt;404 Not Found -- When a url doesn&#39;t point to an existing thing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you don&#39;t use these status codes properly, you won&#39;t be able to distinguish between:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;successes and errors&lt;/li&gt;
&lt;li&gt;errors that are the server&#39;s responsibility and errors that are the client&#39;s responsibility.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These distinctions are dead-simple to make and massively important for determining if errors are occuring, and if so, where to start debugging.&lt;/p&gt;
&lt;p&gt;If you&#39;re in the context of a request and you know to expect exceptions or error events from a specific piece of code, but don&#39;t know/care exactly what type of exception, you&#39;re probably going to want to log it with console.error() and respond with a 500, indicating to the user that there&#39;s a problem with your service.  Here are a couple of common scenarios:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the database is down, and this request needs it&lt;/li&gt;
&lt;li&gt;some unexpected error is caught&lt;/li&gt;
&lt;li&gt;some api for sending email couldn&#39;t connect to the smtp service&lt;/li&gt;
&lt;li&gt;etc, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are all legitimate 500 scenarios that tell the user &amp;quot;hey the problem is on our end, and there&#39;s no problem with your request.  You may be able to retry the exact same request later&amp;quot;.  A number of the &amp;quot;unexpected errors&amp;quot; that you might catch though will indicate that your user actually did send some sort of incorrect request.  In that case, you want to respond with a reasonable 4xx error instead (often just a 400 for &amp;quot;Bad Request&amp;quot;) that tells them what they did wrong.&lt;/p&gt;
&lt;p&gt;Either way, you generally don&#39;t want 500s at all.  I get rid of them by fixing the issues that caused them, or turning them into 4xxs where appropriate (eg. when bad user input is causing the 500), to tell the client that the problem is on their end.  The only times that I don&#39;t try to change a response from a 500 is when it really is some kind of internal server error (like the database is down), and not some programming error on my part or a bad client request.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Detection&lt;/strong&gt;:  500s are important enough that you&#39;re going to want to have a unified solution for them.  There should be some simple function that you can call in all cases where you plan to respond with a 500 that will log your 500, the error that caused it, and the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack&quot;&gt;.stack property&lt;/a&gt; of that error, as well as incrementing a metric, like so:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;internalServerError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;500 &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;method&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Internal Server Error&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;internalServerError&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;statusCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having a unified function you can call like this (possibly monkey-patched onto the response object by a middleware, for convenience) gives you the ability to change how 500&#39;s are logged and tracked everywhere, which is good, because you&#39;ll probably want to tweak it fairly often.&lt;/p&gt;
&lt;p&gt;You&#39;re probably actually going to use this on &lt;em&gt;most&lt;/em&gt; asynchronous functions in your HTTP handling code (controllers?) that you call that you don&#39;t expect an error on.  Here&#39;s an example:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;someId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;internalServerError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Internal Server Error&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// and normal stuff with the user object goes here&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, I just expect to get a user back, and not get any errors (like the database is disconnected, or something), so I just put the 500 handler in the case that an &lt;code&gt;err&lt;/code&gt; object is passed, and go back to my happy-path logic.  If 500s start to show up there at runtime, I&#39;ll be able to decide if they should be converted to a 4xx error, or fixed.&lt;/p&gt;
&lt;p&gt;For example if I start seeing errors where err.message is &amp;quot;User Not Found&amp;quot;, as if the client requested a non-existant user, I might add 404 handling like so:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;someId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;User Not Found&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;User not found!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;internalServerError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Internal Server Error&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// and normal stuff with the user object goes here&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Conversely, if I start seeing errors where err.message is &amp;quot;Database connection lost&amp;quot;, which is a valid 500 scenario, I might not add any specific handling for that scenario.  Instead, I&#39;d start looking into solving how the database connection is getting lost.&lt;/p&gt;
&lt;p&gt;If you&#39;re building a JSON API, I&#39;ve got a great middleware for unified error-handling (and status codes in general) called &lt;a href=&quot;https://github.com/cainus/json-status&quot;&gt;json-status&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A unified error handler like this leaves you with the ability to expand all internal server error handling later too, when you get additional ideas.  For example, We&#39;ve also added the ability for it to log the requesting user&#39;s information, if the user is logged in.&lt;/p&gt;
&lt;h3&gt;Logged Errors&lt;/h3&gt;
&lt;p&gt;I often make liberal use of &lt;code&gt;console.error()&lt;/code&gt; to log errors and their &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack&quot;&gt;.stack properties&lt;/a&gt; when debugging restarts and 500s, or just reporting different errors that shouldn&#39;t necessarily have impact on the http response code (like errors in fire-and-forget function calls where we don&#39;t care about the result enough to call the request a failure).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Detection&lt;/strong&gt;:  I ended up adding a method to &lt;code&gt;console&lt;/code&gt; called &lt;code&gt;console.flog()&lt;/code&gt; (You can name the method whatever you want, instead of &#39;flog&#39; of course!  I&#39;m just weird that way.) that acts just like &lt;code&gt;console.error()&lt;/code&gt; (ultimately by calling it with the same arguments), but also increments a &amp;quot;logged error&amp;quot; metric like so:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;flog&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;increment&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;loggedErrors&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    &lt;span class=&quot;token comment&quot;&gt;// assume `metrics` is required earlier&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; args &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arguments&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unshift&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;LOGGED ERROR:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    &lt;span class=&quot;token comment&quot;&gt;// put a prefix on error logs to make them easier to search for&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  

  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;console&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this in place, you can convert all your &lt;code&gt;console.error()&lt;/code&gt;s to &lt;code&gt;console.flog()&lt;/code&gt;s and your metrics will be able to show you when logged errors are increasing.&lt;/p&gt;
&lt;p&gt;It&#39;s nice to have it on &lt;code&gt;console&lt;/code&gt; because it sort of makes sense there and console is available everywhere without being specifically &lt;code&gt;require()&lt;/code&gt;ed.  I&#39;m normally against this kind of flagrant monkey-patching, but it&#39;s really just &lt;em&gt;too&lt;/em&gt; convenient in this case.&lt;/p&gt;
&lt;h4&gt;Log Levels&lt;/h4&gt;
&lt;p&gt;I should note too that I don&#39;t use traditional log levels (error/debug/info/trace) anymore, because I don&#39;t find them all that useful.  I&#39;m logging everything as an error or not, and I generally just strive to keep the logs free of everything other than lines that indicate the requests being made like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ...
  POST /api/session 201
  GET /api/status 200
  POST /api/passwordReset 204
  GET /api/admin.php 404
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That doesn&#39;t mean that I don&#39;t sometimes need debug output, but it&#39;s so hard to know what debug output I need in advance that I just add it as needed and redeploy.  I&#39;ve just never found other log-levels to be useful.&lt;/p&gt;
&lt;h2&gt;More About Metrics&lt;/h2&gt;
&lt;p&gt;All of the efforts above have been to make defects self-reporting and visible.  Like I said in the first part of this series, the greatest supplement to logging that I&#39;ve found is the time-series metrics graph.  Here&#39;s how it actually looks (on a live production system) in practice for the different types of defects that have been discussed here.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/bad_stuff-600w.webp 600w, /images/bad_stuff-900w.webp 900w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;/images/bad_stuff-600w.jpeg 600w, /images/bad_stuff-900w.jpeg 900w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;metrics : restarts, 500s, logged errors, timeouts&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/bad_stuff-600w.jpeg&quot; width=&quot;900&quot; height=&quot;354&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The way to make metrics most effective, is to keep them on a large video display in the room where everyone is working.  It might seem like this shouldn&#39;t make a difference if everyone can just go to their own web browsers to see the dashboard whenever they want, but it absolutely has a huge difference in impact.  Removing that minor impediment and just having metrics always available at a glance results in people checking them far more often.&lt;/p&gt;
&lt;p&gt;Without metrics like this, and a reasonable aggregated logging solution, you are really flying blind, and won&#39;t have any idea what&#39;s going on in your system from one deployment to the next.  I personally can&#39;t imagine going back to my old ways that didn&#39;t have these types of instrumentation.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Production-Quality Node.js Web Apps : Part I, The Basics</title>
		<link href="/posts/2014-06-02-production-quality-node-dot-js-web-apps-part-i/"/>
		<updated>2014-06-01T17:09:00Z</updated>
		<id>/posts/2014-06-02-production-quality-node-dot-js-web-apps-part-i/</id>
		<content type="html">&lt;p&gt;I&#39;ve been working on production-quality node.js web applications for a couple of years now, and I thought it&#39;d be worth writing down some of the more interesting tricks that I&#39;ve learned along the way.&lt;/p&gt;
&lt;p&gt;I&#39;m mostly going to talk about maintaining a low-defect rate and high availability, rather than get into the details about scaling that are covered in a lot of other places.   In particular, I’ll be talking about load-balancing, process management, logging, and metrics, and the how’s and why’s of each.&lt;/p&gt;
&lt;h3&gt;Balance the Load&lt;/h3&gt;
&lt;p&gt;I&#39;m going to assume that you&#39;re already load-balancing on a given server with &lt;a href=&quot;http://nodejs.org/api/cluster.html&quot;&gt;cluster&lt;/a&gt; or some higher level abstraction ( I use &lt;a href=&quot;https://github.com/isaacs/cluster-master&quot;&gt;cluster-master&lt;/a&gt;) as well as between servers with a load-balancer like &lt;a href=&quot;http://haproxy.1wt.eu/&quot;&gt;ha-proxy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Performance considerations aside, your service will have much better availability, quality, and uptime if you&#39;ve got multiple processes running on multiple machines.  More specifically, you get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the ability to immediately failover in the case of single process or single machine failure&lt;/li&gt;
&lt;li&gt;reduced overall service failure in the case of single process or single machine failure&lt;/li&gt;
&lt;li&gt;the ability to gracefully deploy with the load-balancer&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Gracefully Deploy&lt;/h3&gt;
&lt;p&gt;Gracefully deploying means that your deploy process has enough servers running to handle the load at all times throughout the actual deployment process, and that none of the servers are taken off-line while outstanding requests are still in progress.  This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Your clustering solution must be able to stop new connections and not exit the master process until all servers have finished processing their existing requests.  The solution I personally use is &lt;a href=&quot;https://github.com/isaacs/cluster-master&quot;&gt;cluster-master&lt;/a&gt;, but there are bunch of suitable alternatives.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You need a rolling deployment, meaning that servers are restarted one-at-a-time, or in small groups, rather than all at once.  The easiest way to do this is probably to write a nice deploy script that takes restarting servers out of the load-balancer until they&#39;re running again.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you don&#39;t have a graceful deploy solution, every deployment of new code will lose requests in progress, and your users will have a terrible experience.&lt;/p&gt;
&lt;p&gt;Also note: I&#39;ve seen a few clustering solutions that use some sort of hot-deploy (hot-deploy loads a new version of code without taking the server down) functionality.  If you&#39;ve got a rolling deploy via your load balancer though, you probably &lt;em&gt;don&#39;t&lt;/em&gt; need any sort of hot-deploy functionality.  I&#39;d personally avoid solutions that involve the complexity of hot-deploying.&lt;/p&gt;
&lt;h3&gt;Run as a Service&lt;/h3&gt;
&lt;p&gt;You&#39;re also going to want to be running your app as a service that the OS knows to restart with some service manager like &lt;a href=&quot;http://caolanmcmahon.com/posts/deploying_node_js_with_upstart/&quot;&gt;upstart&lt;/a&gt;.  A service manager like this is going to be absolutely essentially for when your node.js app crashes, or when you spin up new machines.&lt;/p&gt;
&lt;p&gt;It&#39;s probably worth noting that you won&#39;t really want to use something like &lt;a href=&quot;https://github.com/nodejitsu/forever&quot;&gt;forever&lt;/a&gt; or &lt;a href=&quot;http://nodemon.io/&quot;&gt;nodemon&lt;/a&gt; in production, because it doesn&#39;t survive reboots, and is pretty redundant once you&#39;ve added service management that actually does (This is a case where you don&#39;t want redundancy, because these types of process managers can end up fighting with each other to restart the app, thus never really allowing the app to start).&lt;/p&gt;
&lt;h4&gt;Log to Standard Output&lt;/h4&gt;
&lt;p&gt;Logging to standard output (using &lt;code&gt;console.log()&lt;/code&gt;) and standard error (using &lt;code&gt;console.error()&lt;/code&gt;) is the simplest and most powerful way to log.  Here&#39;s how:&lt;/p&gt;
&lt;h5&gt;pipe it, don&#39;t write it&lt;/h5&gt;
&lt;p&gt;In the config file for running your app, you want something like this to specify a log file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; server.js &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; /var/log/myserver.log &lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;2&lt;/span&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;&amp;amp;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; tells your node process to append output to the specified log file and the &lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; tells it that both standard out and standard error should go to that same log file.  You don&#39;t want to be writing to the logs programmatically from within the node process, because you will miss any output that you don&#39;t specifically log, like standard error output from node.js itself which happens anytime that your server crashes.  That kind of information is too critical to miss.&lt;/p&gt;
&lt;h5&gt;console is the only &amp;quot;logging library&amp;quot; you need&lt;/h5&gt;
&lt;p&gt;With this kind of logging set up, I just have to &lt;code&gt;console.log()&lt;/code&gt; for any debug output that I need (usually just temporarily for a specific issue that I&#39;m trying to solve), or &lt;code&gt;console.error()&lt;/code&gt; for any errors I encounter.&lt;/p&gt;
&lt;p&gt;Additionally, one of the first things I do on a new web service is to set up a &lt;code&gt;console.log()&lt;/code&gt; for each request (this should work in any &lt;code&gt;express&lt;/code&gt; or &lt;code&gt;connect&lt;/code&gt; app):&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;  app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;finish&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;method&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;statusCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This chunk of code gives me nice simple logs for every request that look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;...
POST /api/session 400
POST /api/session 401
POST /api/session 200
GET /api/status 200
GET /api/status 200
...
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;rotating the logs&lt;/h5&gt;
&lt;p&gt;The missing infrastructure needed to support this is a way to rotate the logs, like &lt;a href=&quot;http://www.rackspace.com/knowledge_center/article/understanding-logrotate-part-1&quot;&gt;logrotate&lt;/a&gt;.  Once that&#39;s set up properly, your logs will rotate for you nicely and not fill up your disk on you.&lt;/p&gt;
&lt;h2&gt;Tools to Help Detect Problems at Runtime&lt;/h2&gt;
&lt;p&gt;There are two basic key ways that I like to instrument an application to detect problems that occur at runtime: Aggregated logging and metrics.&lt;/p&gt;
&lt;h4&gt;Agreggated Logging&lt;/h4&gt;
&lt;p&gt;One of the most important things you can do for error and defect detection is to have aggregated logging -- some service that brings all your web servers&#39; logs together into one large searchable log.  There are a few products for this:  The stand-out open source one for me seemed to be the &lt;a href=&quot;http://www.elasticsearch.org/overview/kibana/&quot;&gt;logstash/kibana combination&lt;/a&gt;, though these days I&#39;m lazy and generally use the &lt;a href=&quot;https://papertrailapp.com/&quot;&gt;papertrail service&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;I would highly recommend that you set a service like this up immediately, because the small amount of friction involved in &lt;code&gt;ssh&lt;/code&gt;ing into servers to &lt;code&gt;tail&lt;/code&gt; logs is enough to seriously reduce how often you and your teammates will actually look at the logs. The sooner you set this up, the sooner you can benefit from being able to learn about your application through the logs that you have it write.&lt;/p&gt;
&lt;h4&gt;Metrics&lt;/h4&gt;
&lt;p&gt;When I say &amp;quot;metrics&amp;quot; I really mean time-series metrics, that allow me to see the frequency of different types of events over time.  These are invaluable because they&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tell you when something unusual is happening&lt;/li&gt;
&lt;li&gt;aggregate certain types of data in ways that logs can&#39;t&lt;/li&gt;
&lt;li&gt;help you rally the team or company around specific high-value goals (be careful with this one!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The stand-out metrics/graphic open source product is probably &lt;a href=&quot;http://graphite.wikidot.com/&quot;&gt;graphite&lt;/a&gt;.  I&#39;ve generally been using &lt;a href=&quot;https://metrics.librato.com&quot;&gt;Librato&#39;s metrics service&lt;/a&gt; though because it&#39;s easy to set up, and looks great, so that&#39;s where I&#39;ll pull my screenshots from for time-series data.  I&#39;ve also had a pretty good experience with &lt;a href=&quot;http://datadog.com&quot;&gt;DataDog&#39;s service&lt;/a&gt; as well.  Both also come with the ability to raise alerts when a metric surpasses a threshold, which can be a nice way to know when something is going on that you should investigate.&lt;/p&gt;
&lt;h5&gt;Basic Metrics&lt;/h5&gt;
&lt;p&gt;There are a bunch of basic metrics that you can track to see what&#39;s going on in your server.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of some very high-level metrics for us over a week:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/metrics_requests_duration-600w.webp 600w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;metrics : number of requests vs average duration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/metrics_requests_duration-600w.jpeg&quot; width=&quot;600&quot; height=&quot;251&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;in blue: number of requests&lt;/li&gt;
&lt;li&gt;in green: average duration of requests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(Note that at this resolution, the y-values are averages over such long durations that the values aren&#39;t really that useful at face value; it&#39;s the visualization of general trends that is useful.)&lt;/p&gt;
&lt;p&gt;There are a few obvious things that should jump out right away in this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have daily traffic spikes with 5 peaks really standing out and 2 being almost flat (those happen to be Saturday and Sunday).&lt;/li&gt;
&lt;li&gt;We had a spike in average request duration (on Friday morning -- the third peak).  This was caused by some performance issues with our database, and resulted in service outage for a number of our users during that time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can basically put &lt;code&gt;metrics.increment(&amp;quot;someEventName&amp;quot;);&lt;/code&gt; anywhere in my codebase to tell my metrics service when a particular event occurred.&lt;/p&gt;
&lt;p&gt;Also consider OS metrics like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;disk space usage&lt;/li&gt;
&lt;li&gt;cpu utilization&lt;/li&gt;
&lt;li&gt;memory consumption&lt;/li&gt;
&lt;li&gt;etc, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;ve got my codebase set up so that &lt;code&gt;metrics.gauge(&amp;quot;someMetricName&amp;quot;, value);&lt;/code&gt; will allow me to graph specific values like these over time as well.&lt;/p&gt;
&lt;p&gt;If you&#39;re not already doing monitoring like this, you must be wondering what your servers would tell you.  When it&#39;s this easy, you tend to do it all the time and get all kinds of interesting metrics including more business-specific metrics.&lt;/p&gt;
&lt;h2&gt;What next?&lt;/h2&gt;
&lt;p&gt;These are really just the basics.  If you&#39;re not doing these things, and you care about running a production-quality web service, you&#39;re probably putting yourself at a disadvantage.&lt;/p&gt;
&lt;p&gt;There is a lot more that you can do though, and I&#39;ll get into that in my next post, which will be Part II to this one.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>In Defence Of The Office</title>
		<link href="/posts/2014-06-02-in-defence-of-the-office/"/>
		<updated>2014-01-11T22:51:15Z</updated>
		<id>/posts/2014-06-02-in-defence-of-the-office/</id>
		<content type="html">&lt;p&gt;I&#39;ve been reading the 37 signals book &lt;a href=&quot;http://37signals.com/remote/&quot;&gt;Remote&lt;/a&gt; lately and it&#39;s got me thinking a lot about the advantages and disadvantages of working remotely.  While they clearly acknowledge that there are trade-offs to working remotely, I personally don&#39;t think they paint a very clear picture of just how expensive those trade-offs are.  I can only really speak from a software development perspective, but I think this might apply to other types of businesses where a high degree of collaboration is necessary and the concept of &amp;quot;team&amp;quot; is more than just &amp;quot;a group of people&amp;quot;.&lt;/p&gt;
&lt;p&gt;After 7 or 8 years of being a home-based contract-worker, and close to the same time spent working in various office environments, I&#39;ve found that with the right people and the right environment, the office can be a lot more productive (and actually enjoyable) than a home environment, for a number of reasons.&lt;/p&gt;
&lt;p&gt;Skype / Google Hangouts / Webex pale in comparison to actually being in the same room as someone else.  I can&#39;t explain why, because it seems to me like it should be good enough (and I really wish it were sometimes), but the fact of the matter is that it&#39;s not.  You miss nuances in communication that can add up to big differences in productivity.   I&#39;ve been in hours and hours of pair programming sessions over webex: it doesn&#39;t match the high-bandwidth of shoulder-to-shoulder pairing.  I&#39;ve done the shared whiteboard thing: it doesn&#39;t match the speed and simplicity of an actual whiteboard.&lt;/p&gt;
&lt;p&gt;With communication over today&#39;s technological mediums, there&#39;s just a natural tendency to end the interaction as soon as possible &amp;quot;and get back to work&amp;quot; too, where people don&#39;t actually leave Skype / Google hangouts / webex running all day long.  The result is that people are reluctant to start new conversations like that because they&#39;re worried about interrupting the other person.  So people naturally fall back on less intrusive means of communication (text chat) and often even further back to more asynchronous forms of communication (email).&lt;/p&gt;
&lt;p&gt;And asynchronous communication is not the boon to productivity that people think it is.  Email is today&#39;s definitive means of asynchronous communication, but I think it&#39;s pretty obvious that there are few methods of communication that are less efficient.  Imagine a sports team that can only communicate by email.  That would be ridiculous.  Email is amazing at its ability to cut down on interruptions of course, but it&#39;s at the obvious cost of timeliness and immediacy (not to mention the very real human aspects including general tone and emotional nuances!).&lt;/p&gt;
&lt;p&gt;The ideal solution would be to solve the problem of interruptions without losing timeliness.&lt;/p&gt;
&lt;p&gt;Explaining this really requires actually defining an &amp;quot;interruption&amp;quot;:  When you&#39;re on a team and someone wants to talk to you about the main goal of the team, that&#39;s decidedly NOT an interruption.  Imagine a quarterback being annoyed by the &amp;quot;interruption&amp;quot; of someone yelling that they&#39;re open for a pass.  Imagine a soldier in a firefight being annoyed at another soldier for requesting cover fire prior to some forward manoeuvring.  In order for something to really be an interruption, you have to be working on a different priority than the other person, one that you think is of higher priority.&lt;/p&gt;
&lt;p&gt;In a collaborative environment, interruptions should often be viewed as a symptom, and not the actual cause, of the problem.  To solve the problem of interruptions at the root, you&#39;ve got to clearly define the priorities of the team, aligning everyone on those, and concentrating as many people as possible on the top goal rather than going the easy route (management-wise) and doing something like giving each of the X members of the team one of the top X priorities, effectively &amp;quot;&lt;a href=&quot;http://brodzinski.com/2013/11/multitasking-teams.html&quot;&gt;team-multi-tasking&lt;/a&gt;&amp;quot;.  Team-multi-tasking is a common approach because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It&#39;s the easiest thing to do management-wise (Why bother prioritizing when I can have X tasks worked on at once?).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It feels like you&#39;re getting more done, because so many things are in progress at once.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It ensures everyone is 100% utilized.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But it&#39;s also pretty obviously the absolute slowest way to get your top priority shipped and to start getting value from it  (and often &lt;a href=&quot;http://www.startuplessonslearned.com/2011/09/power-of-small-batches.html&quot;&gt;the slowest way to get them all done&lt;/a&gt;, believe it or not!).&lt;/p&gt;
&lt;p&gt;Not only that, but the more you do this, the more people tend to specialize into roles like &amp;quot;the back-end guy&amp;quot; or the &amp;quot;&lt;a href=&quot;http://en.wikipedia.org/wiki/DevOps&quot;&gt;ops guy&lt;/a&gt;&amp;quot;, etc, and individuals lose the ability to be cross-functional, and to practice &lt;a href=&quot;http://www.extremeprogramming.org/rules/collective.html&quot;&gt;collective code ownership&lt;/a&gt;.  It&#39;s a vicious cycle too: the more an individual tends toward deep specialization, the more we&#39;re tempted to give them that kind of work because they&#39;re the best at it.    Not only does your &lt;a href=&quot;http://en.wikipedia.org/wiki/Bus_factor&quot;&gt;bus factor&lt;/a&gt; skyrocket, but you get back into these scenarios where anytime someone engages someone else for help, it&#39;s an interruption to that other person, so people tend to not ask for help when they really should, or they use dog-slow asynchronous methods (like email).  Breaking this cycle means constantly trying to break down these specialty silos for any given specialty by having more experienced people collaborate with (and often mentor) less experienced people.  The end result is a team that &lt;em&gt;makes&lt;/em&gt; full-stack engineers and not just one that hires them.&lt;/p&gt;
&lt;p&gt;I find that the right mindset for the team is to create an environment that would be best for a team working on only 1 super-important thing that you want to start getting value from as soon as possible.  A general rule of thumb is:  If you&#39;re having a text conversation with someone in the same room, you&#39;re doing it wrong.  I know that&#39;s common, but if you think about it, it&#39;s pretty absurd.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How would that environment look?&lt;/strong&gt;  It would be a &amp;quot;&lt;a href=&quot;http://www.sciencedaily.com/releases/2000/12/001206144705.htm&quot;&gt;warroom&lt;/a&gt;&amp;quot; for &lt;a href=&quot;http://www.ibimapublishing.com/journals/CIBIMA/2010/959194/959194.pdf&quot;&gt;radically collocating&lt;/a&gt; the team.  Everyone that needs to be there would be there, arranged in a manner that&#39;s most effective for verbal communication.  There would be nearby whiteboards for collaborative design sessions, and &lt;a href=&quot;http://alistair.cockburn.us/Information+radiator&quot;&gt;information radiators&lt;/a&gt; to show the progress of the efforts and various other metrics of the current state of affairs by just glancing up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How would the team behave?&lt;/strong&gt;  They would be a &amp;quot;tiger team&amp;quot;.  They would all be helping to get that one thing out the door.  They would almost never use any electronic means to communicate (except obviously, when it&#39;s more efficient, like sharing chunks of code, or urls), and you&#39;d never hear someone say &amp;quot;that&#39;s not my job&amp;quot;.  If someone is the only person that knows how to do something, the team identifies them as a process choke-point and quickly tries to get others up to speed on that skill or responsibility (and not by giving them links to docs or occasional hints, but by super-effective methods like &lt;a href=&quot;http://www.extremeprogramming.org/rules/pair.html&quot;&gt;pair programming&lt;/a&gt;, in-person demonstration, and actual verbal discussion).  If one member of the team appears to be stuck, he asks for help, and if he doesn&#39;t, the other members notice, and jump in to help, unprompted.  There are no heroes, and everyone takes responsibility for everything that the team is tasked with.  This can and should be taken to extremes too:  members should drop their egos and make themselves available to do grunt work or testing for other members -- whatever gets the top priority shipped as soon as reasonably (and sustainably) possible.  This includes making yourself vulnerable enough to ask for help from others, not only for tricky aspects of your work, but also just to divide your work up better.  If you&#39;re taking longer than expected on a given task, you should be conscious enough of that to be openly discussing it with the team, including possible solutions, and not trying to be a hero or a martyr.  Conversely, you should never be waiting for extended periods of time for your teammate to do some work that you depend on for something else.  If a teammate is taking longer than usual, jump in and help.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How would management work then?&lt;/strong&gt;  The team should self-organize.  With clear priorities set, the team can and should, for the most part, self-direct.  A manager should not try to manage the avalanche of interactions that happen during free-collaboration throughout the day.  Trying to manage who works on what, will simply make that manager a choke-point and slow the process down (and he/she will inevitably be wrong more than right, compared to the wisdom of the entire team).  Often a non-technical manager can have the advantage over more technical managers, because he&#39;s forced to trust the team&#39;s decisions and doesn&#39;t become an &amp;quot;approval choke-point&amp;quot; for the team&#39;s engineering decisions.&lt;/p&gt;
&lt;p&gt;That doesn&#39;t mean a management role is unnecessary though; it&#39;s actually quite demanding to manage a team like this.  Priorities must always be crystal clear and for the most part, the top few priorities being worked on should not change very often.  If they do change often, you usually have either a management problem or a product quality problem.  Those problems should be fixed at the root as well, rather than making developers feel like management or customers are just a constant stream of interruptions.  Keep in mind that if you do change the top priority often enough, you can completely prevent the team from any progress at all (I&#39;ve spent months on a team like that before -- it&#39;s not fun for anyone).  (For a more complete description of the ideal responsibilities for this style of management, see &amp;quot;The Management&amp;quot; &lt;a href=&quot;/blog/2013/05/07/a-requiem-for-a-team/&quot;&gt;here&lt;/a&gt; )&lt;/p&gt;
&lt;p&gt;Does this work for all types of people?  No.  But then again, you&#39;ll never get a fast team of developers without hiring the right people.  If you have people on the team that are incapable of being team-players, it&#39;s certainly not going to work (and you&#39;ll likely have a number of problems).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What if we have TWO top priorities though?&lt;/strong&gt;  Flip a coin and pick one; It&#39;s that simple.  Just arbitrarily choosing one will get one of them shipped and returning value as soon as possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What about team member X that has nothing to do?&lt;/strong&gt;  The team should recognize this and:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;try to break down the tasks better so they can help (it&#39;s often worth a 30 minute session to bring other people on board -- Any given task can almost always be broken down further with additional design discussion, even if its not worth dividing up the work).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;try to get them pair-programming so they can learn to help better.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;try to get them testing the parts that are done.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Obviously in some scenarios it might make sense for them to start on the second priority, but they should be ready to drop that work at any time to help get priority #1 out the door faster.  &lt;strong&gt;Remember:&lt;/strong&gt; the goal is to ship finished features faster.  It&#39;s not to keep the people on the team as busy as possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Isn&#39;t that really tough on the developers to rarely have quiet time to concentrate?&lt;/strong&gt;  Yes, at first it often is, often because focusing on the top priority requires discipline because it&#39;s different from the status quo.  And people simply aren&#39;t used to the buzz in the room.  The longer you spend working with headphones on, trying to carve out your own niche, separate from the rest of the team, the longer it will take you to transition and the harder that transition will be.  But soon you learn to ignore the irrelevant buzz in the room and to tune back in quickly when it&#39;s important and relevant.  And since you&#39;re all working on the same thing, it&#39;s often relevant, and lot less difficult to get back into the &lt;a href=&quot;http://psygrammer.com/2011/02/10/the-flow-programming-in-ecstasy/&quot;&gt;flow state&lt;/a&gt; than you&#39;d expect (especially if pair programming).  So the pay-off for developers is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;huge productivity improvements&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;less waiting for someone else to do their part&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;longer sessions in &amp;quot;flow state&amp;quot; and easier returns to flow state&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;less solitude without adding interruptions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;less &amp;quot;all the weight is on my shoulders&amp;quot; scenarios&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;more knowledge sharing and personal development&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It helps a lot if developers take breaks more often, because you actually end up spending a lot more time in the flow state in a given day.  You end up learning more from other developers and being vastly more productive as well, which is exhausting and energizing at the same time.  In my opinion, when done right, it&#39;s just a lot more fun than isolated development.&lt;/p&gt;
&lt;p&gt;Of course it often also helps to have break-out rooms for smaller prolonged conversation when desired as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But what if you have dozens of engineers?&lt;/strong&gt;  It&#39;s just not reasonable to try to make teams that contain dozens of engineers.  &lt;a href=&quot;http://en.wikipedia.org/wiki/Brooks%27s_law&quot;&gt;Brooks&#39; law&lt;/a&gt; has seemed to hold fairly well over time and he explains that one reason is that the more people you add to a group, the more communication overhead there is.  I&#39;ve personally seen this as well, with team-size starting to get diminishing returns between  8 and 12 people, with little value (if any) to adding members beyond that.  When you get beyond 8 people on a given team, you need to start thinking about creating a second team.  &lt;a href=&quot;http://en.wikipedia.org/wiki/Conway%27s_law&quot;&gt;Conway&#39;s Law&lt;/a&gt; seems to dictate that a &lt;a href=&quot;http://en.wikipedia.org/wiki/Service-oriented_architecture&quot;&gt;service-oriented architecture&lt;/a&gt; is the best solution we&#39;re going to get for scaling up an organization&#39;s developer head-count, but I&#39;ve personally found that smaller codebases with distinct responsibilities are generally better codebases anyway.&lt;/p&gt;
&lt;p&gt;With all that said, of course I really wish I could work remotely sometimes and get all the same benefits.  I&#39;ve simply never seen a telepresence technology set-up that matches the fidelity of actual face-to-face and shoulder-to-shoulder collaboration.  Maybe it exists.  I&#39;d love to hear about it.  But my experience simply doesn&#39;t indicate that the current status quo technologies (skype, webex, etc), like Remote recommends, are up to snuff.  The way it stands today, I&#39;ll almost always put my money on a collocated group of &lt;a href=&quot;http://avichal.wordpress.com/2011/12/16/focus-on-building-10x-teams-not-on-hiring-10x-developers/&quot;&gt;&amp;quot;team-players&amp;quot;&lt;/a&gt; over a geographically disparate team of &amp;quot;gurus&amp;quot;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>You probably don’t need to version your web API.</title>
		<link href="/posts/2014-06-02-you-probably-dont-need-to-version-your-web-api/"/>
		<updated>2013-09-14T01:47:31Z</updated>
		<id>/posts/2014-06-02-you-probably-dont-need-to-version-your-web-api/</id>
		<content type="html">&lt;p&gt;So you’re thinking about versioning your web API somehow.  Versioning is how we annotate and manage changes in software libraries, so it seems natural to re-apply this solution to changes in web APIs.  Most web APIs are versioned in order to…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;( A ) “freeze” an older version somehow so that it doesn’t change for older clients, or at least it is subjected to much less change than newer versions, so you can still move forward.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;( B ) be able to deprecate older APIs that you no longer wish to support.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;( C ) indicate that changes have occurred and represent a large batch of changes at once when communicating with others.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;However…&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;( A )  Versions don’t actually solve the problem of moving forward despite older clients.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can safely break backward compatibility with or without the concept of versions: just create a new endpoint and do what you want there.  It doesn’t need to have any impact on the old endpoint at all.  You don’t need the concept of “versions” to do that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;( B ) Versions don’t actually solve the problem of deprecating old endpoints.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At best, versions just defer the problem, while forcing you to pay the price of maintaining two sets of endpoints until you actually work out a real change management strategy.  If you have an endpoint that you want to retire, you’re going to have to communicate that to all your clients that you’re deprecating it, regardless of whether or not you’ve “versioned” it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;( C )  Versions DO help you communicate about changes in a bunch of endpoints at once.  But you shouldn’t do this anyway.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Of course, if you’re retiring 20 endpoints at once, it’s easier to say “we’re retiring version 1” than to say “we’re retiring the following endpoints…” (and then list all 20), but why would you want to drop 20 breaking-change notices on your clients all at once?  Tell your clients as breaking changes come up, and tell them what sort of grace period they get on those changes.  This gives you fine-grained control over your entire API, and you don’t need to think about a new version for the entire API every time you have a breaking change.  Your users can deal with changes as they occur, and not be surprised with many changes at once (your new version).&lt;/p&gt;
&lt;h2&gt;“So how the @#$% do I manage change in my API??”&lt;/h2&gt;
&lt;p&gt;With a little imagination, it’s totally possible.  Facebook is one of the largest API providers in the world, and it doesn’t version its API.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Take Preventative measures:&lt;/strong&gt;  Spend more time on design, prototyping, and beta-testing your API before you release it.  If you just throw together the quickest thing that could possibly work, you’re going to be paying the price for that for a long time to come.  An API is a user interface, and as such it needs to actually be carefully considered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consider NOT making non-essential backwards-incompatible changes:&lt;/strong&gt; If there are changes you’d like to make in order to make your API more aesthetically-pleasing, and you can’t do so in an additive fashion, try to resist those changes entirely.  A good public-facing API should value backward compatibility very highly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Make additive changes when possible:&lt;/strong&gt; If you want to add a new property to some resource, just add it. Old clients will just ignore it.  If you want to make breaking changes to some resource, consider just creating a new resource.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use sensible defaults where possible:&lt;/strong&gt;  If you want a client to send a new property, make it optional, and give it a sensible default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Keep a changelog, roadmap and change-schedule for your API:&lt;/strong&gt;  If you want to solve the problem of keeping your users abreast of changes in your API, you need to publish those changes somehow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use hypermedia:&lt;/strong&gt;  Tell the clients what uris to use for the requests that it needs to make and give them uri templates instead of forcing them to make their own uris.  This will make your clients much more resilient to change because it frees you up to change uris however you want.  Clients making their own uris are tomorrow’s version of parsing json with regular expressions.&lt;/p&gt;
&lt;h2&gt;NB!&lt;/h2&gt;
&lt;p&gt;Notice that almost all of these are things that you should do regardless of whether or not you version your API, so they’re not really even extra work.&lt;/p&gt;
&lt;p&gt;Notice also that I never said “Never make changes”.  I’m not trying to make an argument against changes.  I’m just saying that versioning doesn’t help you make changes at all.  At best it just lets you put a bunch of changes in a “bucket” to dump on your API users all at once.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>My Favourite New Ility</title>
		<link href="/posts/2014-06-02-my-favourite-new-ility/"/>
		<updated>2013-06-10T04:21:46Z</updated>
		<id>/posts/2014-06-02-my-favourite-new-ility/</id>
		<content type="html">&lt;p&gt;If you’ve ever seen a laundry list of the types of &lt;a href=&quot;https://en.wikipedia.org/wiki/Non-functional_requirement&quot;&gt;non-functional requirements&lt;/a&gt; like testability, accessibility, reliability, etc, (often called “ilities” because of their common suffix) you probably haven’t seen “rewritability”, but I really want to add it to the pile.&lt;/p&gt;
&lt;p&gt;I’ve often found in software engineering that counterintuitively, if something is difficult or scary there’s a lot to be gained by doing it more often. I think we can probably agree that software rewrites are &lt;a href=&quot;http://www.joelonsoftware.com/articles/fog0000000069.html&quot;&gt;amoung&lt;/a&gt; &lt;a href=&quot;http://www.neilgunton.com/doc/?o=1&amp;amp;doc_id=8583&quot;&gt;those&lt;/a&gt; &lt;a href=&quot;http://chadfowler.com/blog/2006/12/27/the-big-rewrite/&quot;&gt;difficult&lt;/a&gt; &lt;a href=&quot;http://onstartups.com/tabid/3339/bid/2596/Why-You-Should-Almost-Never-Rewrite-Your-Software.aspx&quot;&gt;and&lt;/a&gt; &lt;a href=&quot;http://en.wikipedia.org/wiki/Second-system_effect&quot;&gt;scary&lt;/a&gt; &lt;a href=&quot;http://steveblank.com/2011/01/25/startup-suicide-%E2%80%93-rewriting-the-code/&quot;&gt;tasks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that we’re starting to get better at service-oriented architecture, where networked applications are better divided into disparate services that individually have narrow responsibilities, a natural side effect is that it’s getting easier to write services that are replaceable later.&lt;/p&gt;
&lt;p&gt;So what makes a piece of software rewritable?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clearly defined requirements:&lt;/strong&gt; not just what it needs to do, but also what it won’t do, so that feature-creep creeps into another more appropriate service. This one ends up requiring some discipline when the best place and the easiest place for a given responsibility don’t end up being the same service, but it’s almost always worth it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clearly defined interface:&lt;/strong&gt; If you want to be able to just drop a new replacement in place of a previous one, it’s got to support all the integration points of the previous one. When interfaces are large and complicated this gets a lot harder and a lot riskier. In my opinion, this makes a lot of applications with GUIs very difficult to rewrite from scratch without anyone noticing (Maybe it’s because UX is hard. Maybe that’s because I’m terrible at GUIs.).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Small:&lt;/strong&gt; Even with clearly defined requirements and interface, a rewrite is still going to be expensive and hard to estimate if there’s a lot to rewrite.&lt;/p&gt;
&lt;p&gt;Any software engineers that have found themselves locked into a monolithic ball of mud application can see the obvious upsides of having a viable escape route though.&lt;/p&gt;
&lt;p&gt;And once we’re not scared of rewrites, what new possibilities emerge?  Real experimentation?  Throw-away prototypes that we actually get to throw away?&lt;/p&gt;
&lt;p&gt;How much easier is it to reason about a piece of software when it also meets all the criteria that make it easy to rewrite?&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A Requiem for a Team</title>
		<link href="/posts/2014-06-02-a-requiem-for-a-team/"/>
		<updated>2013-05-08T04:27:20Z</updated>
		<id>/posts/2014-06-02-a-requiem-for-a-team/</id>
		<content type="html">&lt;p&gt;I once asked an interviewee “Ever work on a high-performing team?” and he answered “Yeah…” and then went on to explain how his team profiled and optimized their code-base all the time to give it very high performance.&lt;/p&gt;
&lt;p&gt;That’s not what I meant, but in his defence, I really don’t think many developers have had the opportunity to work on high-performing teams and so they don’t know what they don’t know.&lt;/p&gt;
&lt;p&gt;I’ve been developing software professionally for around 15 years and I’ve only worked on a high-performing team once. It was a couple of years ago, and it was awesome. I haven’t been able to find another since, but now I’m a true-believer in the concept of a &lt;a href=&quot;http://avichal.wordpress.com/2011/12/16/focus-on-building-10x-teams-not-on-hiring-10x-developers/&quot;&gt;10X team&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I suspect that there might be groups out there somewhere who have experience with even higher-performing teams, but I’m certain that I’ve been on enough teams now that high-performing teams are extremely few and far-between. I’m not sure I even know how to create one, but I know one when I see one. I’ve definitely been on teams since that have been close to being high-performing.&lt;/p&gt;
&lt;p&gt;The high-performing team is the ultimate win-win in the software development industry because the developers on the team are thrilled to be going into work on a daily basis and the business is thrilled because they’re producing results much faster and more reliably than other teams. Those are really the two essential criteria, in my opinion:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Is everybody happy to be part of the team?&lt;/li&gt;
&lt;li&gt;Is the team producing results quickly?
The first criteria is absolutely necessary for the second to be sustainable. Any business that neglects developer enjoyment is taking a short-sighted path that will eventually negatively impact performance (due to burnout, employee turnover, etc).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So all of this sounds great, but the real mystery is in how to make it happen. I’m not 100% sure that I know. I don’t think I’ve ever even heard of people talking about how to achieve it.  This is my shot at describing the recipe though.&lt;/p&gt;
&lt;h1&gt;The Management&lt;/h1&gt;
&lt;p&gt;The craziest part of my experience is that the only time I’ve seen a high performance team happen was when the manager of the team had very little software development experience. That seems maddeningly counter-intuitive to me because from a developer’s perspective, one of the most frustrating aspects of software development is having a clueless person telling you what to do and how to do it. It turns out that being clueless in software development can be a huge benefit to being brilliant at software development management though, if the manager is already brilliant with management in general.  &lt;em&gt;This&lt;/em&gt; manager was definitely brilliant on the management side. Here’s why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;He hired for attitude over aptitude. He would hire based on peoples’ potential, their attitudes, and their willingness to work hard instead of whether their precise skillset filled a niche that we needed.&lt;/li&gt;
&lt;li&gt;He would cull developers who weren’t team players. It’s not a job anyone wants to do, but it’s sometimes necessary to let people go when they’re not working out. Not doing this results in the rest of the team being miserable.&lt;/li&gt;
&lt;li&gt;He kept the team small, and didn’t move people in or out of it very often. This gives the team the maximum opportunity to form into a cohesive unit.&lt;/li&gt;
&lt;li&gt;He would set clear goals and priorities. No two things would share the same priority (even though I’m sure he was probably secretly flipping a coin when more than one thing was extremely important). That would give the team a clear direction and an ability to focus on what’s most important.&lt;/li&gt;
&lt;li&gt;He never explained a requirement with &amp;quot;because I said so&amp;quot;. This encouraged a culture of questions and feedback which enhanced learning both on the manager’s part and on the team’s part.&lt;/li&gt;
&lt;li&gt;Even when priorities would change, he’d let us complete our current work where possible, so that we wouldn’t have a mess of incomplete work lying around to try to come back to later. I’ve been on teams since where the team has been repeatedly interrupted to the point of not really delivering anything for months.&lt;/li&gt;
&lt;li&gt;He assigned work to the team, and not to individuals, so the team would have to own it collectively. This kept the manager from being the choke-point for “what should I work on next?” questions.&lt;/li&gt;
&lt;li&gt;He didn’t make decisions or solve problems for the team that the team was able to handle themselves (even when individuals on the team would ask).&lt;/li&gt;
&lt;li&gt;He’d bring us the requirements, but leave the solutioning up to us. The result was that the team was largely autonomous and in control of &lt;em&gt;how&lt;/em&gt; it accomplished its goals, so we immediately had a newfound sense of responsibility for our work and even pride in it.&lt;/li&gt;
&lt;li&gt;He’d get estimates from us, and not the reverse (ie. deadlines). This way he could inform the business about what the estimated cost and schedule for a given feature was so they could make informed decisions about what features to pursue, rather than just delivering what was finished when the clock ran out.&lt;/li&gt;
&lt;li&gt;He’d actively look for scenarios where the team was not “set up for success” and rectify them.  Nothing is worse for team morale than a &lt;a href=&quot;http://c2.com/cgi/wiki?DeathMarchProject&quot;&gt;death march project&lt;/a&gt;, even a mini-one.&lt;/li&gt;
&lt;li&gt;He held the team responsible for the performance of individuals. If someone on the team was struggling on a task (daily stand-up meetings make this pretty obvious) without any help from team, he’d ask the team what they were doing to help.&lt;/li&gt;
&lt;li&gt;All of these things created the perfect climate for a high-performing team, but no one person alone (even a great manager) can create a high-performing team on their own.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;The Team Member&lt;/h1&gt;
&lt;p&gt;The individuals on the team were also really impressive to me and no doubt absolutely essential to making the team what it was. Here’s a loose laundry-list of the qualities I witnessed and tried to adhere to myself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Members of the team were open, honest, and respectful. They would give each other feedback respectfully and truthfully and would never talk behind each others’ backs. On other teams that I’ve worked on where this wasn’t the practice, team-crushing sub-cliques would form.&lt;/li&gt;
&lt;li&gt;Once a decision has been made by the team, every member of the team would support it (even if he/she was originally opposed) until new evidence is presented. This actually worked well because we would always first take the time to actually listen to and consider everyone’s opinions and ideas.&lt;/li&gt;
&lt;li&gt;Members of the team were results-oriented. “Effort” was never involved in our measure of progress. Software actually &lt;em&gt;delivered&lt;/em&gt; according to the team’s standards was our only measure of progress.&lt;/li&gt;
&lt;li&gt;The team would continuously evaluate itself and its practices and try to continuously improve them. We’d have an hour-long meeting every week to talk about how we were doing, and how we could improve (and how we were doing implementing the previous week’s improvements).&lt;/li&gt;
&lt;li&gt;The team would practice collective code ownership, and collective responsibility over all the team’s responsibilities. This is actually a pretty huge deal; if people working on a top priority needed help, they’d ask for it immediately and anyone that could help would. If someone was sick, someone else would take on their current responsibilities automatically. If a build was broken, everyone would drop everything until there was a clear plan to fix it. The morning stand-up meeting would happen at exactly 9 am regardless of whether the manager was there.&lt;/li&gt;
&lt;li&gt;The team would foster cross-functionality as a means of achieving collective code ownership and collective responsibility. What that meant was that members would actively try to teach each other about any particular unique skill-sets they had so that they would be redundant and team members would be better able to take on any task in the work queue.&lt;/li&gt;
&lt;li&gt;The team would be as collaborative as possible. We all sat in a bullpen-like environment where we’d torn down the dividers that were originally erected between us. We’d often pair-program, not only for skill-sharing and mentoring, but also for normal coding tasks, because the boring tasks are less mind-numbing that way and the complicated tasks get better solutions that way.&lt;/li&gt;
&lt;li&gt;In the 5 or 6 teams in our organization at the time, I think our team was by far the fastest, and most capable of handling the more technically diverse and challenging work. No one on the team was a rock-star programmer, but somehow despite that, the team as a whole was really outstanding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Eventually when this manager moved on, I took the management role and ultimately failed to maintain that environment (partially for a number of reasons that were out of my control, and partially because at the time I didn’t realize the necessary ingredients).  I’ve only really learned them since then by watching dysfunctional teams.&lt;/p&gt;
&lt;p&gt;It’s a cliche, but in the right environment, the collective can indeed be greater than the sum of its parts.&lt;/p&gt;
&lt;h1&gt;EDIT (June 2nd, 2014):&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;I just moved my blog over from wordpress, but I don&#39;t want to lose the comments that I had there, because they&#39;re great and they&#39;re from the team that I was writing about. I&#39;m just going to copy/paste them in here for posterity.&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Todd said on May 8, 2013 at 8:12 am: Edit&lt;/p&gt;
&lt;p&gt;You nailed it! I’m glad my simple ‘I miss working with you…’ email triggered you to write this thoughtful post. I admire your choice to spend time sharing your thoughts with the world.&lt;/p&gt;
&lt;p&gt;I was trying to come up with some clever addition to your post but I keep typing and erasing. The one constant thought I whole heatedly believe had the most impact on our teams success is ‘Jaret’. I sure hope he doesn’t read this post, they’ll be no living with him! :)&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Tom said on May 10, 2013 at 7:50 pm: Edit&lt;/p&gt;
&lt;p&gt;Gregg and Todd, I also miss working with you guys. I do, however, have some pertinent hymns to add to the post. Though, I must first agree that a highly productive team is not formed from a cookie-cutter, but many ingredients do add to the potential success; kudos to Gregg for identifying most.&lt;/p&gt;
&lt;p&gt;Management: I’d add that the “ideal” manager is an advocate for the team’s decisions, approach and methodology even if he does not fully understand them. Specifically, if the team can convince, through reason, that they were not smoking crack and that their solution would be suitable and economical (perhaps not in the short-run, but in the long-run), then he would go to bat for them. He’d do this no matter how much counter-pressure was exerted by upper management; clearly JW did this.&lt;/p&gt;
&lt;p&gt;Secondly, a culture of experimentation, collaboration, and trust must trickle down from the upper echelons of management down to the lowest levels. Think of this as an approach to lowering entropy. Without this, all middle managers have their hands tied.&lt;/p&gt;
&lt;p&gt;Team: Diversity in cultural and technological background is highly advantageous. The simple reason is that varied backgrounds allow differing opinions, analysis and approaches to a solution. I’d be bold enough to state that a homogeneous team is useless at being highly-productive because there is not enough diversity in the “knowledge gene pool” to forge great solutions. On the flip side, too much diversity may be a hindrance as agreement may be hard to come by for the final solution, but somebody should play devils advocate during the initial discussions; this only comes from varied experiences.&lt;/p&gt;
&lt;p&gt;As well, team members should feel as if they are creating something of value. Perhaps this is more of a company or management issue, but I believe if people, regardless of their position in a company, feel like they are contributing to a greater good will naturally help their teammates and this will improve the productivity of the team as well as the firm’s bottom line.&lt;/p&gt;
&lt;p&gt;I’m sure there are more comments to add, but I need to go have another glass of wine and reminisce :)&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Gregg Caines said on May 11, 2013 at 8:12 am: Edit&lt;/p&gt;
&lt;p&gt;Ha Good to hear from you Sykora :) I agree with your points. I think JW was set up for success when the “upper echelons” were supportive, and we were all destined for failure once those winds changed and upper management suddenly cared very deeply about the team’s every move on a day-to-day basis. Something makes me think that even if they had a reasonable ratio of right/wrong in their technical decisions, we’d still be irritated to be completely out of control of our own destinies, especially given our history of self-organization. Once the team gets a taste of autonomy, it’s hard for them to go back to command-and-control management. I suspect you of all people would agree.  ;)&lt;/p&gt;
&lt;p&gt;I agree with you on diversity too. We had a pretty diverse team but I think it worked well because we were respectful and trusted each other. I’ve seen teams since that were much less diverse and would argue disrespectfully about tiny things compared to some of the things that we would (calmly) discuss and (quickly) resolve. I’ll tell you one thing that I know for certain now: egos don’t make good team-mates.  ;)&lt;/p&gt;
&lt;p&gt;I agree with the “creating something of value” point as well, but I’m less about the value to the customer and more about the engineering craftsmanship. It’s the only way I’ve found myself able to reconcile product decisions I can’t agree with. Maybe one day I’ll have my greasy hands in the product side as well and get a chance to care all the way through though.  ;)&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;tibi said on May 11, 2013 at 9:11 am: Edit&lt;/p&gt;
&lt;p&gt;Well that was a nice post. And now I miss the team even more. I think you hit it right on the head (I can’t correctly remember the nail euphemism :-) )…&lt;/p&gt;
&lt;p&gt;I’ve been looking for the same dynamics in a team ever since, and I think I’m getting close, but there is always something missing. Perhaps it’s the Tim Horton’s cup arch…&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Jeff said on May 11, 2013 at 3:53 pm: Edit&lt;/p&gt;
&lt;p&gt;Some great thoughts here Gregg – on the money pretty much across the board. A team is definitely only as good as it’s leadership allows. I’ve been in situations where the core team was incredible and worked together well but ultimately failed for the various reasons you any Tom both mention.&lt;/p&gt;
&lt;p&gt;p.s. Hiya boys – hope everyone’s doing well.
Did someone say Tim’s?&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Gregg Caines said on May 13, 2013 at 9:01 am: Edit&lt;/p&gt;
&lt;p&gt;Tibz and Jonesy! Good to see you two are still alive.  :)&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Chris said on May 14, 2013 at 7:06 am: Edit&lt;/p&gt;
&lt;p&gt;It was something special to watch and interact with.&lt;/p&gt;
&lt;p&gt;You do not really know what you’ve got until it’s gone, eh? There was a sense of what was happening but probably also a sense that it would fairly easily be recreated.&lt;/p&gt;
&lt;p&gt;My current co-workers are tired of hearing how “we would have did it at my last place.” ;) Somehow it is not fair to hold other teams to that yardstick.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;JW said on June 10, 2013 at 8:56 am: Edit&lt;/p&gt;
&lt;p&gt;So many great things have been said above – and I have to agree with all of it. From my perspective, it really was a dream team. The trust, collaboration and commitment levels in the entire office were exceptional.&lt;/p&gt;
&lt;p&gt;I have read numerous books on leadership and when I reflect on that team, we had all the characteristics of a high performing team.&lt;/p&gt;
&lt;p&gt;For me, I loved the level of achievement, craftsmanship, and fun that we had. It wasn’t work – even a few of those late nights weren’t too bad because we were doing it together.&lt;/p&gt;
&lt;p&gt;Is there a secret sauce to recreate that environment? Not that I have found. However, I have been lucky enough to be part of 4 different high performing teams over my career, and I believe there are things we can all do to help create an environment that could support a high performing team. From there – it is up to the team to choose to be high performing.&lt;/p&gt;
&lt;p&gt;I identify well with the Patrick Lencioni’s book “The 5 Dysfunctions of Team”. Although I will not rewrite each of the characteristics from the book, I feel that we need to provide special mention to trust. It is the foundation of a high performing team. Nothing can be built without it. That means we need to know our team mates and their goals. How can we help each other? The more we help and recognize each other, the quicker the team will want to collaborate and achieve greater things.&lt;/p&gt;
&lt;p&gt;We are all lucky to have been part of something great. I learned a ton from everyone there and I share those insights in my classes everyday.&lt;/p&gt;
&lt;p&gt;Gregg – many thanks for starting this thread.&lt;/p&gt;
&lt;hr /&gt;
</content>
	</entry>
	
	<entry>
		<title>So I wrote a JSON API Framework and the Framework was the Least Interesting Part</title>
		<link href="/posts/2014-06-02-so-i-wrote-a-json-api-framework-and-the-framework-was-the-least-interesting-part/"/>
		<updated>2013-04-30T04:45:09Z</updated>
		<id>/posts/2014-06-02-so-i-wrote-a-json-api-framework-and-the-framework-was-the-least-interesting-part/</id>
		<content type="html">&lt;h1&gt;First a little background&lt;/h1&gt;
&lt;p&gt;I’ve always been a big fan of&lt;a href=&quot;http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm&quot;&gt; REST the way Roy intended it&lt;/a&gt; for two major reasons:&lt;/p&gt;
&lt;p&gt;It uses HTTP the way HTTP was intended, playing on its strengths and not wasting any time re-inventing what HTTP already has.
The state of HTTP APIs these days is really ridiculously bad, given what we should have learned from the unfathomable success of the WWW.
I was also envious as hell at the great framework Erlang developers had in &lt;a href=&quot;https://github.com/basho/webmachine&quot;&gt;Web Machine&lt;/a&gt; .  If you write HTTP APIs for a living and you haven’t seen HTTP mapped to a state machine, you really owe it to yourself to &lt;a href=&quot;https://github.com/basho/webmachine/wiki/Diagram&quot;&gt;check it out&lt;/a&gt;.  It’s brilliant.&lt;/p&gt;
&lt;p&gt;The thing I really wanted to do though was make web APIs not so terrible.  There are a few reasons that I think they’re terrible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have to read reams of documentation to do the simplest things, like finding the URL for something.&lt;/li&gt;
&lt;li&gt;You have to hard-code urls all over your client app.&lt;/li&gt;
&lt;li&gt;When you do something wrong, there’s no consistency in error output.&lt;/li&gt;
&lt;li&gt;Knowing HTTP doesn’t make it any easier to predict how something will work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you rely on someone else’s API in your day-to-day work, you probably know what I mean.  I’m not going to name any names (but here’s a clue: one of the worst offenders starts with an F and rhymes with Facebook).&lt;/p&gt;
&lt;p&gt;So the APIs I wanted to make and to use would be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;semantically consistent with plain old HTTP&lt;/li&gt;
&lt;li&gt;discoverable, like other pages and controls on normal HTML web sites are discoverable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Luckily HTTP is also the vanguard of API discoverability, most often in the form of hypertext (So that’s what that H stands for!) .   I’m a bit blown away that this wasn’t obvious to me earlier, but luckily I stumbled into &lt;a href=&quot;http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven&quot;&gt;Roy Fielding talking about hypermedia&lt;/a&gt; and I realized that that’s precisely the correct way to solve the discoverability problem.  He was saying real REST APIs should minimize out-of-band knowledge by leaning on what HTTP’s already got: links! [^1] .&lt;/p&gt;
&lt;p&gt;Then I saw &lt;a href=&quot;http://vimeo.com/20781278&quot;&gt;Jon Moore make it real with an XHTML API&lt;/a&gt; .  XHTML forms are a method of discoverability as well?!? My mind was blown.  Think about that: XHTML documents tell you what kind of write-possibilities the API has.  You don’t need to read docs to find out!&lt;/p&gt;
&lt;p&gt;And then I saw &lt;a href=&quot;http://amundsen.com/media-types/collection/format/&quot;&gt;Mike Amundsen bring it all back to json&lt;/a&gt; and I knew it might be something I could actually use in the real world and people trying to Get Stuff Done wouldn’t want to hunt me down and murder me in my bed (especially since I’m also a card-carrying member of the People Who Want To Get Stuff Done Liberation Front).   I think most of us are of the belief that XHTML isn’t going to unseat json as the preferred media-type for APIs anytime soon.&lt;/p&gt;
&lt;p&gt;Armed with all this inspiration, I wrote a web-framework.  I ended up picking node.js mostly because the &lt;a href=&quot;http://nodejs.org/api/http.html&quot;&gt;HTTP line-protocol&lt;/a&gt; stuff was already covered there without any extra cruft to get in my way, so I was free to try to aim for “Web Machine with json with links”[^2], which I call &lt;a href=&quot;http://percolatorjs.com/&quot;&gt;Percolator&lt;/a&gt;.  The framework isn’t the interesting part though; it’s the stuff I learned along the way, which can be done in any framework/language/platform, even if it’s not baked into the framework.&lt;/p&gt;
&lt;h1&gt;The First Interesting Part:  Hypermedia apis are indeed awesome&lt;/h1&gt;
&lt;p&gt;I started by just putting links in my json to other endpoints that make sense.  That made my json APIs so much easier to use, even when the user is me.  I had one endpoint for my entire API and every other endpoint was discoverable by following links.  I used &lt;a href=&quot;https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc?hl=en&quot;&gt;JSONView for Chrome&lt;/a&gt; and &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/jsonview/&quot;&gt;for Firefox&lt;/a&gt; and I could click around my entire API testing the GET method on every endpoint just by clicking.  Here’s how it looks:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/json-with-links-530w.webp 530w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;json with links&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/json-with-links-530w.jpeg&quot; width=&quot;530&quot; height=&quot;492&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Those purple links are visited links that you can actually click on and get a new API response.  I showed some co-workers that were using my API and eventually they stopped asking “Hey what’s the URL for getting X again???”  They could always easily re-find it themselves.&lt;/p&gt;
&lt;p&gt;Adding links also pays off when humans aren’t involved.  In many cases it means that the client doesn’t need to construct its own links.  For example: when one of my APIs was being used for replication by a client app the client developer asked how we’d handle pagination, because he wanted to page through all my results to replicate my API’s data elsewhere (sort of like how &lt;a href=&quot;http://wiki.apache.org/couchdb/Replication&quot;&gt;couchdb replication works, which is simple yet amazing&lt;/a&gt; ) .  I had a pagination scheme working, but it didn’t make use of the database indices as well as I wanted so I told him instead to just follow the ‘next’ link and not to worry about the parameters for constructing the URL at all and that the absence of a ‘&lt;a href=&quot;http://www.w3.org/TR/html4/types.html#type-links&quot;&gt;next&lt;/a&gt;’ link would indicate the end of the results.  What this meant for me is that when I changed the pagination scheme to something more friendly to my database, I didn’t even have to tell him.  What it meant for him is that he never had to change anything on his side to support the new form of pagination, and he didn’t have to construct any urls.&lt;/p&gt;
&lt;p&gt;It blows my mind that pushing this simple technology further could end up with clients ONLY needing to store the root URL of the API, and not a who’s-who of possible disparate endpoints that practically mirrors the routing table on the server.    People are actually starting to &lt;a href=&quot;http://vimeo.com/20781278&quot;&gt;push the envelope this way&lt;/a&gt;.  Wouldn’t it be great if at some point we could stop writing client software that’s hopelessly &lt;a href=&quot;https://github.com/ttezel/twit&quot;&gt;service&lt;/a&gt;-&lt;a href=&quot;https://github.com/arsduo/koala&quot;&gt;dependent&lt;/a&gt; ?  Wouldn’t it be great if one day client-side url construction was considered as silly as using regexes to get data from json?&lt;/p&gt;
&lt;p&gt;I should also add that even if you’re writing both the client and the server, which happens a lot with single-page apps and mobile apps, you might be tempted to think this is a waste of time, but in my experience it makes testing and debugging much easier and helps me remember what my API does after a month without using it despite my terrible memory.  That minor extra effort of adding links pays for itself over and over again.&lt;/p&gt;
&lt;h1&gt;Interesting Part #2: JsonSchema is surprisingly awesome&lt;/h1&gt;
&lt;p&gt;Of course once I could surf around my API, it didn’t take long for me to bemoan the fact that I could only peruse GETs this way.  I had seen &lt;a href=&quot;http://vimeo.com/20781278&quot;&gt;Jon Moore’s XHTML API demo&lt;/a&gt;  (This is my third link to it here, so you know it’s worth a watch!) , and I was jealous of how XHTML forms could describe the POSTs as well.  Originally I decided that json needed forms as well, but the big brains in the &lt;a href=&quot;https://groups.google.com/forum/?fromgroups#!forum/hypermedia-web&quot;&gt;Hypermedia-Web Google Group&lt;/a&gt;  convinced me that I could just expand my link concept to know about other HTTP methods.   And I had already stumbled upon &lt;a href=&quot;http://json-schema.org/&quot;&gt;JsonSchema&lt;/a&gt; as a way to specify what was expected in a PUT or POST payload, just like XHTML forms can do (but still using json of course).&lt;/p&gt;
&lt;p&gt;JsonSchema is a particularly elegant solution to the problem, because I can write all my validations in JsonSchema, publish the validations as json to the api (JsonSchema is just json afterall), and then on the client side re-use them for validations before I even bother with an http request to the api.  This way I can use the same validations on the client and server, AND communicate them naturally as part of the json payload.  The end result was that my json APIs could now fully communicate everything that was possible via the json API itself.  Here’s how it looks:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/json-with-write-link-521w.webp 521w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;json with POST link&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/json-with-write-link-521w.jpeg&quot; width=&quot;521&quot; height=&quot;719&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;I added baked-in JsonSchema support to Percolator right away of course, but you can do it easily in &lt;a href=&quot;http://json-schema.org/implementations.html&quot;&gt;any of the most popular languages  ( see the validators tab)&lt;/a&gt;.  Currently I haven’t implemented any clients that use it for validations yet, but I do use it for my server-side validations.  More importantly still, it communicates to humans everything that’s necessary for a successful PUT or POST. [^3]&lt;/p&gt;
&lt;p&gt;Ultimately the addition of JsonSchema lead me to add a static frontend to Percolator that, after abstracting it away, I published separately as the &lt;a href=&quot;https://github.com/cainus/hyperjson-browser&quot;&gt;Hyper+JSON Browser&lt;/a&gt; .  You don’t need it, but you can use it in conjunction with Percolator apps to ‘browse’ them even more easily than JSONView does (and without installing a plugin).  Any app (using any language/framework) that spits out the same sort of output as Percolator could use this the Hyper+Json Browser just the same, because it’s a static single-page app that works over any API that works similarly.  Here’s how it looks in use:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/browser1-600w.webp 600w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;simple Browser view&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/browser1-600w.jpeg&quot; width=&quot;600&quot; height=&quot;693&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;When you click on that ‘create’ link to POST, it does this:&lt;/p&gt;
&lt;p&gt;Browser after clicking the POST link
&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/browser2-600w.webp 600w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;Browser after clicking the POST link&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/browser2-600w.jpeg&quot; width=&quot;600&quot; height=&quot;723&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;That red json logo indicates that you haven’t entered valid json (yet).  Pressing OK will actually POST the json that you enter and show you the result.&lt;/p&gt;
&lt;p&gt;Here’s a view of another resource (an individual item in the list from the previous collection resource, which can be found by clicking that item’s &#39;&lt;a href=&quot;http://www.w3.org/TR/html4/types.html#type-links&quot;&gt;self&lt;/a&gt;&#39; link.  It shows delete and update links for this particular resource.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;/images/browser3-600w.webp 600w&quot; sizes=&quot;(min-width: 1024px) 100vw, 50vw&quot; /&gt;&lt;img alt=&quot;Browser after clicking one of the items in the list&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;/images/browser3-600w.jpeg&quot; width=&quot;600&quot; height=&quot;669&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;People have likened this to the &lt;a href=&quot;http://www.djangobook.com/en/2.0/chapter06.html&quot;&gt;Django admin interface&lt;/a&gt;, which is a huge compliment, not only because the Django admin interface is pretty legendary, but also because this frontend doesn’t know a single thing about the API other than the requirement that the API uses the aforementioned link format.  This is an area where I’m really excited: In what other ways can other programs use these APIs without foreknowledge?  (I’m not really talking about intelligent agents  – they’d need to understand a little more than the API provides — but dumber things that still use human interaction eventually, like automatic HTML form generation, are mostly possible.)&lt;/p&gt;
&lt;h1&gt;(Somewhat less) Interesting Part #3:  Object-oriented routing leads to less stupid stuff&lt;/h1&gt;
&lt;p&gt;I hate to sound old-school, but sometimes the object-oriented paradigm maps to a problem better than a functional one.  In this case, I’m talking about routing.  I don’t know why the HTTP methods GET, POST, PUT, etc are named “methods” but it sure does make perfect sense, because each one is tied to a particular “resource”: that “thing” you’re interacting with by using the HTTP methods for a given URL.  It should be obvious then that HTTP resources should be the thing we route to, and not disparate methods.  REST APIs are supposed to be the antithesis of RPC, but when routing involves the method as well, developers tend to make less RESTful APIs and framework developers tend to mess up some of the finer points of HTTP.  Here’s a quick test:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Grab your favorite web framework and create a resource with a single GET handler.&lt;/li&gt;
&lt;li&gt;POST to it.  Did you get the proper 405 response?&lt;/li&gt;
&lt;li&gt;send an OPTIONS request.  Did it tell you that only GET was available?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Probably not.  Web-machine gets this right because it routes to the resource, instead of disparate functions that when imagined together form a resource.  I wrote Percolator to work like web machine in this way, because I wanted my APIs to look like something other than a haphazard collection of RPC calls without requiring a lot of self-discipline.  The result is that Percolator responds with 405s when a client tries a method that that resource doesn’t support, and also responds to OPTIONS requests with a list of all the allowed methods.  The result again is better discoverability without reams of documentation, and better feedback for client developers when they’ve done something the API doesn’t support.&lt;/p&gt;
&lt;p&gt;There are advantages to OO routes for application developers to though, organization-wise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All routes for a particular resource are connected to that resource, so there’s no chance of sloppy intermingling in the source code.&lt;/li&gt;
&lt;li&gt;A bunch of code that you have to write in each method can be written just once for the resource.&lt;/li&gt;
&lt;li&gt;You start to see patterns in what resources do, which can lead to certain classes of resources that can be re-used over and over, sometimes wholesale and sometimes with particular strategies that change them slightly.  This is a bit of a big deal, in my opinion because it’s extremely rare that I see this kind of re-use in web applications in the real world.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyway:  Percolator is indeed ready for production use (at least for the use-cases for which I’ve used it in production!).   It’s extremely fast and extensible, and I hate it a lot less than anything else I’ve used for json REST APIs.&lt;/p&gt;
&lt;p&gt;Hopefully it helps someone make a nice API, or it gives some other framework developer some new ideas.  The APIs we have today cannot possibly be the best that we can do.&lt;/p&gt;
&lt;p&gt;[^1]: plus a pile of other conventions&lt;/p&gt;
&lt;p&gt;[^2]: Ultimately I diverged quite a bit from Web Machine, but it was always a huge inspiration.&lt;/p&gt;
&lt;p&gt;[^3]: Alright not everything, but a heck of a lot.  Linked documentation on my RELs would be another huge boost to discoverability.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>3 Terrible Anti-patterns for Error-Handling in &#39;REST&#39; APIs:</title>
		<link href="/posts/2014-06-02-3-terrible-anti-patterns-for-error-handling-in-rest-apis/"/>
		<updated>2013-04-22T05:22:07Z</updated>
		<id>/posts/2014-06-02-3-terrible-anti-patterns-for-error-handling-in-rest-apis/</id>
		<content type="html">&lt;p&gt;I’ve seen these anti-patterns in a lot of web APIs, so I thought I’d detail why they’re bad and what to do instead.&lt;/p&gt;
&lt;h1&gt;Using a 200 status code for every response:&lt;/h1&gt;
&lt;p&gt;This anti-pattern is common for SOAP-like RPC APIs.  Using a 200 status code for all your responses is silly because you end up having to reinvent an error-indication in your response body instead, and nobody in the world knows your new standard (or wants to have to learn it).&lt;/p&gt;
&lt;p&gt;It’s also extremely confusing in the cases that an error has occurred because a status code of 200 means everything is A-OK.  &lt;a href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html&quot;&gt;There are already a bunch of error codes in the 400 and 500 ranges&lt;/a&gt; that are fully capable of indicating all sorts of common problems. It’s still great to put an error message in the response body, but there should be a 400 or 500-level status code so people know that an error even occurred and don’t go ahead and try to interpret the response body as normal or otherwise assume a success.&lt;/p&gt;
&lt;h1&gt;Using a 500 status code for all errors:&lt;/h1&gt;
&lt;p&gt;This anti-pattern is common because 500 is what most frameworks will do when a web application throws an uncaught exception, and so it becomes convenient to just throw exceptions and not worry about the repercussions. This is mildly better than using a 200 status code for literally everything, because at least it shows an error occurred but it still causes a lot of confusion for client developers.&lt;/p&gt;
&lt;p&gt;When you 500 for an error (even if your web framework did it for you), you’re signalling that the problem with the request was the fault of your application (the server) and it’s possible that retrying the request will be successful. Because 500 errors indicate an internal &lt;strong&gt;server error&lt;/strong&gt;, they shouldn’t actually ever happen though[^1] — In general, you’ve got a bug in your application if they do, and the web server will tell everyone about it. The right thing to do, if there’s something wrong with the request is to respond with the appropriate 400-level status code.&lt;/p&gt;
&lt;p&gt;Using a 500 error when a 400-level status code is more appropriate is obviously really confusing to the person making the requests because it doesn’t even let them know that their request needs to be fixed. Even if that person is also you, it forces you to start digging into your back-end for what could possibly just be a bad client request. If you don’t know which 400-level code to use, at the very least use 400 (Bad Request) itself. This will at least give your client developer an indication if the blame is on the server or the client and cut your debugging in half. A few words about the error in the response body can go a long way as well.&lt;/p&gt;
&lt;h1&gt;Logging 400-level codes at ‘error’ level:&lt;/h1&gt;
&lt;p&gt;Logging is pretty important to measuring the quality of implementation of an API, and learning about specific defects. The ‘error’ level in your logs should be a way to indicate “things that should not have happened that are within this application’s control”, so that you actually have a hope of attempting a 0-error policy. 400 level codes are errors of course, but they’re client errors, and not your server application’s error, so they should not be logged as errors along with your actual 500-level errors (Of course you might still log them as “info” level to keep track of what kinds of crazy things your clients are doing).&lt;/p&gt;
&lt;h1&gt;Why do all these details matter?&lt;/h1&gt;
&lt;p&gt;When you have an interface between two applications (the client and the server in this case) like HTTP, it REALLY simplifies things a lot if they communicate whether messages are acceptable or not (and why). Even if you control both ends of the interaction, you can save yourself a lot of server-side debugging by having the server indicate what exactly went wrong with a given request, instead of repeatedly reading stack traces every time some JSON you POSTed is missing a property. Compared to how little extra work there is involved in communicating the problem correctly, it’s pretty short-sighted to just let all exceptions bubble-up, or catch all exceptions silently (and 200).&lt;/p&gt;
&lt;p&gt;Keep in mind too that if you’re now convinced that communicating errors is important, then HTTP already has a system for just that: HTTP status codes (plus whatever specifics you want to additionally communicate in the response body). Status codes are part of the greater HTTP standard that a lot of developers, libraries, proxies, and caches already understand. Re-inventing your own error mechanism is generally a waste of everyone’s time (with you at the top of the list).&lt;/p&gt;
&lt;p&gt;Getting this right is a real time-saver over the long-haul even if you’re the only consumer of the API writing both client-side and server-side.  The time-savings only multiplies as you add more clients.&lt;/p&gt;
&lt;p&gt;[^1]: Sometimes 500 is appropriate of course: If your application requires a database and its lost connectivity to it, then a 500 makes total sense. It signals that there’s a problem in your application and the client can possibly try the request again later.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Node.js Community is Quietly Changing the Face of Open Source</title>
		<link href="/posts/2014-06-03-the-node-dot-js-community-is-quietly-changing-the-face-of-open-source/"/>
		<updated>2013-04-13T13:46:06Z</updated>
		<id>/posts/2014-06-03-the-node-dot-js-community-is-quietly-changing-the-face-of-open-source/</id>
		<content type="html">&lt;p&gt;If you consider the number of packages on &lt;a href=&quot;https://pypi.python.org/pypi&quot;&gt;pypi&lt;/a&gt;, &lt;a href=&quot;https://npmjs.org/&quot;&gt;npm&lt;/a&gt;, and &lt;a href=&quot;https://rubygems.org/&quot;&gt;rubygems&lt;/a&gt;, and the release dates of python (1991), ruby (1995) and node.js (2009), it looks a lot like those communities are getting new packages at the following rates, per year:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;python:&lt;/strong&gt;  29,720 packages / 22 years = &lt;strong&gt;1351 packages per year&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ruby:&lt;/strong&gt;      54,385 packages / 18 years = &lt;strong&gt;3022 packages per year&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;node.js&lt;/strong&gt;  26,966 packages / 4 years = &lt;strong&gt;6742 packages per year&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It’s important to note that I’m only showing the other languages as a measuring stick.  There are probably a lot of reasons for the disparity here (including my imprecise math), and I’m not trying to say anything like “node.js &amp;gt; ruby &amp;gt; python”  but obviously new node.js packages are being published to npm at a staggering rate.   I just checked npm (on a Sunday night) and 20 new versions of packages have been published to npm in the last hour alone.&lt;/p&gt;
&lt;p&gt;This is a pretty amazing feat for node.js.  How is this possible?&lt;/p&gt;
&lt;h1&gt;Batteries NOT included&lt;/h1&gt;
&lt;p&gt;If you’ve needed an HTTP client in Python, you’ve probably asked yourself “should I use urllib, urllib2, or httplib for this?” like &lt;a href=&quot;http://stackoverflow.com/questions/3305250/python-urllib-vs-httplib&quot;&gt;so many people&lt;/a&gt; before you.  Well the answer is probably that you should use &lt;a href=&quot;http://docs.python-requests.org/en/latest/&quot;&gt;requests&lt;/a&gt;.  It’s just a really simple, intuitive HTTP client library that wraps up a lot of weirdness and bugs from the standard libraries, but it’s not a standard library like the others.&lt;/p&gt;
&lt;p&gt;The “Batteries included” philosophy of Python was definitely the right approach during the mid 90’s and one of the reasons that I loved Python so much; this was a time before modern package management, and before it was easy to find and install community-created libraries.  Nowadays though I think it’s counter-productive.  Developers in the community rarely want to bother trying to compete with the standard library, so people are less likely to try to write libraries that improve upon it.&lt;/p&gt;
&lt;p&gt;Developers are less likely to use non-standard libraries in their projects too.  I’ve heard many instance of people suffering through using an inferior standard library just to have “no dependencies”.  But in this day and age of cheap massive storage and modern package management, there are very few reasons for a policy of “no dependencies”.&lt;/p&gt;
&lt;p&gt;Conversely, the node.js core developers seem to actually want to minimize the standard library as much as possible.  They have repeatedly &lt;em&gt;removed&lt;/em&gt; features from the standard library to free them up to be implemented by the community instead.  This allows for the most variety and lets the best implementation win (but only until someone makes a better one, of course!).&lt;/p&gt;
&lt;p&gt;Imagine how liberating this is for standard library maintainers too.  The node.js standard library is &lt;a href=&quot;https://nodejs.org/api/&quot;&gt;comparatively tiny&lt;/a&gt;, freeing the core developers to just deal with the core necessities.&lt;/p&gt;
&lt;h1&gt;The Tiny Module Aesthetic&lt;/h1&gt;
&lt;p&gt;Just like the 140 character limit on twitter makes people “blog” more, the node.js community has a &lt;a href=&quot;http://substack.net/how_I_write_modules&quot;&gt;culture of publishing tiny modules&lt;/a&gt; that makes people more comfortable with publishing smaller packages, and so it happens vastly more often.&lt;/p&gt;
&lt;p&gt;While I don’t really consider myself “a node.js developer”, I’ve found myself publishing &lt;a href=&quot;https://npmjs.org/~cainus&quot;&gt;over a dozen packages&lt;/a&gt; in the last year myself, just because I’m working on a node.js project at work, and I publish any reusable package from that work that I create.  My project ends up factored better, and I end up with a bunch of building blocks I can re-use elsewhere (and then I do!).  Sometimes random people from the interwebs &lt;a href=&quot;https://github.com/cainus/Prozess/pull/26&quot;&gt;even fix my bugs before I notice them&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;This approach is not unusual at all either, at least in the node.js community.  The community is lead by developers that have each published literally hundreds of packages.  I don’t even know how &lt;a href=&quot;https://npmjs.org/~substack&quot;&gt;this is possible&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Of course there’s absolutely nothing to stop other languages from following suit, so it seems to me like community culture is the deciding factor.&lt;/p&gt;
&lt;p&gt;Massive monolithic frameworks like Ruby on Rails tend to not take hold in the node.js community mindshare, I think due in part to this “tiny module aesthetic”, and it’s all the better for it.  It seems to me that monolithic frameworks like Rails don’t have a clear notion of what does &lt;strong&gt;not&lt;/strong&gt; belong in Rails, and so they tend to expand indefinitely to include everything an application could need.  This leads to people trying to assert that Rails is the best solution for all problems, and having a cooling effect on innovation within the web application space in the Ruby community.&lt;/p&gt;
&lt;p&gt;The tiny module aesthetic also leads to an ecosystem of extreme re-use.  When a package doesn’t do more than is absolutely necessary, it’s very easy to understand and to integrate into other applications.  Conversely, while massive monolithic frameworks tend to appear in a lot of end-user applications, they rarely never end up being dependencies in other packages themselves.  It seems unfortunate to me that so much great software should be so difficult to re-use.&lt;/p&gt;
&lt;h1&gt;git and github.com monoculture&lt;/h1&gt;
&lt;p&gt;To be honest, few things are more boring to me in software development than version control, and I find the complexity of git to be a bit silly and mostly unnecessary for me, but I’ve never heard of a node.js developer that doesn’t use it, and there’s huge value in that kind of monoculture.  It means that they all speak with a common language and there’s no impedance when you want to contribute to someone else’s projects.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/&quot;&gt;Github.com&lt;/a&gt; has a similar effect in lowering the barriers for cross-pollination between developers.  I’ve only very rarely seen a node.js project that wasn’t on github.  This means I immediately know exactly where to find source code if I want to contribute.&lt;/p&gt;
&lt;p&gt;The pluses and minuses of a github monoculture go far beyond this, but there’s probably enough fodder there for an entirely different post.&lt;/p&gt;
&lt;h1&gt;Permissive Licensing&lt;/h1&gt;
&lt;p&gt;Node.js packages tend to use extremely permissive licensing like MIT and BSD licensing.  In fact, the default license for a package created by &lt;code&gt;npm init&lt;/code&gt; is BSD.  I think this is another sign of the times.&lt;/p&gt;
&lt;p&gt;Very few people care anymore if someone else forks and doesn’t contribute back.  There’s very little to gain in not contributing back anyway because of the cost of maintaining your own fork.&lt;/p&gt;
&lt;p&gt;This is important because no one wants to have to deal with dependencies that make them think about legal repercussions, or give them extra responsibilities.  Licenses like the GPL end up having a cooling effect on software-reuse for this exact reason.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;EDIT Jun 3rd, 2014:  Comments below are basically copy/pasted from my old blog format for posterity.&lt;/p&gt;
&lt;hr /&gt;
&lt;div id=&quot;comments&quot;&gt;
&lt;h2 id=&quot;comments-title&quot;&gt;
30 thoughts on &amp;ldquo;&lt;span&gt;The node.js Community is Quietly Changing the Face of Open Source&lt;/span&gt;&amp;rdquo;			&lt;/h2&gt;
&lt;ol class=&quot;commentlist unstyled&quot;&gt;
&lt;li id=&quot;li-comment-1498&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1498&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/120061cb6e8934e09ec4cdf57d082e0f?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;https://maxogden.com&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;max ogden&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-14T10:25:52+00:00&quot;&gt;April 14, 2013 at 10:25 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Nice writeup! I do think that the term &amp;#8216;node community&amp;#8217; is a little bit too general since some of the most popular node modules are in fact bigger than they should be. &lt;/p&gt;
&lt;p&gt;For example, the 4 most popular modules from &lt;a href=&quot;https://npmjs.org/&quot; rel=&quot;nofollow&quot;&gt;https://npmjs.org/&lt;/a&gt;: underscore, async, request and express could all be split up into smaller pieces:&lt;/p&gt;
&lt;p&gt;Underscore isn&amp;#8217;t terribly large but it has things tucked in it like a templating function that don&amp;#8217;t belong. &lt;/p&gt;
&lt;p&gt;Async is thematically consistent, offering many variations on a theme, but from the empirical usage patterns that I&amp;#8217;ve seen most people use a small percentage of the offered functionality. &lt;/p&gt;
&lt;p&gt;Request actually went through the modularization process over the last month or two and went from having 1 or 2 dependencies to having 11. &lt;/p&gt;
&lt;p&gt;Express is perhaps the greediest module on NPM (IMHO) in that it invented its own naive APIs early on which means that now you can only use modules designed for express with express since the extensibility is stuck in a relatively pre-cambrian era. Classic framework lock-in, albeit to a lesser extent than other, larger web frameworks. I&amp;#8217;ve thought a lot about why this happened and believe that if you try to make a land-grab early on and abstract too much too early then you get stuck with your abstractions due to backwards compatibility. Good software grows slowly.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1498 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1499&quot; class=&quot;comment byuser comment-author-admin bypostauthor odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1499&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c8475420ebca73833e55ccf57d8d7500?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;https://caines.ca&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Gregg Caines&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-14T13:30:35+00:00&quot;&gt;April 14, 2013 at 1:30 pm&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Yeah I totally agree, and you&amp;#8217;ve probably explained it even better than I did.&lt;/p&gt;
&lt;p&gt;Express is actually a bit of a conundrum for me for a few reasons, especially since in trying to create a mini API framework myself ( &lt;a href=&quot;https://percolatorjs.com&quot; rel=&quot;nofollow&quot;&gt;https://percolatorjs.com&lt;/a&gt; ), I&amp;#8217;ve felt forced into duplicating some of the things I dislike about the modularity (or lack of modularity) in express, to the point that I eventually gave up and added &amp;#8216;connect&amp;#8217; middleware support.  There are a few competing pressures that make web frameworks like express (and rails for that matter) popular:&lt;/p&gt;
&lt;p&gt;(1) Some people just want to &amp;#8220;get shit done&amp;#8221; &amp;#8482; and don&amp;#8217;t want to have to search for multiple pieces of a puzzle to hobble together a solution.  I think there&amp;#8217;s probably a gap where finding the best modules for a given problem is still a too hard.  Filling that gap (somehow) will promote collaboration even more.  The current npm search (on its own) doesn&amp;#8217;t solve the problem IMO.&lt;/p&gt;
&lt;p&gt;(2) HTTP is actually really complicated and very hard to abstract effectively.  For example, how many frameworks 404 when you try an invalid method on an existing resource instead of the proper 405?  This is mostly because of the way routing is abstracted; These frameworks use the http method as the first &amp;#8216;key&amp;#8217; in the routing table, when really the url makes more sense as a key and the method should be secondary.  There are a number of cross-cutting aspects like this including logging, error-handling, and authentication where some sort of centralized pre-processing makes a lot of sense.  Not all &amp;#8220;aspects&amp;#8221; should be handled with serialized pre-processing middleware though, and unfortunately that&amp;#8217;s what we&amp;#8217;re seeing a proliferation of.  I&amp;#8217;m disappointed that I can&amp;#8217;t build a mini-framework without integrating connect, or rewriting/repackaging all those otherwise great connect middleware modules out there, but I don&amp;#8217;t know a better way.  To be honest, I don&amp;#8217;t even know at this point what the better abstraction would be.  Doing everything in pre-processing middleware and monkey-patching the request/response objects doesn&amp;#8217;t seem like the answer though.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1499 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1507&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1507&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/2c3f82d7e0971f4c1e2a0362f7d67bc4?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://iknuth.com&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Edwin Knuth&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-15T22:41:53+00:00&quot;&gt;April 15, 2013 at 10:41 pm&lt;/time&gt;:	&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Good stuff.  I haven&amp;#8217;t felt this excited about a platform community in a long time.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1507 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1508&quot; class=&quot;comment odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1508&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c1f1e16b07305fafb16504e0bcd26c87?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://teddy.fr&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Ronan Berder&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-15T23:37:41+00:00&quot;&gt;April 15, 2013 at 11:37 pm&lt;/time&gt;:	&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Good read: spot on.&lt;/p&gt;
&lt;p&gt;I would add a couple additional factors to that trend:&lt;/p&gt;
&lt;p&gt;- Proper package management: `npm` was and still is what got me hooked up. Package management is often an afterthought that is rarely properly addressed.&lt;/p&gt;
&lt;p&gt;- Flat community: which is partly illustrated with the extreme culture of re-use you mentioned. I feel there is much lower friction in creating and contributing to modules in the node.js community, with no gate keeper in sight.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1508 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1509&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1509&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/f5eb27f42a3a520903f1a4b8e55744e4?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; style=&quot;height:70;width:70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://qq.is/&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Mark Smith&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T00:26:52+00:00&quot;&gt;April 16, 2013 at 12:26 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;For a similar system: Perl&amp;#8217;s CPAN (the package repository) has been online since 1995 and presently has 120,447 modules for a yearly rate of 6691 modules for 18 years now.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s been providing the same functionality you mention: an encouraged license (&amp;#8220;the same terms as Perl&amp;#8221;), a monoculture of software (CPAN for package distribution/documentation), and an emphasis on tiny modules. Little packages are encouraged and really the way to go when you&amp;#8217;re building Perl modules.&lt;/p&gt;
&lt;p&gt;That said, it&amp;#8217;s great to see those practices being adopted successfully by Node and seeing the success of the groups using it. We live in very exciting times for open source. :)&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1509 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1510&quot; class=&quot;comment odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1510&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/7617806a46bacb54f44c7ca8f6647e6e?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://liveditor.com&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Edwin Yip | dev of LIVEditor&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T03:02:19+00:00&quot;&gt;April 16, 2013 at 3:02 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;The &amp;#8220;The Tiny Module Aesthetic&amp;#8221; reminds me that, the emerging of  the &amp;#8220;Single-purpose app&amp;#8221; in recent years, and the design philology of the Unix utilities. And I think those are all about &amp;#8220;simplicity&amp;#8221;, which I think and care about the more and more in recent years, but I always have to remind myself about when writing code for LIVEditor &amp;#8211; my code editor with &amp;#8220;Firebug&amp;#8221; embedded.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1510 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1512&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1512&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/7a3cffc8ed6e84af12c633e063cd1ec1?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;Mansur&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T03:21:08+00:00&quot;&gt;April 16, 2013 at 3:21 am&lt;/time&gt;:				&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;There are some frameworks in Node.JS which are just copied, not unique, like for example &lt;a href=&quot;https://github.com/biggora/caminte&quot; rel=&quot;nofollow&quot;&gt;https://github.com/biggora/caminte&lt;/a&gt; &amp;#8211; is just a copy of Juggling DB &lt;a href=&quot;https://github.com/1602/jugglingdb&quot; rel=&quot;nofollow&quot;&gt;https://github.com/1602/jugglingdb&lt;/a&gt;.&lt;br /&gt;
I would strongly recommend to use genuine frameworks which have been tested by the community and better supported.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1512 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1514&quot; class=&quot;comment odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1514&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c3c59c91293af5a13a840a9855024afe?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://www.technostall.com/&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Chankey Pathak&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T04:11:27+00:00&quot;&gt;April 16, 2013 at 4:11 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Why don&amp;#8217;t you consider Perl? 120,460 Perl modules in 15 years, that makes it 8030 modules per year and it&amp;#8217;s increasing exponentially now.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1514 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1515&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1515&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/5a07b05ddc37550d0dd6311c4a4c31ca?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;PeterisP&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T04:16:12+00:00&quot;&gt;April 16, 2013 at 4:16 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;&amp;#8220;Batteries not included&amp;#8221; approach puts a significant cost on application developers.&lt;br /&gt;
If I need to do a simple thing X, I&amp;#8217;d rather have a single good library for X rather than twenty libraries with varying focus and quality.  Even if one of those twenty libraries would be far better for my needs, the task of properly comparing and choosing the lib is often higher than doing X with a random library.&lt;/p&gt;
&lt;p&gt;It also reduces maintainability &amp;#8211; if one project uses lib1 for X, and another project uses lib2 with a different API for the exact same thing, then it makes stuff harder to maintain.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1515 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1516&quot; class=&quot;comment byuser comment-author-admin bypostauthor odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1516&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c8475420ebca73833e55ccf57d8d7500?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;https://caines.ca&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Gregg Caines&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T06:29:43+00:00&quot;&gt;April 16, 2013 at 6:29 am&lt;/time&gt;:	&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;@ Chankey Pathak, Mark Smith: For the record, I didn&amp;#8217;t include perl because I haven&amp;#8217;t got any perl experience to draw from, while I&amp;#8217;ve spent years writing reams of code in ruby, python and node.js.  I can honestly say though that CPAN is nothing short of legendary even outside the perl community, and npmjs.org would do well to follow its lead.  It would be interesting to know too how CPAN maintains that rate of growth, and if it&amp;#8217;s due to the same things I&amp;#8217;ve mentioned.&lt;/p&gt;
&lt;p&gt;I should also add that node.js isn&amp;#8217;t even the language/platform that&amp;#8217;s nearest and dearest to my heart.  I&amp;#8217;d really just love my other favorite languages&amp;#8217; ecosystems to pick up some of these qualities.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1516 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1518&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1518&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/e03a08f9418b20c5a3ea8956a40f595b?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;https://twitter.com/sheeshee&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Su-Shee&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T08:47:49+00:00&quot;&gt;April 16, 2013 at 8:47 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;From a CPAN&amp;#8217;s lover&amp;#8217;s perspective NPM already is _very_ well done and pretty smooth to use. &lt;/p&gt;
&lt;p&gt;From a Perl lover&amp;#8217;s perspective, JavaScript doesn&amp;#8217;t have a choice anyways, because you really NEED a lot of modules to work around well let&amp;#8217;s politely say &amp;#8220;language quirks&amp;#8221;. ;) &lt;/p&gt;
&lt;p&gt;You simply need things like underscore or node, because it gives you things which aren&amp;#8217;t builtin in the language. (*cough* npm install printf *cough* ;) &lt;/p&gt;
&lt;p&gt;Similarily, Perl has gotten its Lisp-style MOP OO module Moose, because there&amp;#8217;s no such thing as a &amp;#8220;class&amp;#8221; in Perl. &lt;/p&gt;
&lt;p&gt;Our equivalent of underscore-alike modules are for example List::Utils, Lists::MoreUtils etc. etc. &amp;#8211; and you can&amp;#8217;t possibly shove ALL those modules into what we call &amp;#8220;core&amp;#8221; &amp;#8211; set aside that half of the people want Foo and the other half Bar and then there&amp;#8217;s our  &amp;#8220;problem&amp;#8221; we&amp;#8217;re really proud of: Backwards compatibility is _amazing_ in Perl and there&amp;#8217;s always someone who runs a 12 year old Perl and still needs his Really::Ancient::Module::BlahBlah. ;) &lt;/p&gt;
&lt;p&gt;So far I encountered exactly ONE npm module which I couldn&amp;#8217;t install blindly with npm install -g &amp;#8211; and that was due to an architecture check in its requirements (which isn&amp;#8217;t necessary, module very high level) and my Linux flavor returns a different architecture string &amp;#8211; so one lesson might be to encourage a best practise &amp;#8220;don&amp;#8217;t overdo requirements for your module, it just complicates things&amp;#8221;&lt;/p&gt;
&lt;p&gt;In Perl, it&amp;#8217;s common that you simply ask &amp;#8220;the community&amp;#8221; (IRC for example) &amp;#8220;what do I want for XY?&amp;#8221; and get a variety of 2-5 modules and a short explanation why you want A and not B. Imagine for example you have more than one XML/HTML parser module (which we do) &amp;#8211; do you want XPath support or do you prefer DOM-style methods? Do you need a strict parser or do you want to work on dirty HTML? &lt;/p&gt;
&lt;p&gt;Most module authors mention these kinds of use cases and &amp;#8220;flavors&amp;#8221; to do things and refer graciously to the alternatives. Plus, there&amp;#8217;s the entire commenting and rating system for modules and yes, you of course look if Perl gurus Tom, Dick and Harry Superperl ranks module Foo highly or not &amp;#8211; it&amp;#8217;s not that we don&amp;#8217;t have our own little rockstars and divas. ;)&lt;/p&gt;
&lt;p&gt;Due to variety and so many choices, there&amp;#8217;s also bad choices and we put A LOT of work into discouraging certain modules these days which are simply not really appropriate to use in 2013 or some well known badly written ones. But you can&amp;#8217;t just throw them out, too &amp;#8211; because Perl is installed everywhere &amp;#8211; what is the browser for JavaScript is pretty much any Linux/Unix for Perl. And all the shitty JavaScript quirks you&amp;#8217;ve gotten from browser vendors, we get from distributors which come with a Perl from 1999 in 2013. &lt;/p&gt;
&lt;p&gt;Sooner rather than later (there already are a couple) there will be a class of modules on NPM which are dual use &amp;#8211; browser and Node-based server-side and you will have to keep that straight and compatible and that will be a lot of work. Also, what if people start writing JavaScript modules which are able to run in browser, on Node AND on e.g. spidermonkey? (what about Rhino/Nashorn?) I&amp;#8217;d encourage that a lot, not everything needs Node and NPM is the de facto thing to put a module up on by now. &lt;/p&gt;
&lt;p&gt;Another advantage of CPAN is: It&amp;#8217;s _extremely_ centralized. You look for a module on CPAN. Period. There&amp;#8217;s no &amp;#8220;download from here&amp;#8221; or &amp;#8220;fetch from there&amp;#8221; &amp;#8211; it&amp;#8217;s on CPAN or it doesn&amp;#8217;t exist. As CPAN is tested and tested and retested by volunteers, using modules from CPAN pretty much ensures been tested on a dozen platforms. If you use the plain &amp;#8220;cpan Foo::Bar&amp;#8221; installer, you can always watch all tests live while running the installation of a module.&lt;/p&gt;
&lt;p&gt;And Perl modules have tests LIKE THERE&amp;#8217;S NO TOMORROW &amp;#8211; as Perl&amp;#8217;s testing flavor TAP is extremely easy and simply and cheaply to do, modules actually _do_ have a LOT of tests.&lt;/p&gt;
&lt;p&gt;Last but not least: On average, the commonly used Perl modules are _extremely_ well documented  and the docs can be read on commandline and via web. The documentation style is probably rather old-school from a Node lover&amp;#8217;s perspective &amp;#8211; it&amp;#8217;s more on the dry, informative side and less about being cute and funny &amp;#8211;  but some docs literally go into the amount of a book written.&lt;/p&gt;
&lt;p&gt;Also, no matter how big a project &amp;#8211; I simply expect it to be installable via CPAN. There&amp;#8217;s a couple of Perl things which are more applications but &amp;#8220;modules&amp;#8221; and are not installable via CPAN, but that&amp;#8217;s pretty rare. Entire frameworks are installed via CPAN &amp;#8211; think like the difference of how you install Derby.js and Meteor.js. &lt;/p&gt;
&lt;p&gt;And: I run deliberately large dependency-chains for the fun of it &amp;#8211; CPAN has a flag for &amp;#8220;resolve all dependencies yourself and say auto-yes to everything you&amp;#8217;re asked during installation&amp;#8221; and I manage a couple of hundred modules in ONE session WITHOUT any error while running ALL tests during installation &amp;#8211; possibly on half a dozen Perl versions (Made with perlbrew which is our nvm/rvm/virtualenv). &lt;/p&gt;
&lt;p&gt;As the Perl mantra &amp;#8220;there&amp;#8217;s more than one way to do it&amp;#8221; is done by the JavaScript community on the same level of excess (a dozen web frameworks anyone? ;)  you&amp;#8217;ve made your choice already anyways to go down the road of extreme flexibility and variety. It already happened, no going back here. &lt;/p&gt;
&lt;p&gt;The Perl community for example is very forceful to really push people into using modules from CPAN exactly BECAUSE they&amp;#8217;re tested and have solved hundreds of problems for you &amp;#8211; you don&amp;#8217;t split a CSV file by hand, you use Text::CSV which is proven to work for a decade. You won&amp;#8217;t do better with your meager little split. :) &lt;/p&gt;
&lt;p&gt;You don&amp;#8217;t parse HTML with regex, you use a module. You don&amp;#8217;t validate email addresses by hand, you use a module. We have modules like Regex::Common for example which contain a range of common usecases people usally throw (bad) regex on or modules which pretty much read any stupid format known to mankind &amp;#8211; it&amp;#8217;s all put into modules and more modules. &lt;/p&gt;
&lt;p&gt;Luckily, Perl also has most of the necessary modules I usally call &amp;#8220;boring shit&amp;#8221; modules &amp;#8211; Excel reading and writing anyone? Those are the true heroes in my opinion &amp;#8211; people who sit down and really write this kind of ungrateful, boring stuff you suddenly need there&amp;#8217;s *gasp* lurking an &amp;#8220;enterprise&amp;#8221; around the corner &amp;#8211; not to mention that nobody in their right mind is going to implement SSL bindings three times. (One lesson for JavaScript/Node might be to maybe not add another web framework but deliberately go for the boring stuff sooner rather than later and get it over with..) &lt;/p&gt;
&lt;p&gt;For my part, I can&amp;#8217;t rave enough about CPAN and some of the people poured their hearts and time and knowledge into some modules. Billion euro/dollar businesses run on it &amp;#8211; some for over a decade straight. &lt;/p&gt;
&lt;p&gt;So, hack, upload and enjoy. :)  &lt;/p&gt;
&lt;p&gt;Yours truely &amp;#8211; a Perl lover. :) &lt;/p&gt;
&lt;p&gt;CPAN&amp;#8217;s main website: &lt;a href=&quot;http://metacpan.org&quot; rel=&quot;nofollow&quot;&gt;http://metacpan.org&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1518 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1519&quot; class=&quot;comment odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1519&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/d0d69c7fb957410cba3d3a1ce6d2e7d3?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://subdigit.com/&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;subdigit&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T09:19:34+00:00&quot;&gt;April 16, 2013 at 9:19 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Maven is also something that&amp;#8217;s begun to pick up pace in the Java community.  Stats seem to be here: &lt;a href=&quot;http://search.maven.org/#stats&quot; rel=&quot;nofollow&quot;&gt;http://search.maven.org/#stats&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But not sure about exact growth rate.  A pretty picture is available here: &lt;a href=&quot;http://mvnrepository.com/&quot; rel=&quot;nofollow&quot;&gt;http://mvnrepository.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While having a small standard library is great for essentially encouraging reinventing the wheel to make it better, it can at times be a detriment for &amp;#8220;just getting things done&amp;#8221;.  It&amp;#8217;s called a &amp;#8220;standard&amp;#8221; for a reason, which is that you can rely on it to be present and available for use, and more importantly, for understanding by the developers that come in and out of a project.&lt;/p&gt;
&lt;p&gt;That being said, popular extensions will solidify and essentially become a 3rd party standard for use and becomes indispensable and tied into the core project, whether it&amp;#8217;s just the common-knowledge standard du jour, or it actually gets merged in.&lt;/p&gt;
&lt;p&gt;It certainly is a more interesting way to get a diversity of development of what people consider to be core though.  For that, I find that model interesting to watch and see how it grows and if anything I favor &amp;#8220;wins&amp;#8221; :).&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1519 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1520&quot; class=&quot;comment byuser comment-author-admin bypostauthor even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1520&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c8475420ebca73833e55ccf57d8d7500?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;https://caines.ca&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Gregg Caines&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T09:37:13+00:00&quot;&gt;April 16, 2013 at 9:37 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Su-Shee: thanks for the education! I agree, CPAN sounds great.  Since we&amp;#8217;re getting along so well, I won&amp;#8217;t say anything about the language itself.  :) &lt;/p&gt;
&lt;p&gt;A few minor clarifications on javascript in 2013:  Don&amp;#8217;t `npm install printf`, use util.format:  &lt;a href=&quot;https://nodejs.org/api/util.html#util_util_format_format&quot; rel=&quot;nofollow&quot;&gt;https://nodejs.org/api/util.html#util_util_format_format&lt;/a&gt; .  Underscore is much less necessary nowadays (especially in node.js) as a result of ecmascript 1.6 improvements  (See &amp;#8220;iteration methods&amp;#8221; at &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array&quot; rel=&quot;nofollow&quot;&gt;https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array&lt;/a&gt; ).  Also using jslint will keep you 99% quirk-free (I have it integrated into my builds and vim).&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1520 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1521&quot; class=&quot;comment odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1521&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/0fc5485611721e78b1583657212a046a?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://sourcecontribute.com/&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Rudolf Olah&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T10:30:05+00:00&quot;&gt;April 16, 2013 at 10:30 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;There&amp;#8217;s no need to slander the GPL in this post, it&amp;#8217;s just as permissive and would allow the same type of collaboration. The trouble is that most developers also want to use libraries as part of proprietary code bases. I don&amp;#8217;t understand why they don&amp;#8217;t just dual-license; GPL for non-profits and devs, MIT/BSD for commercial/proprietary software.&lt;/p&gt;
&lt;p&gt;There really should be a bigger push to license internal code under the GPL. 99% of the time it doesn&amp;#8217;t offer a competitive edge. It&amp;#8217;s the data and marketing and network effects that have more to do with it than anything.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1521 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1522&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1522&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/9b947f8fe80d95df24fd3ab465869bc2?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;Andrew de Andrade&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T10:46:25+00:00&quot;&gt;April 16, 2013 at 10:46 am&lt;/time&gt;:	&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Great post. I&amp;#8217;d also add to that list the benefits of local by default packages that are in your project folder. The approach of tools like easy_install, pip, bundler, etc is to hide all your depemdencies in some dot-prefixed folder outside your project directory. This promotes an out of sight, out of mind mentality. The npm approach on the other hand puts them in your project and makes it much more likely that you are going to explore the source of your dependencies, more likely that you bug fix those dependencies instead of work around bugs and most importantly you&amp;#8217;ll treat that folder like part of your own project. This last point means that you are likely to develop one of your own generic modules to the point where it&amp;#8217;s good enough to submit back to npm as a public module.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1522 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1523&quot; class=&quot;comment odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1523&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/e03a08f9418b20c5a3ea8956a40f595b?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;https://twitter.com/sheeshee&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Su-Shee&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T11:03:23+00:00&quot;&gt;April 16, 2013 at 11:03 am&lt;/time&gt;:	&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Oh, go ahead and say something about the language and I will probably tell you the exact same thing back about JavaScript &amp;#8211; or something quite similar. If anything, both have A LOT of history and baggage &amp;#8211; but they both also have A LOT of flexibility, otherwise the range of modules existing as of today wouldn&amp;#8217;t even be possible and people wouldn&amp;#8217;t deliver at that speed. And let&amp;#8217;s face it: We can happily unite (Come along, you too Java, don&amp;#8217;t be shy&amp;#8230;) in Python&amp;#8217;s and Ruby&amp;#8217;s dislike for {} and ; &amp;#8211; and we use a lot of them. ;)  &lt;/p&gt;
&lt;p&gt;Sadly, format.util supported too few options when I looked last. (In the end, I did it in DB anyways..) &amp;#8211; but it&amp;#8217;ll evolve, I&amp;#8217;m sure. &lt;/p&gt;
&lt;p&gt;Underscore will probably move to other list-supporting functions over the years I would expect, the map-grep-filter-foreach range is just the basics anyways. (At least, Perl didn&amp;#8217;t need map-grep-foreach-shift-unshift-push-pop-splice as a module, that really is core-core&amp;#8230;)&lt;/p&gt;
&lt;p&gt;And before someone is tempted to bitch about Java-and-Maven: _THAT_ community delivered literally EVERYTHING I can think up of &amp;#8220;boring shit&amp;#8221; and &amp;#8220;enterprisey stuff&amp;#8221; you can imagine. And if you ever looked for &amp;#8220;good PDF manipulation&amp;#8221; for example: Java did deliver. Kudos for that. &lt;/p&gt;
&lt;p&gt;If anything the lesson simply is: Yes, you want TONS of modules, yes, the environment IS important, no, it doesn&amp;#8217;t matter if you&amp;#8217;re a less-than-perfect language, as long as you support a certain flexibility, people will work around it. &lt;/p&gt;
&lt;p&gt;And style evolves a lot &amp;#8211; nobody writes JavaScript like in 2000 anymore and you get discouraged a lot to do so &amp;#8211; same goes for Perl. But if you already had a web business in 2000, you probably just can&amp;#8217;t throw out your entire carefully crafted JavaScript or your backend of the day (in 2000) and that is something EVERYBODY faces. Perl did and we paid dearly, Java does, Ruby will, Python will do too. &lt;/p&gt;
&lt;p&gt;JavaScript showed &amp;#8211; thanks to Douglas Crockford and jQuery among others and yes, thanks to Node.js, too &amp;#8211; how to evolve nicely into a new style &amp;#8211; but also Node.js setups will at some point be really huge and not that easily updated anymore and then you face the very same thing everybody else does. &lt;/p&gt;
&lt;p&gt;And god do I wish this petty bickering among languages would stop &amp;#8211; we owe each other so many things &amp;#8211; all of us &amp;#8211; and all of us owe Lisp and Smalltalk and C. &lt;/p&gt;
&lt;p&gt;Let me all remind you that there was a time when &amp;#8220;real programmers&amp;#8221; laughed about using a &amp;#8220;scripting language&amp;#8221; on this cheap little Linux hack with this meh little HTML thingie to put up a business on and now look where we all are today&amp;#8230;&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1523 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1524&quot; class=&quot;comment byuser comment-author-admin bypostauthor even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1524&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c8475420ebca73833e55ccf57d8d7500?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;https://caines.ca&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Gregg Caines&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on :&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Su-shee: Totally agree.  Well said.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1524 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1525&quot; class=&quot;comment byuser comment-author-admin bypostauthor odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1525&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c8475420ebca73833e55ccf57d8d7500?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;https://caines.ca&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Gregg Caines&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T12:39:51+00:00&quot;&gt;April 16, 2013 at 12:39 pm&lt;/time&gt;:				&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Rudolph:  &amp;#8220;Slander&amp;#8221; is a legal term and a pretty ridiculous one for what I said.  More legalese isn&amp;#8217;t going to help the GPL&amp;#8217;s case.  You already agree that the GPL is more restrictive for people mixing software with other proprietary software, so how can it *possibly* be slanderous for me to say it&amp;#8217;s not as permissive?&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1525 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1526&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1526&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c794c7c92f51240638e2ba1e8952f854?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://www.luarocks.org&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Hisham&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T12:49:20+00:00&quot;&gt;April 16, 2013 at 12:49 pm&lt;/time&gt;:	&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Well, counting the age of the Python and Ruby repos by the age of the language (and not of the package management projects, such as pypi and rubygems) while considering node.js by the age of the project and not the language (JavaScript) skews the numbers quite a bit!&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s compare by language age:&lt;/p&gt;
&lt;p&gt;python:  29,720 packages / 22 years (1991) = 1351 packages per year&lt;/p&gt;
&lt;p&gt;ruby:      54,385 packages / 18 years (1995) =    3022 packages per year&lt;/p&gt;
&lt;p&gt;node.js  26,966 packages / 18 years (1995) =   1498 packages per year&lt;/p&gt;
&lt;p&gt;And by package manager age:&lt;/p&gt;
&lt;p&gt;python:  29,720 packages / 11 years (2002?)  = 2701 packages per year&lt;/p&gt;
&lt;p&gt;ruby:      54,385 packages / 10 years (2003) = 5438 packages per year&lt;/p&gt;
&lt;p&gt;node.js  26,966 packages / 4 years (2009) = 6742 packages per year&lt;/p&gt;
&lt;p&gt;Except that, of course, these numbers are meaningless, because each language/tools has its own submission evaluation process (including &amp;#8220;no evaluation&amp;#8221;), and also different granularities in how to count &amp;#8220;packages&amp;#8221; (by module? by a set of modules that compose a project?).&lt;/p&gt;
&lt;p&gt;Also, language-specific package managers are more or less a new thing &amp;#8212; counting for example the number of packages submitted &lt;i&gt;last year&lt;/i&gt; would be a more meaningful metric (apart from the problems I raised above.)&lt;/p&gt;
&lt;p&gt;Still, it&amp;#8217;s nice to see that language-specifc package managers are thriving, and I wish all the best to all of them. :)&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1526 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1532&quot; class=&quot;comment odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1532&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/f1e3ab214a976a39cfd713bc93deb10f?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;TJ&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T17:40:50+00:00&quot;&gt;April 16, 2013 at 5:40 pm&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;The reason Express is the size it is, is because all these things are what we would be duplicating each time anyway. Yes a lot of it could/should/will live in npm, but an aggregate is not harmful. Look at npm-www for example, this is what happens when you re-create things every single time you write an app, it becomes are large unwieldy mess of stitching together random things and re-inventing within the app itself instead of an aggregate &amp;#8220;framework&amp;#8221;. Most middleware should absolutely be abstracted to a lower level and then &amp;#8220;wrapped&amp;#8221; as middleware, there&amp;#8217;s no question about that, but should they cease to exist? absolute not.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1532 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1534&quot; class=&quot;comment byuser comment-author-admin bypostauthor even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1534&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c8475420ebca73833e55ccf57d8d7500?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;https://caines.ca&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Gregg Caines&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-16T20:07:35+00:00&quot;&gt;April 16, 2013 at 8:07 pm&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;TJ: Yeah, I actually agree that the core http module isn&amp;#8217;t a useful enough abstraction to be used for many (most?) real world web applications.  It also doesn&amp;#8217;t offer a reasonable way to add functionality other than wrapping it or monkey-patching the request/response objects.  Cross-cutting concerns are the obvious problem (security, logging, routing, etc), but also: what if you want to just add functionality that&amp;#8217;s more easily accessible than constantly requiring the same 20 modules that are all very HTTP relevant?  And I agree that larger aggregates are useful and valid (and I bet you&amp;#8217;d also agree conversely that putting an orm in a web server abstraction is a superfluous aggregation, and so there are limits to what aggregates make sense).    &lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t actually have a better solution than what express does.  I hope that was obvious from my comments.  I certainly tried, but ended up coming back to connect.  At the same time, I find it unfortunate that connect middleware have non-obvious interdependencies and are difficult to keep clash-free (basically all the problems of monkey-patching).  But like I say, I haven&amp;#8217;t got a better proposal.&lt;/p&gt;
&lt;p&gt;I personally don&amp;#8217;t think node.js has the HTTP abstraction problem solved very well (yet).&lt;/p&gt;
&lt;p&gt;&gt; Most middleware should absolutely be abstracted to a lower level and then “wrapped” as middleware, there’s no question about that&lt;/p&gt;
&lt;p&gt;Not a bad start!&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1534 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1536&quot; class=&quot;comment odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1536&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c3c59c91293af5a13a840a9855024afe?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://www.tizentips.com/&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Chankey Pathak&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-17T00:12:52+00:00&quot;&gt;April 17, 2013 at 12:12 am&lt;/time&gt;:	&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;@Su-Shee: If there would be an upvote button on comments here I would&amp;#8217;ve hit it so hard that it would break my mouse! Well written, +1 to you.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1536 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1587&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1587&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/efab0eadca0e9998429621eb25379f37?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://gflarity.github.com&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Geoff Flarity&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-04-21T20:38:03+00:00&quot;&gt;April 21, 2013 at 8:38 pm&lt;/time&gt;:				&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Some times I get confused when people try to convince other&amp;#8217;s programmers that easily re-usuable modules are awesome and you should try them. Then I remember that not every was into perl 10 years a go&amp;#8230;  Even if you&amp;#8217;re not a fan of the perl syntax (beauty), CPAN is the shit and so is NPM.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1587 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1623&quot; class=&quot;pingback odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;p class=&quot;row&quot;&gt;
&lt;strong class=&quot;ping-label span1&quot;&gt;Pingback:&lt;/strong&gt;
&lt;span class=&quot;span7&quot;&gt;&lt;a href=&quot;http://open.blogs.nytimes.com/2013/04/25/this-weeks-links-_why-edition/&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;This Week&amp;#039;s Links: _why Edition - NYTimes.com&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1903&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-1903&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/ccd75193c0478fcb39029aa2cd2da43b?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;a href=&quot;http://www.shybadger.com&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;Adam&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-05-15T20:17:50+00:00&quot;&gt;May 15, 2013 at 8:17 pm&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;I&amp;#8217;m sure this was already said.. but you can&amp;#8217;t compare node.js to php/ruby. I am a node developer.. but node is a new FRAMEWORK. It would be more accurate to compare JAVASCRIPT to php/ruby.&lt;/p&gt;
&lt;p&gt;Just FYI&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1903 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-1905&quot; class=&quot;comment byuser comment-author-admin bypostauthor odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;article id=&quot;comment-1905&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://0.gravatar.com/avatar/c8475420ebca73833e55ccf57d8d7500?s=70&amp;amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;&lt;time pubdate=&quot;&quot; datetime=&quot;2013-05-15T23:17:40+00:00&quot;&gt;May 15, 2013 at 11:17 pm&lt;/time&gt;:&lt;/span&gt;					&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;Adam: The comparisons I make are comparisons in the customs of the communities surrounding those technologies and not the technologies themselves.  I think at that level, it&amp;#8217;s apples-to-apples.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-1905 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-2121&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-2121&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/ffb3baf93be7d2ae4e5ea0f72c803dbf?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;Juzer Ali&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-06-30T12:30:43+00:00&quot;&gt;June 30, 2013 at 12:30 pm&lt;/time&gt;:					&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;@PeterisP:&lt;br /&gt;
&amp;gt; “Batteries not included” approach puts a significant cost on application developers.&lt;br /&gt;
I agree, it sure wastes a hell lot of time.&lt;/p&gt;
&lt;p&gt;@TJ: Is express code too succinct for what it does? For example, its very difficult to figure out what is happening inside a router &lt;a href=&quot;https://github.com/visionmedia/express/blob/master/lib/router/index.js#L46&quot; rel=&quot;nofollow&quot;&gt;https://github.com/visionmedia/express/blob/master/lib/router/index.js#L46&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-2121 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-2170&quot; class=&quot;pingback odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;p class=&quot;row&quot;&gt;
&lt;strong class=&quot;ping-label span1&quot;&gt;Pingback:&lt;/strong&gt;
&lt;span class=&quot;span7&quot;&gt;&lt;a href=&quot;http://scalableapps.com/?p=1&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;To node or not to node – overview of Node.js | Developing Scalable Applications&lt;/a&gt;&lt;span class=&quot;sep&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-2323&quot; class=&quot;comment even thread-even depth-1&quot;&gt;
&lt;article id=&quot;comment-2323&quot; class=&quot;comment row&quot;&gt;
&lt;div class=&quot;comment-author-avatar span1&quot;&gt;
&lt;img alt=&quot;&quot; src=&quot;https://1.gravatar.com/avatar/368346708a485060d31f77677a21d2a5?s=70&amp;amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D70&amp;amp;r=G&quot; class=&quot;avatar avatar-70 photo&quot; height=&quot;70&quot; width=&quot;70&quot; /&gt;				&lt;/div&gt;
&lt;footer class=&quot;comment-meta span7&quot;&gt;
&lt;p class=&quot;comment-author vcard&quot;&gt;
&lt;span class=&quot;fn&quot;&gt;Simon Boudrias&lt;/span&gt; &lt;span class=&quot;says&quot;&gt;said&lt;/span&gt; on &lt;time pubdate=&quot;&quot; datetime=&quot;2013-09-13T10:17:43+00:00&quot;&gt;September 13, 2013 at 10:17 am&lt;/time&gt;:&lt;/p&gt;&lt;!-- .comment-author .vcard --&gt;
&lt;/footer&gt;&lt;!-- .comment-meta --&gt;
&lt;div class=&quot;comment-content span7&quot;&gt;
&lt;p&gt;@Adam I have to disagree here. JavaScript is only a language (it is syntax), PHP/Ruby are more than syntax, it is syntax + all about the runtime and functions hooks to the environment. Node.js is JavaScript + runtime/hooks stuff. That&amp;#8217;s why Node.js is comparable to PHP and Ruby, JavaScript isn&amp;#8217;t.&lt;/p&gt;
&lt;/div&gt;&lt;!-- .comment-content --&gt;
&lt;/article&gt;&lt;!-- #comment-2323 .comment --&gt;
&lt;/li&gt;
&lt;li id=&quot;li-comment-2404&quot; class=&quot;pingback odd alt thread-odd thread-alt depth-1&quot;&gt;
&lt;p class=&quot;row&quot;&gt;
&lt;strong class=&quot;ping-label span1&quot;&gt;Pingback:&lt;/strong&gt;
&lt;span class=&quot;span7&quot;&gt;&lt;a href=&quot;http://adaptivepatterns.net/blog/?p=1418&quot; rel=&quot;external nofollow&quot; class=&quot;url&quot;&gt;~ The Truth about JavaScript. &amp;laquo; Clint Nash&lt;/a&gt;&lt;span class=&quot;sep&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;!-- .commentlist .unstyled --&gt;
&lt;/div&gt;&lt;!-- #comments --&gt;
</content>
	</entry>
	
	<entry>
		<title>Release-ophobia</title>
		<link href="/posts/2014-06-03-release-ophobia/"/>
		<updated>2013-03-16T14:33:09Z</updated>
		<id>/posts/2014-06-03-release-ophobia/</id>
		<content type="html">&lt;p&gt;If you’ve developed SaaS in a large organization (or even a small organization that acts like one), you’ve probably seen some of the symptoms of fear of releasing software:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Off-hours deployments and weekend deployments&lt;/li&gt;
&lt;li&gt;Infrequent releases&lt;/li&gt;
&lt;li&gt;extended code-freeze and testing cycles&lt;/li&gt;
&lt;li&gt;Reluctance to refactor&lt;/li&gt;
&lt;li&gt;Feature branches for the purpose of ‘cherry-picking’&lt;/li&gt;
&lt;li&gt;release managers&lt;/li&gt;
&lt;li&gt;many non-customer-facing environments before production.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These symptoms usually happen only in larger/older organizations, because of two factors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They take a lot more personnel / time to implement than smaller organizations have.&lt;/li&gt;
&lt;li&gt;They are usually processes and attitudes that are collected as a reaction to problems that occur in the course of a company’s lifetime.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;#“But you can’t be too careful!”
One problem is that you CAN indeed be too careful. It’s absolutely imperative that the costs be considered as well, if you want software development to still go reasonably fast. Otherwise these manual preventative processes will slowly creep in over time and your team will be releasing at a snail’s pace.&lt;/p&gt;
&lt;p&gt;The other problem is that these policies alone are in some ways not careful &lt;em&gt;enough&lt;/em&gt;. Where are the techniques for mitigating defects that inevitably still slip through? Where are the techniques to detect them, limit the customers exposed, and limit the time that customers are exposed?&lt;/p&gt;
&lt;p&gt;All of these symptoms have a few things in common: They tend toward heavy &lt;strong&gt;manual and preventative&lt;/strong&gt; process added generously over time, usually with little thought to the cost/benefit ratio of such process. It’s all too common for every production issue to result in a new process to prevent it, without regard to how infrequently that problem might occur, how damaging the result is, or how easily it is rectified.&lt;/p&gt;
&lt;h1&gt;So how do we keep bugs from getting to our customers?!?&lt;/h1&gt;
&lt;p&gt;Non-preventative measures (I call them “&lt;strong&gt;Reactive Measures&lt;/strong&gt;“) do indeed exist, and can help you safely maintain a fast and steady flow of new features to customers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://code.flickr.net/2009/12/02/flipping-out/&quot;&gt;Feature-Flags&lt;/a&gt; allow you to commit incomplete work to master and push it to production safely. Customer-specific feature flags allow you to test in production or enroll customers in a beta program. With a good feature-flag system, it’s even possible to release a feature to only a certain percentage of customers, and to watch your metrics to see the effects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy/fast (read “Automated”) deployment.&lt;/strong&gt; If deployment takes a long time, then you can’t afford to deploy often. Also, if you can’t deploy quickly, you can’t redeploy quickly (in the event of a problem).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy-undo.&lt;/strong&gt; Rolling back from a defective release to a known-good release is the simplest and fastest way to recover from defects, if the process is both quick and easy. Defects will happen no matter how much prevention you use: Easy-undo can mean the difference between light customer impact and heavy customer impact.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smaller releases.&lt;/strong&gt; Smaller releases have less code, and therefore generally less bugs. Because they don’t contain many changes, they’re easier to test and a rollback is less-likely to negatively impact a customer. Also when a production defect appears in the latest release you have much less code to sift through to determine the cause.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice Continuous Integration&lt;/strong&gt; (&lt;a href=&quot;/blog/2012/01/03/your-team-probably-doesnt-have-the-same-dvcs-requirements-as-linus/&quot;&gt;which necessarily involves always committing to master, and only incidentally has to do with using a CI server&lt;/a&gt;) . Feature branches, infrequent commits, and committing non-production-ready work are all practices that need to be avoided, because they are all time-consuming delaying mechanisms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“Done” == “In Production”.&lt;/strong&gt; If the team moves on to new features before the last one is in production, then that last feature is obviously unnecessarily being held back from release. They will be faster if they deliver to production and ensure it functions there properly before moving on to new features because it avoids unnecessary and time-consuming multi-tasking. This goes hand-in-hand with smaller, more frequent releases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehensive Automated testing.&lt;/strong&gt; When you deploy more often, you need to test more often. The cheapest way to do this is with comprehensive automated tests. While they’re a heavy-upfront cost, if you run them as often as possible, they’ll pay for themselves very shortly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Production testing.&lt;/strong&gt; Create automated &lt;em&gt;black-box&lt;/em&gt; integration tests for some of your most important features and figure out a way to run them repeatedly and continuously against your production deployment so that you know instantly when those features are broken. There’s no need to wait for customer feedback to learn about a faulty release.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Searchable, aggregated logging with proper log-levels.&lt;/strong&gt; Making your logs easily searchable in one place makes them something that developers will actually use for defect detection and for debugging. They can go a long way to making your application more transparent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runtime monitoring, runtime metrics and information radiators (most importantly alerts).&lt;/strong&gt; Instrument the things you care about most, and have alerts sent out when the measurements are abnormal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Of course some preventative processes are necessary, but when they are, automation is almost always preferable to time-consuming manual human processes.  Either way, you should consider the cost of the process and determine if it the fall-out from the type of defect it prevents is actually worth that cost.&lt;/p&gt;
&lt;p&gt;In the end, a fear of releasing is a fear of change, and a fear of change is a fear of improvement. This is a crucial lesson that Big Company software teams can learn from the small, scrappy start-ups that are quickly trying to disrupt them. The more often you release, the more often you can test hypotheses and get customer feedback, and the more often you can course-correct. Companies that don’t realize this are susceptible to being leap-frogged by competitors that do.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Your Team Probably Doesn&#39;t have the Same DVCS Requirements as Linus</title>
		<link href="/posts/2014-06-03-your-team-probably-doesnt-have-the-same-dvcs-requirements-as-linus/"/>
		<updated>2012-01-03T14:43:58Z</updated>
		<id>/posts/2014-06-03-your-team-probably-doesnt-have-the-same-dvcs-requirements-as-linus/</id>
		<content type="html">&lt;p&gt;Version control branches come with costs. I’m at the point now that I don’t think it’s possible to get away without spending a couple of days every month managing issues with version control and merging if you’re using feature branches liberally as is common with DVCS (like git) users. I’ve spent days myself in the past months, so I felt compelled to write this because those were days I could’ve been actually doing something that adds value instead.&lt;/p&gt;
&lt;p&gt;The purpose of branching is to delay integration of some code into the main code line (for various reasons). There’s a heavy cost that comes from this in that the less often you merge, the harder it is to merge. I’m blown away by the effectiveness of automatic conflict resolution in git, but the bottom line is that if two developers are working in the same area of the codebase, &lt;a href=&quot;http://martinfowler.com/bliki/SemanticConflict.html&quot;&gt;semantic conflicts&lt;/a&gt; will emerge that need the intervention of a human to resolve. These can be complicated and tedious and involve multiple developers. Yes, branching is easier with DVCS, but this actually exacerbates a fundamental merging problem that DVCS doesn’t solve.&lt;/p&gt;
&lt;h1&gt;“What if I keep my branches short-lived?”&lt;/h1&gt;
&lt;p&gt;There are some &lt;a href=&quot;http://dev-spout.blogspot.com/2011/07/feature-branches-are-not-evil-in-fact.html&quot;&gt;better defenses for branching&lt;/a&gt;, like “What if I keep my branches very short-lived?”, and while it does mitigate most of the problems with merging, it also mitigates any advantage you think you might get from branching. If you’re only going to branch for a day, what’s the point?&lt;/p&gt;
&lt;h1&gt;“Then how can I pick and choose what gets added/released?”&lt;/h1&gt;
&lt;p&gt;Merging early and often leads to simpler merges, but what about the case when you get partway through a feature and want to scrap it because you’ve come up with a better way? There are a number of ways to mitigate this problem, but if your need to “unmerge” occurs more often than your need to merge, you’ve probably got larger organizational issues to deal with. If those issues are purely technical, try more prototyping to uncover those issues earlier, and &lt;a href=&quot;http://www.rallydev.com/engblog/2011/12/20/feature-toggles-branching-in-code/&quot;&gt;feature-toggles&lt;/a&gt; for better control over what gets released. If those organizational issues are non-technical, like frequent changing requirements mid-feature-development then you simply need to get better (and probably smaller) &lt;a href=&quot;http://www.agilemodeling.com/artifacts/userStory.htm#Introduction&quot;&gt;user stories&lt;/a&gt; before commencing.&lt;/p&gt;
&lt;h1&gt;“What if I do daily merges from the mainline into my feature branch?”&lt;/h1&gt;
&lt;p&gt;You’d think it shouldn’t matter which way you merge if you merge often, but that’s only fine if you’re the only one branching. As soon as someone else on the team comes along and starts up their own feature branch and follows your same best practice, the two of you are diverging from each other and creating merge-debt.&lt;/p&gt;
&lt;h1&gt;Using a continuous integration server is NOT sufficient for actually practicing continuous integration.&lt;/h1&gt;
&lt;p&gt;I’ve heard of some teams using a bot to auto-add all branches to the team’s CI server, making sure that each branch gets put through the proper rigor of the CI server. This is actually cargo-cult continuous integration though because those teams are not actually continually integrating at all. Merging early and often is a prerequisite of continuous integration, by definition. Instead, running multiple branches in CI supports maintaining those multiple distinct branches for even longer, so you’re actually using the CI server to undermine the ideals of CI.  Even if you run a special build that tries to auto-merge all branches (yeah right!), but is not the mainline and is not intended for release, you lose the ability to regularly deliver work to some staging environment for manual regression testing.&lt;/p&gt;
&lt;h1&gt;A small non-distributed team doesn’t have the same problems as Linus&lt;/h1&gt;
&lt;p&gt;If your team is in the same room and practices &lt;a href=&quot;http://c2.com/cgi/wiki?CollectiveCodeOwnership&quot;&gt;collective code ownership&lt;/a&gt; (instead of having a central maintainer) you should just do in-person peer code reviews (or better yet, pair programming) instead of relying on pull requests. It’s wasteful to force every aspect of intra-team communication to go through the computers in the room. I would even go so far as to say that if you’re in the same room, you don’t actually need a DVCS.&lt;/p&gt;
&lt;p&gt;Most of the reasons behind feature branches seem to be a cure that’s worse than the disease itself. It’s vastly simpler for us to commit to the mainline at all times, early and often, and deal with deactivating or removing particular pieces of code in other ways (like feature-toggles) as those problems arise (which does not in my experience tend to be very often compared to how often I am merging new stuff in that stays in).&lt;/p&gt;
&lt;p&gt;I don’t mean to be negative about DVCS either. I actually use git exclusively now, I think github has been a huge boon to open source, and I love anything that makes Linus more effective at maintaining my favourite OS kernel. It just really seems like feature-branches have never solved any real problem that I have, while they have caused a lot of pain.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Agile: The Good Parts</title>
		<link href="/posts/2014-06-03-yoagile-the-good-parts/"/>
		<updated>2011-09-14T14:51:37Z</updated>
		<id>/posts/2014-06-03-yoagile-the-good-parts/</id>
		<content type="html">&lt;p&gt;Let’s just forget about story points, pigs, chickens, daily stand-ups, burndown charts, sprints and scrummasters for a second.  In my experience all of that weird jargon is really hurting Agile’s adoption among the no-nonsense type of developer that doesn’t have time for fluff and wants to know the real benefits of something before investing time in learning about it (instead of a million other things they could be learning).&lt;/p&gt;
&lt;p&gt;I’ve also seen that when anyone happens to cite a failed experience with Agile, the explanation from Agilists is invariably the cryptic “you weren’t doing it right”. This is a bit of an irritating response to anyone that’s spent a significant amount of time following the ceremonies and speaking the lingo though.  Instead I’d like to submit that you have a much better chance of succeeding with Agile if you know the real reasons behind the madness.&lt;/p&gt;
&lt;p&gt;There are a number of Agile values I’ve noticed in my years of practicing scrum and XP that I think stand on their own even if you’re not doing Agile and just want to improve your development process in some small way.  I’m going to list them (and try to stay jargon-free) because I imagine that they would be useful individually, but they do have a sort of self-reinforcing quality to them where their effects will somehow be amplified if you use them together.  You should also feel free to break the rules where you feel they need to be broken, but I’ve very rarely found that to be necessary.  Usually when I’ve broken these rules, I’ve regretted it later, because what I thought was an exception didn’t really end up being an exception.&lt;/p&gt;
&lt;h1&gt;Create a team, not just a group of individuals.&lt;/h1&gt;
&lt;p&gt;A project will move faster when it is being developed by a team that self-organizes around its goals rather than a group of individuals working separately.  Here are few rules of thumb to creating a team instead of just having a group of individuals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Don’t assign tasks to individuals.  Let the team figure out who works on what, and let the team take responsibility for all tasks rather than individuals.   Everyone on the team needs to agree on what it means to be done and how, and everyone on the team needs to take responsibility for it.&lt;/li&gt;
&lt;li&gt;Strive for cross-functional skillsets.   Let the team members teach each other so they can better help each other in the future rather than allowing one person to become the bottleneck for any particular kind of task.&lt;/li&gt;
&lt;li&gt;Try not to change team size or membership very much.  A good team can be a fragile thing.&lt;/li&gt;
&lt;li&gt;Throw out the notion of individual code ownership. The entire team owns the code.&lt;/li&gt;
&lt;li&gt;Create more of a bullpen environment where the team members are all basically in the line of sight of one another and can just talk to one another about what they’re working on.  This was tough, because it made us give up our individual offices, telecommuting, and deciding our own hours, but it was well worth it for the improvement to the quality of our work day.  Almost anytime a developer has to use some means of communication other than his voice to talk with a teammate, you have unnecessarily wasted time.&lt;/li&gt;
&lt;li&gt;Put QA personnel on the team so that testing can be can be on-going and so the team can more easily take on QA and testing as a team-wide responsibility.&lt;/li&gt;
&lt;li&gt;The whole team needs to agree on what kind of work is necessary for each task before it is to be considered “done”.  (coding standards, documentation standards, how rigorously they test, etc, etc)&lt;/li&gt;
&lt;li&gt;The result of this was a highly capable team that could “swarm” to complete goals reliably and quickly.  We actually developed a sort of sports team mentality that made this way of working genuinely fun, and helped us push ourselves to be better all the time.  There are a lot of challenges to creating a great team that can inter-communicate openly and honestly, but it’s an amazing thing to behold when it happens.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Estimates need to come from developers.&lt;/h1&gt;
&lt;p&gt;This is can be very hard for some organizations to swallow, but developers are the ones that are most qualified to do estimations, and as professionals, they should be working diligently to improve their estimation capability.  When a developer is responsible for estimation, that developer feels a sense of ownership about his work and will feel a vastly greater sense of responsibility to meet the estimate.  Developers that have never learned how to estimate will not be good at it at first, but there’s no other way for them to get good at it than to have them do it.  There are a few major things that can vastly help estimation too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Always break work down into tiny chunks.  We generally broke work up into chunks that were less than 3 days of effort.  I’ve never seen a task that couldn’t be broken down into subtasks that are this small or smaller, if the developers are so inclined.&lt;/li&gt;
&lt;li&gt;The team should take a look at bad estimates in retrospect and figure out where they went wrong.
Recognize work that will be impossible to do due to lack of clarity from the business, or unmet dependencies and push to have those requirements met.&lt;/li&gt;
&lt;li&gt;For highly speculative work, just commit to doing a proof-of-concept, or time-boxed research.&lt;/li&gt;
&lt;li&gt;The more developers that are involved in the estimation process, the better.  You’ll probably want to include QA/testers as well, because good ones have unique insights.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Context-switching should be avoided &lt;em&gt;mercilessly&lt;/em&gt;.&lt;/h1&gt;
&lt;p&gt;This means that each developer needs the discipline to make sure he only works on one task at a time, that the team works on as few tasks at one time, and that developers need sustained uninterruptable timeboxes where the priority of work is not allowed to change.&lt;/p&gt;
&lt;p&gt;Most people (especially non-developers) have no idea how much of a huge time-suck that context switching is, and few realize how seldom it’s actually worthwhile.  Also if the team is tackling as few tasks as possible at once, if any task can be finished by having more developers on it at once, then that’s what the team should do rather than starting as many tasks as possible and working on them in parallel.  This might sound counter intuitive, but with the team ultra-focussed on as few tasks as possible at once, they can get the totality completed faster.&lt;/p&gt;
&lt;h1&gt;Try to always improve.&lt;/h1&gt;
&lt;p&gt;The team must commit to continually improving. At regular intervals, the team should look at how things are going and pick a few actionable things to make their work better/faster/easier.  You’d be surprised at the huge speed improvements that can come from this practice over time.  If the team has a shared calendar, set up a reoccurring meeting at a regular interval to have this meeting, and be laser-focussed on deciding what improvement you want to achieve and how exactly you’ll try to achieve that.  We’ve always set aside 1 hour per week, but your mileage may vary.  Start every meeting by evaluating how successful the team was with the previous meeting’s goals.&lt;/p&gt;
&lt;h1&gt;If something is difficult or time-consuming, do it more often.&lt;/h1&gt;
&lt;p&gt;This sounds crazy to the uninitiated but there are two reasons for this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Doing difficult things more often will drive out new creativity in making them less difficult.  Pro-tip: Automation is almost always the answer when the problem is testing (See &lt;a href=&quot;http://www.agiledata.org/essays/tdd.html&quot;&gt;TDD&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Behavior_Driven_Development&quot;&gt;BDD&lt;/a&gt;, &lt;a href=&quot;http://testobsessed.com/2008/12/08/acceptance-test-driven-development-atdd-an-overview/&quot;&gt;ATDD&lt;/a&gt;) or deployment.  (See &lt;a href=&quot;http://continuousdelivery.com/&quot;&gt;Continuous Delivery&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Many types of tasks get more difficult the longer they are postponed and so are always easier if you do them more often instead of letting the risk of complexity pile up.  Integrating code into the main branch is one example  (See &lt;a href=&quot;http://martinfowler.com/articles/continuousIntegration.html&quot;&gt;Continuous Integration&lt;/a&gt;).  Deploying is another (See &lt;a href=&quot;http://continuousdelivery.com/&quot;&gt;Continuous Delivery&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Be merciless about achieving high quality&lt;/h1&gt;
&lt;p&gt;Over the long haul, &lt;a href=&quot;/blog/2010/12/05/quality-is-the-constraint/&quot;&gt;speed comes from quality&lt;/a&gt;, so everyone on the team needs to make quality their job.  Everyone needs to test, and everyone needs to think about how to continually make testing easier without cutting corners.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have QA personnel on every team, and have them testing as the team works.&lt;/li&gt;
&lt;li&gt;The whole team needs to agree on what level of quality is needed, and what quality metrics will be used to judge every check-in.&lt;/li&gt;
&lt;li&gt;Perform a root-cause-analysis on each defect.  Try to figure out how to avoid that class of defect in the future.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Do everything in tiny increments.&lt;/h1&gt;
&lt;p&gt;Tiny increments reduce the risk of compounding problems, and allow you to get feedback and correct your course more often.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;break-down your work into tiny tasks&lt;/li&gt;
&lt;li&gt;plan just-in-time and just enough to do work.&lt;/li&gt;
&lt;li&gt;test as you go, instead of in huge batches&lt;/li&gt;
&lt;li&gt;merge code to the mainline early and often.&lt;/li&gt;
&lt;li&gt;deploy early and often.&lt;/li&gt;
&lt;li&gt;don’t add anything to the system that you don’t need until you need it (&lt;a href=&quot;http://c2.com/xp/YouArentGonnaNeedIt.html&quot;&gt;YAGNI&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Get customer feedback early and often&lt;/h1&gt;
&lt;p&gt;Get customer feedback early and often to converge on the best possible solution as fast as possible by constantly correcting course instead of blindly following some long-running plan or doing unnecessary work.  The customer’s priorities and vision of the product will change as he sees results, so it’s better to not find out about these changes after a lot of unnecessary work has been done.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do work in priority order as dictated by the customer.  This will allow them to see the aspects that they care about most as early as possible, and therefore help you converge on a unified vision of the product faster.&lt;/li&gt;
&lt;li&gt;Work break-down is better done in vertical slices where the customer can get some amount of real value from each piece (or at least see some evidence of work) rather than having many non-user-facing tasks, where possible.  This allows for more potential for feedback.&lt;/li&gt;
&lt;li&gt;The work shouldn’t be considered done by anyone on the team until the customer, or a representative of the customer agrees that it’s done.&lt;/li&gt;
&lt;li&gt;Constantly improve estimation skills so that they are generally more reliable so the customer knows the cost of the work he has requested and can make realistic decisions based on that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyway, feel free to try what you want and throw out the rest!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Quality is the Constraint</title>
		<link href="/posts/2014-06-03-quality-is-the-constraint/"/>
		<updated>2010-12-05T22:33:50Z</updated>
		<id>/posts/2014-06-03-quality-is-the-constraint/</id>
		<content type="html">&lt;p&gt;One fine day in the trenches, a junior engineer was tasked with optimizing a particular web service call that was way too slow (sometimes slower than 20 seconds!).  I had just figured out how to use a performance profiler for that particular platform, so I thought I’d offer to show him how to use it.  His response was that he was on a tight deadline and didn’t have time to learn to use the profiler, and that he was just going to tune the database calls to make them perform better.&lt;/p&gt;
&lt;p&gt;Later in the year when the problem still wasn’t solved, I had a chance to take it on myself.  The profiler showed me that this service call was itself making around 20 web service calls to a second system that could obviously add up to 20 seconds, if that other web service took 1 second for each of its responses (and the logs showed that sometimes it did).  It turned out that almost all of those web service calls were redundant and completely unnecessary.  Simply removing them (which took about 1 day of effort) shaved 19 seconds off this web service call’s duration in production in some cases.&lt;/p&gt;
&lt;p&gt;The total execution time spent on database calls was 5 milliseconds.  A 50% improvement there would probably take a week’s worth of effort, and really only get you 2 or 3 milliseconds of performance improvement.&lt;/p&gt;
&lt;p&gt;The moral of the story is that there’s a pretty simple process for optimizing a system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identify and isolate the component that is tying up the most time in the system  (let’s call it the bottleneck)&lt;/li&gt;
&lt;li&gt;Optimize that component to make it less wasteful&lt;/li&gt;
&lt;li&gt;Repeat&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Skipping step 1 isn’t a shortcut.  It’s absolutely critical to know that you’re optimizing the bottleneck, and not some other random component.&lt;/p&gt;
&lt;p&gt;This is pretty obvious stuff for most experienced developers of course.  And while they seem to know to apply this to the systems that they work on, it’s more rare that they notice it outside of the code and see it in the process of software engineering in general.&lt;/p&gt;
&lt;p&gt;The software development &lt;em&gt;process&lt;/em&gt; is a system as well, made up of components.  Requirements come in at one end, and deliverables go out the other end.  As people who are involved in that process, we naturally want it to be more and more efficient.  We are constantly trying to figure out how to optimize that system so we can deliver better software in less time.&lt;/p&gt;
&lt;p&gt;So step 1:  Identify and isolate the component that is tying up the most time in the system.&lt;/p&gt;
&lt;p&gt;Not every team develops software the same way, so this component of the process could be different team by team.  In practice though, I’ve always seen teams spending the most time doing these sorts of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Refactoring poorly written code so that features can be added&lt;/li&gt;
&lt;li&gt;Learning/relearning existing code that has long since swapped out of all developers’ “mind pages” (for extension or bug-squashing).&lt;/li&gt;
&lt;li&gt;Debugging&lt;/li&gt;
&lt;li&gt;Performing Manual User Acceptance Testing (by both developers and testers)&lt;/li&gt;
&lt;li&gt;issue tracking (administration of that tool and issue in it)&lt;/li&gt;
&lt;li&gt;discovery and documentation of steps to reproduce&lt;/li&gt;
&lt;li&gt;triage (what bugs to squash first?)&lt;/li&gt;
&lt;li&gt;communication between customers, support, QA and developers&lt;/li&gt;
&lt;li&gt;customer support&lt;/li&gt;
&lt;li&gt;customer dissatisfaction leading to churn and reputation problems (affecting the entire organization)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these time consumers are affected directly or indirectly by our ability to control quality.  In my experience, the majority of the software development process isn’t hung up in requirements analyis, design, or implementation.  It’s hung up in all these Quality Control related issues.  Quality Control is the constraint that keeps us from creating the right software faster.  Steve McConnell confirms it in a more scientific way than I ever could:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The rest of us would do well to learn from a discovery made by IBM in the 1970s: Products with the lowest defect counts also have the shortest schedules (Jones 1991). Many organizations currently develop software with defect levels that give them longer schedules than necessary. After surveying about 4000 software projects, Capers Jones reported that poor quality was one of the most common reasons for schedule overruns (1994). He also reported that poor quality is implicated in close to half of all canceled projects. A Software Engineering Institute survey found that more than 60 percent of organizations assessed suffered from inadequate quality assurance (Kitson and Masters 1993). On the curve in Figure 1, those organizations are to the left of the 95-percent-removal line.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(&lt;a href=&quot;http://www.stevemcconnell.com/articles/art04.htm&quot;&gt;http://www.stevemcconnell.com/articles/art04.htm&lt;/a&gt; — The whole article is extremely illuminating)&lt;/p&gt;
&lt;p&gt;What this means is that if we really want to move quickly, we need to take a good hard look at how we manage quality.  Of course this is counter-intuitive, and its actually hard to swallow, because ensuring quality can be mundane and tedious if you’re not doing it right.  But as developers we’d be silly to ignore the real bottleneck in the process, and optimizing for that.  Micro-optimizations elsewhere in the process will yield very little benefit compared to improving measures that ensure quality.&lt;/p&gt;
&lt;p&gt;As developers, we love to argue about and discuss these micro-optimizations all day long:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Editor_war&quot;&gt;what text editor you use&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://steve-yegge.blogspot.com/2008/09/programmings-dirtiest-little-secret.html&quot;&gt;how important input speed is&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://stackoverflow.com/questions/136056/ide-or-text-editor&quot;&gt;IDEs vs. editors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It sure seems silly though to be pursuing micro-optimizations, at the expense of tackling the real #1 time-suck:  Quality.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Lost Art of Prototyping</title>
		<link href="/posts/2014-06-03-the-lost-art-of-prototyping/"/>
		<updated>2009-12-27T00:19:01Z</updated>
		<id>/posts/2014-06-03-the-lost-art-of-prototyping/</id>
		<content type="html">&lt;p&gt;Prototyping is a &lt;strong&gt;design&lt;/strong&gt; methodology that basically involves “trying stuff out and seeing what works”. It’s meant to be iterative in that you continue to create prototypes (possibly by alterring previous prototypes) until you’ve got all the information you need to say your design is complete.&lt;/p&gt;
&lt;p&gt;If we were building cars, we would probably first prototype a body design with CGI to be able to collect feedback before building the car itself. It’s much cheaper (effort and materials wise) to iteratively develop the body with a 3d model than with the actual materials that would be used.&lt;/p&gt;
&lt;p&gt;If we were designing websites, we might prototype the design in photoshop for a bunch of iterations until the client is happy. The great thing about that is that the web designer can actually chop up that protoype in photoshop, and use it for images as part of the work after the client has approved the design stage. In this case, the prototype isn’t a throw-away prototype — it’s actually useful to bring into the implementation stage.&lt;/p&gt;
&lt;p&gt;In software development we can (and usually do) prototype similarly. There’s usually a point in the design process where a developer needs to “try some stuff out and see what works”. Once the developer has proven a methodology with code, the prototyping phase can mostly be called complete. Throwing away that code would widely be considered a huge waste though, so it usually ends up being used in the final implementation as well.&lt;/p&gt;
&lt;h1&gt;Prototyping VS. Hacking&lt;/h1&gt;
&lt;p&gt;It’s probably safe to say that many developers do prototyping (a design methodology) and implementation &lt;strong&gt;at the same&lt;/strong&gt; time bouncing back and forth between the two as necessary, blurring that line between design and implementation.&lt;/p&gt;
&lt;p&gt;This way of developing is seductive, because you get straight to banging on the keyboard, which feels like you’re making progress, but it’s really upstream in the design stage where you get the opportunity to save the most amount of time. If you don’t distinguish between design and implementation, it’s tough to tell which stage you’re in at any given time, and so it’s tough to determine if you’re in &lt;strong&gt;the right stage&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You can imagine how wasteful this back-and-forth would be if you were an automative engineer instead, and you swapped back and forth between prototyping and working on the implementation details. As you iterate on the prototype, those details you worked on in the last iteration could be completely removed — that’s a big waste of time, and it’s often emotionally difficult to let go of design decisions that have undergone a lot of implementation work. So while realistically design never really stops, you do want to do as much up front as possible.&lt;/p&gt;
&lt;p&gt;So there are definitely right and wrong ways to prototype, but it’s extremely valuable and worthwhile if done correctly. I doubt many developers would argue that sometimes you just need to try stuff out and see what works. Very few developers are interested in development methodologies that omit the ability to prototype.&lt;/p&gt;
&lt;h1&gt;So What about TDD?&lt;/h1&gt;
&lt;p&gt;This seems to me to be the most often used argument against Test Driven Development (TDD). I agree that TDD doesn’t work well for tasks that don’t have clear-cut solutions, but TDD is still always applicable downstream after the solution has become more clear. The trick is to reach a certain level of solidity with your solution’s plan &lt;em&gt;before&lt;/em&gt; you get into TDD.&lt;/p&gt;
&lt;p&gt;Here’s a case in point as &lt;a href=&quot;http://xprogramming.com/xpmag/oksudoku/&quot;&gt;Ron Jeffries attempts to “solve sudoku” with TDD without even knowing the rules of the game&lt;/a&gt;. If you follow his method of solving the problem and compare it against &lt;a href=&quot;http://norvig.com/sudoku.html&quot;&gt;Peter Norvig’s design-first approach&lt;/a&gt;, TDD starts to look like a miserable failure. Indeed, some have dragged this out as a case against the utility of TDD “in the real world”.  Ron Jeffries’ example doesn’t really make the case against TDD at all though; It simply shows that you have no business being in the TDD stage before you fully understand the problem and you’ve done adequate design. TDD doesn’t preclude other design methods (like prototyping) at all.&lt;/p&gt;
&lt;p&gt;And in cases of large architectural issues, prototyping is likely not the first tool that you should turn to — it’s too detail oriented, and you can iterate much faster on designs expressed via whiteboard doodling, flowcharts, UML, etc. You might move to prototyping at some stage later though before you completely decide on some particular design. The important part to keep in mind though is that you’re &lt;strong&gt;not&lt;/strong&gt; in the implementation stage — you’re planning.  Changes are cheap and easy at this stage, and it saves you so much more time than if you just jumped in and started developing.&lt;/p&gt;
&lt;p&gt;The software that comes out of the prototyping process is a nice side effect, but it’s almost never ready for production. This is where TDD comes in. If you have a clear understanding of the solution you want to implement (whether you used prototyping or not) then your design is sufficiently complete to &lt;strong&gt;start&lt;/strong&gt; TDD. In this way TDD and prototyping are not opposed at all. Prototyping is just one possible methodology in the design stage that should precede implementation. TDD just says that tests should be written before implementation. It doesn’t say anything about what else you do prior to implementation.&lt;/p&gt;
&lt;p&gt;So, there’s nothing un-TDD about prototyping a solution, setting it aside, writing your tests, then writing an implementation that passes those tests (based on the knowledge you got from your prototype). Ideally you’re working with units that are single-minded and small so copying/pasting from the prototype isn’t even necessary, but to be honest, I think some copy/paste from the prototype is fine. If it’s done in a careful way where you’re not hurting the quality of the final code (because prototypes generally don’t care all that much about code quality), you might as well make use of your previous work, if you can. You just have to be careful that it’s the quality you want, but then again TDD will force a lot of the quality.&lt;/p&gt;
&lt;h1&gt;The Steel Thread&lt;/h1&gt;
&lt;p&gt;The concept of &lt;a href=&quot;http://en.wikipedia.org/wiki/Steel_thread&quot;&gt;the steel thread&lt;/a&gt; is one that I use quite often on the team that I work in when we’re working on complex tasks. It’s definitely a loose sort of prototype, and it’s meant to prove the basics of our core concepts. Basically, we concentrate on the core functionality of the complex task, putting priority on the completion of the “&lt;a href=&quot;http://en.wikipedia.org/wiki/Happy_path&quot;&gt;happy path&lt;/a&gt;“, the path of execution without error scenarios, special cases, etc. Once that core functionality is in place, the general design can be considered verified, the necessary components can be easily identified, and the existing work can be evolved to something high-quality (possibly through a fresh start with TDD). Work is easily divided amoung teammates after this steal thread has been acheived.&lt;/p&gt;
&lt;h1&gt;Spike Solutions&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://www.extremeprogramming.org/rules/spike.html&quot;&gt;Spike Solutions&lt;/a&gt; are like the opposite of the steel thread in many ways. Where the steal thread tries to prove the viability of the entire solution (in a breadth-first sort-of-way), a spike solution will try to prove the viability of a part of the solution that isn’t very well known, in a depth first sort-of-way. It’s useful when there’s a particular piece of the solution that we’re not sure will work, so we prototype that part as quickly as possible to make sure our overall solution won’t fail because of that single part.&lt;/p&gt;
&lt;p&gt;The point of the concepts of steel threads and spikes is to tackle the unknowns early on and prove the viability of the entire solution as early as possible. Once everyone is relatively sure that the team is on the right path and the design is firmed up, you’re ready to get into the more detail-oriented aspects of development.   It’s not until this point that I’d switch to TDD, and start writing my tests for the implementation stage of the work.&lt;/p&gt;
&lt;h1&gt;Is this just &lt;a href=&quot;http://c2.com/xp/BigDesignUpFront.html&quot;&gt;BDUF&lt;/a&gt;?&lt;/h1&gt;
&lt;p&gt;I don’t think so.   I’m not proposing a huge documentation process that specifies every aspect of the final product.  I’m simply talking about spending some time to loosely figure out what we’re going to do before we do it.    It’s time well spent, because it’s just so much cheaper to make major changes at this earlier stage in the process.  We’ll still figure out the minor details as we go.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Future-Proofing Trap</title>
		<link href="/posts/2014-06-03-the-future-proofing-trap/"/>
		<updated>2009-12-21T00:27:28Z</updated>
		<id>/posts/2014-06-03-the-future-proofing-trap/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;“We will encourage you to develop the three great virtues of a programmer: laziness, impatience, and hubris.” — &lt;a href=&quot;http://en.wikipedia.org/wiki/Larry_Wall&quot;&gt;Larry Wall&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this quote Larry Wall makes some great points about what it means to be a great programmer in a zen-like,  toungue-in-cheek sort-of-way.  Let’s look at one aspect of the Virtue of Laziness.&lt;/p&gt;
&lt;p&gt;Every reasonable developer knows that he should write his code to be easily maintained.  As part of that work, it’s natural for that developer to want to try to make his code as ready for future change as possible.  Taking that desire a few steps further, he might want to write code that solves future needs in addition to the current requirements, so that that code doesn’t even need to be revisited.  Unfortunately, that’s a common mistake that leads to a lot of wasted time and &lt;strong&gt;less&lt;/strong&gt; maintainable code.&lt;/p&gt;
&lt;p&gt;I’d like to propose a principle of software development that I’ve come to believe:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The most maintainable code is the simplest possible code that meets all the requirements.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is almost a tautology because simple code is (by definition) easier to understand, so it’s easier to change/enhance/extend.  Code that does more than what’s currently necessary is not as simple as it could be though, so it’s not as maintainable given the current requirements.&lt;/p&gt;
&lt;p&gt;One might argue that code that does more than what’s necessary can meet future requirements without change, thereby proving itself to be more easily maintained (no maintenance required!), but all of that hinges upon the developer’s ability to consistently and accurately foresee future requirements.  Otherwise that developer has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;wasted time developing unnecessary functionality&lt;/li&gt;
&lt;li&gt;decreased the maintainability of the codebase&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Even when everybody is pretty certain of the future requirements…&lt;/h1&gt;
&lt;p&gt;Now let’s consider the case where the developer is almost absolutely sure that the requirements will change a certain way, and so the code should be written to handle that scenario as well.  Wouldn’t it be better to do that work now?  No.  It still takes more time and effort (at a time when we know its not necessary), and it’s still less maintainable code until those requirements change (in case other unrelated changes are required).  On top of all that, there’s &lt;em&gt;still&lt;/em&gt; risk that the requirements won’t change in the anticipated way!&lt;/p&gt;
&lt;h1&gt;Even when everyone is absolutely 100% certain of the future requirements…&lt;/h1&gt;
&lt;p&gt;Now let’s consider the case where everyone is 100% certain that the requirements will change in a specific way, and you can write your code to handle that way as well as the current way.  In that infrequent scenario, you don’t face a bunch of losing propositions, so it does make a bit more sense.  However, I’d still like to pose a question:  how much more work is it to do the additional work later instead of now?  Truthfully, the amount of effort is virtually identical regardless of whether you do it now or later.  That means you can enjoy maintaining the simpler version until the time comes that it needs to be changed to meet new requirements.&lt;/p&gt;
&lt;p&gt;This isn’t a new idea I’ve dreamt up: it’s the &lt;a href=&quot;ttp://c2.com/cgi/wiki?YouArentGonnaNeedIt&quot;&gt;YAGNI&lt;/a&gt; principle, and it’s an essential part of &lt;a href=&quot;http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd&quot;&gt;Uncle Bob’s 3 Rules of TDD&lt;/a&gt;.  It’s also a great way to avoid unnecessarily complex code.&lt;/p&gt;
&lt;p&gt;(It’s important to note too that YAGNI doesn’t say to avoid making your work as futureproof as possble.  YAGNI just says not to put extra code into making that possible.  For example, if you create a class for a UI button that will be used to save some user data in a form, don’t call it “UserDataSaveButton” — just call it “Button”.  It’s no extra work and the re-usability possibilities have increased dramatically.)&lt;/p&gt;
&lt;p&gt;We’re not engineers building bridges;  we don’t work with unchangeable steel and concrete, and we can accomodate changing requirements easily.  It’s unrealistic and wasteful to guess that we know what future requirements will come, especially when the potential work saved in the long run is neglible.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Code Slower</title>
		<link href="/posts/2014-06-03-code-slower/"/>
		<updated>2009-12-14T00:32:30Z</updated>
		<id>/posts/2014-06-03-code-slower/</id>
		<content type="html">&lt;p&gt;Here’s a controversial opinion, but one that I really believe to be true: most of the things we do to produce code faster are actually counter-productive.  It sounds crazy, and I would naturally oppose it except that every time I ignore this lesson, experience has a way of reteaching me.  This is as much a message to myself as it is to anyone else that might happen upon it (I’m talking to you, viagra comment spammers).&lt;/p&gt;
&lt;h1&gt;Development Time VS. Maintenance Time&lt;/h1&gt;
&lt;p&gt;There’s no doubt that the original development stage of a piece of software can be time-consuming.  It’s interesting though, when you consider the difference in time spent in development vs. time spent in maintenance.  At what point do you cross into maintenance mode?&lt;/p&gt;
&lt;p&gt;Let’s face it: you’re actually also in maintenance mode pretty much right away, unless you’re some superhuman that conceives of the whole system at once and doesn’t make any design tweaks (or even typos) while coding.  But you’re not.  So the development-time VS. maintenance-time dichotomy is a false one.  You’re always in maintenance mode.&lt;/p&gt;
&lt;h1&gt;Invest Early, Invest Often&lt;/h1&gt;
&lt;p&gt;So if you spend so much time (all your time) in maintenance mode, then it makes sense to do every little change and tweak in such a way that your subsequent tweaks and changes are as easy as possible.  We should be spending the majority of our energy optimizing our time spent on maintenance and not our time spent on development.&lt;/p&gt;
&lt;p&gt;Now it’s natural that one might say “well why not optimize both?”, and that’s a valid question.  There’s no good reason not to try to optimize both, but we have to remember to never ever ever optimize the development process at the expense of the maintenance process, simply because we just spend &lt;strong&gt;so&lt;/strong&gt; much time in maintenance mode.&lt;/p&gt;
&lt;h1&gt;Some examples&lt;/h1&gt;
&lt;h2&gt;Skipping the planning stage.&lt;/h2&gt;
&lt;p&gt;This is generally caused by the “Weeks of coding can save days of planning” fallacy.  Uncover all the main parts of your design &lt;strong&gt;before&lt;/strong&gt; you code yourself into a corner that requires a near-rewrite to escape.&lt;/p&gt;
&lt;h2&gt;Writing untestable code or skipping unit-testing&lt;/h2&gt;
&lt;p&gt;Unit-tests are your insurance that future changes don’t cause non-obvious regressions.  They also have a magical way of creating better factored, higher-quality code.  If you skip this stage, your code &lt;strong&gt;will not&lt;/strong&gt; be factored as well as it could be, and come maintenance time, you’ll be scared to make changes for fear of breaking something somewhere else.&lt;/p&gt;
&lt;h2&gt;Writing classes and functions that do a lot&lt;/h2&gt;
&lt;p&gt;This one is a really seductive one.  We want to be &lt;strong&gt;consumers&lt;/strong&gt; of classes and methods that do a lot for us, because higher levels of abstraction are how we get more done in less time.  From the consumer stand-point, this makes lots of sense, and it’s actually the best way to improve development speed and maintenance speed at the same time.  If you’re also the person writing the class or function that does more though, you have to be very careful to use the highest abstractions possible for that as well, even if you’re writing its inner abstractions as well.  What this means is that every level of abstraction does as little as possible, and you build up to the level of abstraction that you want with those thin, thin layers.  Classes and functions that try to do a lot instead of relying on other classes and functions are very hard to maintain, simply because there’s so much to do read and understand, and there’s no easy way for the maintainer to skim and decide what piece is relevant, because the pieces are doing multiple things.&lt;/p&gt;
&lt;h2&gt;Leaving code in a low-quality state&lt;/h2&gt;
&lt;p&gt;I’m talking about everything involving non-readable and poorly factored code, including bad names, foggy separation of concerns, etc.  Code should not be written just for the machine.  It needs to be written for the next guy that comes along as well.  That next guy could be you.  Or a &lt;a href=&quot;http://wtfcode.net/post/193202062/always-code-as-if-the-guy-who-ends-up-maintaining&quot;&gt;violent psychopath&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Using code generation&lt;/h2&gt;
&lt;p&gt;Code generation is just pure evil, if there’s ever a remote chance a human will ever have to read it or change it.  A computer program doesn’t know how to write code that a human will understand, and human understanding is exactly what we need to strive for if we care about making maintainable code.&lt;/p&gt;
&lt;h1&gt;Understatement of the day:  You’re more than just a typist&lt;/h1&gt;
&lt;p&gt;It’s largely irrelevant if you can touch type at 90 wpm.  It’s largely irrelevant if your IDE can do automated refactors.  It’s largely irrelevant if your efficiency with Emacs or vim makes you look like Neo in The Matrix.  These things are great bonuses, but won’t make much difference to your proficiency (and efficiency) as a programmer if you neglect to first consider the maintainability of your codebase.  (Corollary:  In the name of all that is good in this world, please don’t name your variables p1, atb, etc, or your functions like atoi() just for the sake of saving keystrokes!)&lt;/p&gt;
&lt;p&gt;Time and time again my mistakes remind me:  there’s only one way to be more productive over the long haul: work with better, higher abstractions.&lt;/p&gt;
</content>
	</entry>
</feed>