<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aleks Verein</title>
    <description>The latest articles on DEV Community by Aleks Verein (@tpom6oh).</description>
    <link>https://dev.to/tpom6oh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F448159%2F37b392fd-e1df-42d9-b720-db3817661572.jpeg</url>
      <title>DEV Community: Aleks Verein</title>
      <link>https://dev.to/tpom6oh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tpom6oh"/>
    <language>en</language>
    <item>
      <title>How we broke the code-review bottleneck with CodeSpeak - and the opportunity it opened</title>
      <dc:creator>Aleks Verein</dc:creator>
      <pubDate>Mon, 13 Jul 2026 10:27:18 +0000</pubDate>
      <link>https://dev.to/tpom6oh/how-we-broke-the-code-review-bottleneck-with-codespeak-and-the-opportunity-it-opened-lmj</link>
      <guid>https://dev.to/tpom6oh/how-we-broke-the-code-review-bottleneck-with-codespeak-and-the-opportunity-it-opened-lmj</guid>
      <description>&lt;p&gt;&lt;em&gt;For decades, understanding the code better than anyone was an engineer's most valuable skill. The models have that now - and that turns out to be good news. Here's how we moved human review from the diff to the spec, kept the deep dives for code that warrants them, and used what it freed up to take intellectual control of the whole system, not just the code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There is far more code in the world than there was two years ago, and a fast-growing share of it was never typed by a human. The models got good enough that most teams now let them write - and, increasingly, trust what comes back. Which surfaces a question the industry keeps circling and never quite says out loud: does all of that code still need a person to review it?&lt;/p&gt;

&lt;h2&gt;
  
  
  The question we keep not quite asking
&lt;/h2&gt;

&lt;p&gt;For now, the answer is yes - because the models still slip more often than a careful human does, especially at the volume they produce. There's simply so much code that checking it has become its own job.&lt;/p&gt;

&lt;p&gt;But that gap is closing from both sides. The models keep getting better, and an AI reviewer on every pull request catches more than a tired human ever did. We run one; it's real leverage, and if you ship with agents and you don't, you should. Code quality, the thing everyone is anxious about today, is the kind of problem that gets solved over time.&lt;/p&gt;

&lt;p&gt;So play it forward. Suppose it &lt;em&gt;is&lt;/em&gt; solved - the models stop making more mistakes than we do, the reviewers close the rest of the gap, and bugs stop being the thing that keeps you up at night. Is human review finished then? Is there anything left for an engineer to hold?&lt;/p&gt;

&lt;h2&gt;
  
  
  What's left isn't bugs. It's understanding.
&lt;/h2&gt;

&lt;p&gt;There is, and it was never really about bugs. It's understanding - knowing what the code does, why it's shaped the way it is, what breaks if you touch it. The name for that is &lt;a href="https://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html" rel="noopener noreferrer"&gt;intellectual control&lt;/a&gt;, the thing Dijkstra worried about back in 1972, when he reminded us a program still has to fit inside one head - "the strictly limited size of his own skull."&lt;/p&gt;

&lt;p&gt;For most of software's history, that was the most valuable thing an engineer had. Peter Naur put it sharply in 1985: the real product of programming isn't the text, it's a &lt;em&gt;theory&lt;/em&gt; of the system that lives in the programmers' minds - so much so that "the &lt;a href="https://www.baldurbjarnason.com/2022/theory-building/" rel="noopener noreferrer"&gt;death of a program&lt;/a&gt; happens when the programmer team possessing its theory is dissolved," even while the binary keeps running. The person who held that theory - who could trace any behavior to its cause without looking it up - was the one a company paid the most and feared losing. Intellectual control of the code &lt;em&gt;was&lt;/em&gt; the skill.&lt;/p&gt;

&lt;p&gt;And it's the skill the models just learned. Point Claude at a file and it reads, explains, and traces it about as well as the engineer who's prized for doing so - and far faster. Code-level intellectual control, the scarce and expensive thing, is quietly becoming a commodity. If your value was that you understood the code better than the people around you, the floor is moving.&lt;/p&gt;

&lt;p&gt;There's one catch, and it's the important one: the model understands the code in front of it brilliantly, but it doesn't &lt;em&gt;keep&lt;/em&gt; that understanding. As Sean Goedecke puts it, "&lt;a href="https://www.seangoedecke.com/programming-with-ai-agents-as-theory-building/" rel="noopener noreferrer"&gt;AI agents can't retain theories of the codebase. They have to build their theory from scratch every time.&lt;/a&gt;" The model is a superb momentary reader and a hopeless long-term owner. The persistent theory of the system still has to live in a human.&lt;/p&gt;

&lt;p&gt;So the question for engineers isn't whether they've been replaced. It's narrower and more useful: if the model now owns code-level understanding, where should a human's understanding go?&lt;/p&gt;

&lt;h2&gt;
  
  
  The level nobody held
&lt;/h2&gt;

&lt;p&gt;Up. To the one level intellectual control almost never reached: the whole system.&lt;/p&gt;

&lt;p&gt;Be honest about the old world. Individuals held their files, their service, their corner of the map. But the understanding of how the entire thing fit together - across services, across teams, across the years - usually sagged. It lived in nobody's head, or in one over-subscribed person's, or it rotted as people churned and walked out the door with their theory. We tolerated that gap because holding the whole system was a luxury almost nobody could afford: the human budget was already spent, line by line, on the code.&lt;/p&gt;

&lt;p&gt;That's what changes. The models can hold the code now. Which frees the scarce human attention that used to go there for the thing we never had the budget for - taking intellectual control of the &lt;em&gt;system&lt;/em&gt;. Not "understand less." Understand higher. The frontier moves from "I know this function cold" to "I know how this whole machine behaves" - the more valuable understanding it was always too expensive to have.&lt;/p&gt;

&lt;p&gt;That's the opportunity. The rest of this is how we chase it in practice - concrete enough to try on a single module this week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review the spec, not the diff
&lt;/h2&gt;

&lt;p&gt;It starts by dropping an assumption: that "understanding the code" means "reading the code." Simon Willison - who co-created the Django web framework - keeps a golden rule: he won't commit code he "&lt;a href="https://simonwillison.net/2025/Mar/19/vibe-coding/" rel="noopener noreferrer"&gt;couldn't explain exactly what it does to somebody else&lt;/a&gt;". We kept his rule and moved its unit. It's no longer "can you explain this line" (Claude can). It's "can a human still explain what this &lt;em&gt;system&lt;/em&gt; does." That's the understanding we refuse to give up, and the diff is a terrible place to keep it: at a thousand lines a pull request, the reviewer drowns in detail and surfaces with no theory at all. As Willison notes, once the typing is free, "&lt;a href="https://simonwillison.net/2025/Oct/5/parallel-coding-agents/" rel="noopener noreferrer"&gt;the natural bottleneck on all of this is how fast I can review the results&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;So we review a different artifact: a &lt;code&gt;.cs.md&lt;/code&gt; file spec - borrowed from a tool called &lt;a href="https://codespeak.dev" rel="noopener noreferrer"&gt;CodeSpeak&lt;/a&gt;, and used deliberately backwards from how it was designed.&lt;/p&gt;

&lt;p&gt;CodeSpeak, built by Andrey Breslav (the creator of Kotlin), is a spec-as-source-of-truth system: you write a plain-English &lt;code&gt;.cs.md&lt;/code&gt; describing what the software should do, and &lt;code&gt;codespeak build&lt;/code&gt; generates the code from it. The spec is what you maintain; the code is the output, about &lt;a href="https://codespeak.dev/docs/glossary" rel="noopener noreferrer"&gt;5–10× longer&lt;/a&gt; than the spec that produced it. There's even a one-time &lt;code&gt;codespeak takeover&lt;/code&gt; command for pointing it at an existing codebase and extracting a spec &lt;em&gt;from&lt;/em&gt; the code - a door you walk through once on your way to living in spec-land.&lt;/p&gt;

&lt;p&gt;We inverted it. We keep the &lt;strong&gt;code&lt;/strong&gt; as the source of truth, and treat the &lt;code&gt;.cs.md&lt;/code&gt; as a generated &lt;em&gt;description of what the shipped code already does&lt;/em&gt; - regenerated from the code, checked against the code, never compiled back into it. We live permanently in the place &lt;code&gt;takeover&lt;/code&gt; only visits. We borrow CodeSpeak's format; we never run its compiler. &lt;strong&gt;Reverse CodeSpeak&lt;/strong&gt;, if you want a name for it: the same tool, turned 180°.&lt;/p&gt;

&lt;p&gt;Here's the shape of it - a file that's a few hundred lines of types, reducers, and guards collapses into something a reviewer holds in one screen (an illustrative shape, not a specific file):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# CheckoutReducer&lt;/span&gt;
&lt;span class="gu"&gt;## Short description&lt;/span&gt;
Folds checkout actions into cart and order state. Pure; no I/O.
&lt;span class="gu"&gt;## Data&lt;/span&gt;
Reads &lt;span class="sb"&gt;`Cart`&lt;/span&gt;; writes &lt;span class="sb"&gt;`Order`&lt;/span&gt;. Money is integer minor units, never floats.
&lt;span class="gu"&gt;## Functional requirements&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`AddItem`&lt;/span&gt; is a no-op when the SKU is already in the cart.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`Checkout`&lt;/span&gt; fails closed when &lt;span class="sb"&gt;`total`&lt;/span&gt; is missing - emits no &lt;span class="sb"&gt;`Order`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`ApplyCoupon`&lt;/span&gt; runs before tax; an expired coupon is ignored, not rejected.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a few hundred lines of behavior in a dozen you can actually read. Our review step regenerates the spec for every changed file, then builds the reviewer's reading path &lt;strong&gt;from the specs, not the source&lt;/strong&gt; - the rule is blunt: don't open a source file when a sibling spec exists. Instead of a thousand-line diff, you walk a few hundred lines of compressed meaning in dependency order: what each piece does, what contract it holds, what changed.&lt;/p&gt;

&lt;p&gt;So two reviewers do two different jobs, and neither pretends to do the other's:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/fkub0y91wwvfar3umamw.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fasn6cnz1uwean7yufcdw.png" alt="Two reviewers, two jobs: the AI reviewer reads the code and finds bugs; the human reviewer reads the generated .cs.md spec, builds understanding, and takes system-level intellectual control - with deep dives into the code when it warrants them." width="800" height="714"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model reads the code for defects. The human reads the spec for understanding - and still flags bugs, architecture, and design as they go, understanding is just the part this piece is about. We hand the line-by-line control to the thing that's now better at it, and spend the human on the level the model can't keep.&lt;/p&gt;

&lt;p&gt;And there's a third reader, a side effect we were counting on: the agents themselves. Working in this codebase, they reach for the &lt;code&gt;.cs.md&lt;/code&gt; before the source - the same compressed map the human reviewer walks, at a fraction of the tokens. It doesn't solve Goedecke's problem - the agent still rebuilds its theory every session - but it makes the rebuild cheap: a dozen lines of spec instead of a few hundred lines of code, for every file the task touches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the map up
&lt;/h2&gt;

&lt;p&gt;There's an obvious objection, and it's the right one: a map that nothing compiles, imports, or tests will quietly start to lie. A refactor moves the territory and the map says nothing. A description of code that's drifted from the code is worse than no description at all.&lt;/p&gt;

&lt;p&gt;So most of the work isn't generating specs - it's keeping them up to date, without a compiler to lean on.&lt;/p&gt;

&lt;p&gt;Two things do that. First, a deterministic gate on every change - a small, dependency-free script that runs on the developer's machine, inside the agent pipeline, and in CI on every pull request, and &lt;strong&gt;hard-fails&lt;/strong&gt; the change on any of three findings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The fingerprint check.&lt;/strong&gt; Every generated spec ends with a stamped footer recording a hash of the exact source bytes it was generated from. The gate re-hashes the current source: if the code changed and the map didn't - one character is enough - the hashes disagree and the change fails on the spot. No string matching, no judgment call; the file either is the one the spec describes or it isn't. It's the closest thing the map gets to a compiler: not an opinion about drift, a proof of it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The coverage check.&lt;/strong&gt; Drift isn't only a map that lies - it's also territory with no map. A changed file that warrants a spec but doesn't have one fails the same gate. So does the mirror image: a spec whose source file no longer exists fails as an orphan, so deleted code can't leave a ghost map behind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The removed-shape check.&lt;/strong&gt; When a type or branch that existed before the change is gone from the source but the spec still names it, the gate fails and says which name - the fingerprint tells you &lt;em&gt;that&lt;/em&gt; the map went stale; this tells you &lt;em&gt;what lie&lt;/em&gt; it would have told.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those failures is something an AI reviewer can wave through - a deterministic signal overrides every softer opinion in the pipeline - so catching a stale map never depends on a human noticing it. A semantic pass behind the gate reads for the subtler drift a checksum can't catch: wording that's now misleading, a claim the code no longer keeps.&lt;/p&gt;

&lt;p&gt;Second, regeneration is &lt;strong&gt;anchored&lt;/strong&gt;: we keep the previous wording wherever behavior is unchanged and re-describe only what actually moved - so specs don't churn on every refactor, and when the spec and the code disagree, the code always wins.&lt;/p&gt;

&lt;p&gt;And we still read the code. The spec is the &lt;strong&gt;default&lt;/strong&gt; review surface, not a cage. When a change is gnarly, security-sensitive, or just unfamiliar, we drop into the actual source and do a deep dive. That's the point, not an exception to it: we ceded the cheap, line-by-line reading so we could afford to spend real attention exactly where a human is worth it.&lt;/p&gt;

&lt;p&gt;Some files don't get a spec at all - and that's the same principle, not a gap in it. A presentational component's meaning &lt;em&gt;is&lt;/em&gt; how it looks; a paragraph describing its spacing and color would be a worse map than the component itself. So we don't spec those - we look at them, in browser QA. Only the big, logic-heavy containers - real state, real branching, real gating - earn a &lt;code&gt;.cs.md&lt;/code&gt;, and even then it's stripped of visuals: the contract, not the CSS. Spec what you'd reason about; look at what you'd eyeball. The whole point is to put each kind of understanding where it actually lives.&lt;/p&gt;

&lt;p&gt;A note on the machinery, to head off the obvious question of who runs all this: the specs are auto-generated, never hand-written. They're refreshed as the work happens: when an agent edits a file, it regenerates that file's spec before it commits. And they feed a gate a human still owns - a person approves the merge.&lt;/p&gt;

&lt;p&gt;There's a deliberate cost choice underneath that. A spec system that regenerates on every change is the natural thing to run against a metered, per-token model API - every regeneration is tokens you pay for, and the bill grows with your codebase. We wanted the opposite: a way to run the same approach on a subscription. So we generate the specs as a skill inside Claude Code, on the flat subscription our engineers already work in, not a metered per-token API. Regenerating a spec on every change is cheap by design - you can run it on the agent tooling you already have, with no new vendor and no per-token meter.&lt;/p&gt;

&lt;p&gt;If you want to try it, the bootstrap is smaller than it sounds - ours was three steps, no new tooling:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Point your agent at CodeSpeak and ask it to build the generator.&lt;/strong&gt; That's not a simplification - it's what we did. We pointed Claude at the CodeSpeak docs and asked it to write a skill that produces a &lt;code&gt;.cs.md&lt;/code&gt; in that format from a source file. The format is documented plain English, and "describe this file in this shape" is exactly the kind of task the model nails on the first pass. Alternatively, run CodeSpeak's own &lt;code&gt;codespeak takeover&lt;/code&gt; on your codebase - fully compliant specs, straight from the tool that defined the format.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wire the skill into your dev pipeline.&lt;/strong&gt; Regenerate the spec for every file an agent edits before it commits, remember to anchor the new file with the previous one, and add the drift gate - the fingerprint alone (hash the source bytes into the spec's footer, re-hash on every change) is a small script and catches most of the rot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start narrow.&lt;/strong&gt; Your stack doesn't matter - the spec is plain English, and plain English describes any codebase. Generate specs for your highest-churn module, fail the build when one drifts, and review the next pull request from the specs instead of the diff. One module is enough to feel whether you're holding more of the system or less.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The next altitude
&lt;/h2&gt;

&lt;p&gt;Today our specs are per-file: one &lt;code&gt;.cs.md&lt;/code&gt; next to each source file. That already lets a reviewer hold a whole change in their head at a level the raw diff never allowed. But a file is still a low rung, and "intellectual control of the system" is a promise a stack of per-file specs doesn't quite keep on its own.&lt;/p&gt;

&lt;p&gt;So our next experiment - and it is an experiment, not something we've shipped - is specs a level up: for &lt;strong&gt;modules and subsystems&lt;/strong&gt;, a higher-altitude map than the per-file ones. The goal is the full-system control that always used to sag: a human who can hold what the whole thing does, not just what each file does, and who reads down into the detail only where it earns the attention.&lt;/p&gt;

&lt;p&gt;Notice what that is and isn't. It is not less control - it's the same scarce attention, re-spent and aimed higher. A reviewer working from good specs understands &lt;em&gt;more&lt;/em&gt; system per unit of attention than they did back when they read every line - which makes this, oddly, &lt;strong&gt;more&lt;/strong&gt; of a grip on the whole than the all-human world ever managed, not a retreat from it. That's the real deal on offer, if you take it on purpose: not "stop understanding your software," but "stop spending your understanding on the parts a model now holds, and spend it on the whole that no model will."&lt;/p&gt;

&lt;h2&gt;
  
  
  Trust is the side effect
&lt;/h2&gt;

&lt;p&gt;We didn't build any of this to manufacture trust - and, honestly, not even for the big reason this whole piece is about. We built it because code review had become a bottleneck and we wanted reviews to go faster. Taking intellectual control of the whole system, and the trust that came with it, were what we found once we had it - not the plan.&lt;/p&gt;

&lt;p&gt;In a June 2026 essay, Kent Beck named the dynamic better than we could. "&lt;a href="https://newsletter.kentbeck.com/p/trust-factory" rel="noopener noreferrer"&gt;We're accumulating code faster than we are accumulating trust&lt;/a&gt;", he wrote - and the reason it matters is that "software is bipedal-code &amp;amp; trust go together. One without the other just hops along awkwardly." Trust, he notes, "accumulates slowly &amp;amp; evaporates in an instant." A bug you can usually repair; trust, in his telling, is "irreversible."&lt;/p&gt;

&lt;p&gt;You can't bolt that kind of trust on at the end. It's the residue of understanding. Keep a real grip on what the system does and trust comes along for free; lose the grip and no amount of green checkmarks buys it back. And it's concrete, not a mood: the reviewer who can actually say what a change does; the engineer six months from now who inherits the system and finds a current map of it, not a codebase whose theory left with whoever wrote it; the team that can hand work to an agent and still answer for what it built. We kept our grip on the thing that still needs a human - the whole system - and trust came as the side effect. Willison's rule survives intact: don't ship what you can't explain. We just moved where the explaining happens. Let the models have the code. Take the system for yourself.&lt;/p&gt;

</description>
      <category>codespeak</category>
      <category>codereview</category>
      <category>ai</category>
    </item>
    <item>
      <title>Comparing switch-like operators in 14 different programming languages</title>
      <dc:creator>Aleks Verein</dc:creator>
      <pubDate>Sat, 11 Sep 2021 10:00:22 +0000</pubDate>
      <link>https://dev.to/tpom6oh/comparing-switch-like-operators-in-14-different-programming-languages-4da9</link>
      <guid>https://dev.to/tpom6oh/comparing-switch-like-operators-in-14-different-programming-languages-4da9</guid>
      <description>&lt;p&gt;We are going to look at Javascript, Typescript, Java, C#, Swift, Objective-C, Python, PHP, Ruby, Kotlin, ReasonML, Dart, Go and Elixir.&lt;/p&gt;

&lt;p&gt;At Avo (avo.app) we work with 12 languages, and I decided to do a series of quick comparisons of those languages, plus 3 languages we are going to support soon.&lt;/p&gt;

&lt;p&gt;First feature we are going to look at is the switch-like constructs. We are interested in 3 features related to switches - ability to use switch as an expression (so it returns a value), whether the switch construct is exhaustive (you need to handle all cases to compile the code) and if the fall-through logic disabled (so you don't need to break out of each case explicitly).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;has switch expression&lt;/th&gt;
&lt;th&gt;is exhaustive&lt;/th&gt;
&lt;th&gt;no need to break&lt;/th&gt;
&lt;th&gt;reference&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;javascript&lt;/td&gt;
&lt;td&gt;limited, only if wrapped in a function &lt;a href="https://stackoverflow.com/a/55944296" rel="noopener noreferrer"&gt;https://stackoverflow.com/a/55944296&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;typescript&lt;/td&gt;
&lt;td&gt;limited, only if wrapped in a function&lt;/td&gt;
&lt;td&gt;limited &lt;a href="http://ideasintosoftware.com/exhaustive-switch-in-typescript/" rel="noopener noreferrer"&gt;http://ideasintosoftware.com/exhaustive-switch-in-typescript/&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;same as JS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;java&lt;/td&gt;
&lt;td&gt;starting java 12&lt;/td&gt;
&lt;td&gt;expression is, statement is not&lt;/td&gt;
&lt;td&gt;additional syntax starting java 12&lt;/td&gt;
&lt;td&gt;&lt;a href="https://openjdk.java.net/jeps/354" rel="noopener noreferrer"&gt;https://openjdk.java.net/jeps/354&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c#&lt;/td&gt;
&lt;td&gt;starting C# 8.0&lt;/td&gt;
&lt;td&gt;- (expression will give a compile warning)&lt;/td&gt;
&lt;td&gt;need to break in the statement&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;swift&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html" rel="noopener noreferrer"&gt;https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;objc&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;🤷‍♂️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;python&lt;/td&gt;
&lt;td&gt;no switch in python :)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;php&lt;/td&gt;
&lt;td&gt;called match, introduced in php 8&lt;/td&gt;
&lt;td&gt;match is, switch is not&lt;/td&gt;
&lt;td&gt;match , switch is not&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.php.net/manual/en/control-structures.match.php" rel="noopener noreferrer"&gt;https://www.php.net/manual/en/control-structures.match.php&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ruby, called &lt;code&gt;case&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ruby-doc.org/core-3.0.1/doc/syntax/control_expressions_rdoc.html#label-case+Expression" rel="noopener noreferrer"&gt;https://ruby-doc.org/core-3.0.1/doc/syntax/control_expressions_rdoc.html#label-case+Expression&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kotlin, called when&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;expression is, statement is not&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;&lt;a href="https://kotlinlang.org/docs/control-flow.html#when-expression" rel="noopener noreferrer"&gt;https://kotlinlang.org/docs/control-flow.html#when-expression&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;reasonml/rescript&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;&lt;a href="https://rescript-lang.org/docs/manual/latest/pattern-matching-destructuring#switch-based-on-shape-of-data" rel="noopener noreferrer"&gt;https://rescript-lang.org/docs/manual/latest/pattern-matching-destructuring#switch-based-on-shape-of-data&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dart&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dart.dev/guides/language/language-tour#switch-and-case" rel="noopener noreferrer"&gt;https://dart.dev/guides/language/language-tour#switch-and-case&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;go&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;&lt;a href="https://tour.golang.org/flowcontrol/9" rel="noopener noreferrer"&gt;https://tour.golang.org/flowcontrol/9&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;elixir          (called case)&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;- (runtime error CaseClauseError)&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;&lt;a href="https://elixir-lang.org/getting-started/case-cond-and-if.html#case" rel="noopener noreferrer"&gt;https://elixir-lang.org/getting-started/case-cond-and-if.html#case&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>programminglanguages</category>
    </item>
    <item>
      <title>How to set up `git bro` command with git alias</title>
      <dc:creator>Aleks Verein</dc:creator>
      <pubDate>Fri, 16 Jul 2021 11:49:38 +0000</pubDate>
      <link>https://dev.to/tpom6oh/how-to-unlock-git-bro-command-1l40</link>
      <guid>https://dev.to/tpom6oh/how-to-unlock-git-bro-command-1l40</guid>
      <description>&lt;p&gt;Have you seen people use the &lt;code&gt;git bro&lt;/code&gt; command in terminal and always wondered how they do it?&lt;/p&gt;

&lt;p&gt;It's actually very easy and I'm going to teach you now. Moreover, after mastering this technique you'll be able to use any command your imagination comes up with, like &lt;code&gt;git cmon&lt;/code&gt; or &lt;code&gt;git brunch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I'll also share my own commands config in the end (quite conservative tbh).&lt;/p&gt;

&lt;h2&gt;
  
  
  You have git set up
&lt;/h2&gt;

&lt;p&gt;First of all, you need git. I assume you already have it, if not, &lt;a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git" rel="noopener noreferrer"&gt;check this out&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the command
&lt;/h2&gt;

&lt;p&gt;All you need to add a command is to define an alias, like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global alias.bro `branch`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Manage the aliases
&lt;/h2&gt;

&lt;p&gt;To see all the aliases run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To remove one run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global --unset alias.bro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  My aliases
&lt;/h2&gt;

&lt;p&gt;As I promised, in the end I share my setup&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias.co=checkout
alias.cm=commit
alias.st=status
alias.bro=branch
alias.br=checkout -b
alias.pushit=push -u origin HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Thanks for tuning in
&lt;/h2&gt;

&lt;p&gt;That's it, now you can update your CV stating that you are bros with &lt;code&gt;git&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;👋&lt;/p&gt;

</description>
      <category>git</category>
      <category>tips</category>
      <category>devtips</category>
    </item>
    <item>
      <title>ReasonML &amp; Rescript in 5 minutes</title>
      <dc:creator>Aleks Verein</dc:creator>
      <pubDate>Fri, 23 Apr 2021 16:46:57 +0000</pubDate>
      <link>https://dev.to/tpom6oh/reasonml-rescript-in-5-minutes-58l6</link>
      <guid>https://dev.to/tpom6oh/reasonml-rescript-in-5-minutes-58l6</guid>
      <description>&lt;h3&gt;
  
  
  What is this language about?
&lt;/h3&gt;

&lt;p&gt;It's a functional language that compiles to JavaScript (or to OCaml). We use it widely at &lt;a href="//avo.app"&gt;avo.app&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is ML in ReasonML?
&lt;/h3&gt;

&lt;p&gt;Nowadays ML usually stands for Machine Learning, but in the old days there was a programming language called "Meta Language" which is the ancestor of ReasonML, or Reason Meta Language.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why rename?
&lt;/h3&gt;

&lt;p&gt;ReasonML is compatible with both JS and OCaml, but lately it was mostly used in the JS ecosystem.&lt;br&gt;
Rescript takes JS-related things from Reason and stops being limited by OCaml support.&lt;/p&gt;
&lt;h3&gt;
  
  
  What are the good things?
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Immutability
&lt;/h4&gt;

&lt;p&gt;All references are actually constants. Shadowing is widely used. Standard library functions are non-mutative and produce new instances if any changes are made. There is a workaround to create a mutable reference if needed but deliberate enough to be discouraging.&lt;/p&gt;
&lt;h4&gt;
  
  
  Piping and currying
&lt;/h4&gt;

&lt;p&gt;Rescript is a functional language with no methods on objects, but you can call and chain functions in a familiar way with piping and currying, like&lt;br&gt;
&lt;code&gt;myList-&amp;gt;List.length&lt;/code&gt; &lt;br&gt;
or &lt;br&gt;
&lt;code&gt;myArray-&amp;gt;Array.map(item =&amp;gt; item * 2)&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Sound type system and type inference
&lt;/h4&gt;

&lt;p&gt;This is probably the main reason to choose rescript. It has strong type system and powerful type inference, so you are rarely required to explicitly define types, but the compiler always knows what the types are.&lt;/p&gt;
&lt;h4&gt;
  
  
  No folder requirements and no imports
&lt;/h4&gt;

&lt;p&gt;This is a case in many languages, but coming from Java I really appreciate this feature. And Javascript developers love the no imports thing!&lt;/p&gt;
&lt;h4&gt;
  
  
  Full support of algebraic data types
&lt;/h4&gt;

&lt;p&gt;It's very easy to describe any domain with the custom types&lt;br&gt;
You can create type aliases like &lt;code&gt;type eventId = string&lt;/code&gt; or complex types like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type event = {
  id: eventId,
  name: string,
  uniqueName: option&amp;lt;string&amp;gt;,
  description: string,
  properties: list&amp;lt;property&amp;gt;,
  types: list&amp;lt;eventType&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The main construction in the language is the exhaustive switch optimized for pattern matching
&lt;/h4&gt;

&lt;p&gt;It's accompanied by an empowered kind of enum called variants. There are options of variants with and without duck typing. &lt;a href="https://tinyurl.com/yv4nfpkm" rel="noopener noreferrer"&gt;Better to see it in action&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Simple syntax
&lt;/h4&gt;

&lt;p&gt;It's possible to start writing code after just a few hours of learning if you already know another programming language.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relatively safe refactoring
&lt;/h3&gt;

&lt;p&gt;The combination of a rigid type system and exhaustive switches make the compiler very efficient in finding bugs in the compile time.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the not so good things?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Simple syntax means it's verbose
&lt;/h4&gt;

&lt;p&gt;There is not much syntax sugar, for example to unwrap an optional constant you'd have to write &lt;code&gt;maybeSomething-&amp;gt;Option.map(something -&amp;gt; something-&amp;gt;performOperation)&lt;/code&gt; instead of &lt;code&gt;maybeSomething?.performOperation()&lt;/code&gt; in some other languages.&lt;/p&gt;

&lt;h4&gt;
  
  
  You have to define functions before using them
&lt;/h4&gt;

&lt;p&gt;Yes, like in good old C.&lt;/p&gt;

&lt;h4&gt;
  
  
  You can still have type-related bugs
&lt;/h4&gt;

&lt;p&gt;Having a powerful compiler that catches 99% of the type bugs can be too relaxing and it becomes easier to miss that one occasional bug that slips through the compiler checks. 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus
&lt;/h3&gt;

&lt;p&gt;We are maintaining a public code style guide for &lt;a href="https://github.com/avohq/reasonml-code-style-guide" rel="noopener noreferrer"&gt;ReasonML&lt;/a&gt;, contributions are very welcome!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>web</category>
      <category>node</category>
    </item>
    <item>
      <title>Kotlin vs Swift: implementing a method that accepts a limited set of polymorphic equitable types</title>
      <dc:creator>Aleks Verein</dc:creator>
      <pubDate>Tue, 23 Mar 2021 18:47:34 +0000</pubDate>
      <link>https://dev.to/tpom6oh/kotlin-vs-swift-implementing-a-method-that-accepts-a-limited-set-of-polymorphic-equitable-types-jd8</link>
      <guid>https://dev.to/tpom6oh/kotlin-vs-swift-implementing-a-method-that-accepts-a-limited-set-of-polymorphic-equitable-types-jd8</guid>
      <description>&lt;p&gt;At Avo we work on code generation based on tracking plans.&lt;br&gt;
Recently we added a new interface for calling events - before we were generating a method for each event in the tracking plan, i. e. there were methods &lt;code&gt;Avo.userSubscribed(userType, subscriptionType)&lt;/code&gt; and &lt;code&gt;Avo.commentAdded(authorId, mentionedUserIds)&lt;/code&gt;.&lt;br&gt;
With the new interface we create a type for each event, i.e. &lt;code&gt;UserSubscribed&lt;/code&gt; with &lt;code&gt;userType&lt;/code&gt; and &lt;code&gt;subscriptionType&lt;/code&gt; as fields and &lt;code&gt;CommentAdded&lt;/code&gt; with &lt;code&gt;authorId&lt;/code&gt; and &lt;code&gt;mentionedUserIds&lt;/code&gt; fields, and a new method called &lt;code&gt;track&lt;/code&gt; that expects instances of those types, like this  &lt;code&gt;Avo.track(UserSubscribed(userType, subscriptionType))&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;This change makes Avo more flexible to use in large codebases, for example you can build the &lt;code&gt;UserSubscribed&lt;/code&gt; events in different parts of you app gradually and pass it around.&lt;br&gt;
You can also build a simple test implementation of the new &lt;code&gt;track&lt;/code&gt; interface that does not require mocking.&lt;/p&gt;
&lt;h3&gt;
  
  
  What are the challenges?
&lt;/h3&gt;

&lt;p&gt;Firstly, we don't want users of the generated code to pass unexpected things to the track method. Only the events defined in the tracking plan are expected.&lt;br&gt;
Secondly, we want the events to be meaningfully comparable.&lt;/p&gt;
&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;Let's see what both languages can offer us to solve this little challenge.&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Defining the event types.
&lt;/h4&gt;

&lt;p&gt;The ways of choice to define a limited set of types are:&lt;/p&gt;

&lt;p&gt;In Kotlin - sealed classes. Sealed classes are abstract classes and you can define their child classes only in the same file. User's won't be able to create their implementation of our sealed class, exactly as we want. This also makes the compiler know the exact set of descendants of our sealed class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sealed class AvoEvent {
    data class UserSubscribed(val userType: String, val subscriptionType: String): AvoEvent()
    data class CommentAdded(val authorId: String, val mentionedUserIds: List&amp;lt;String&amp;gt;): AvoEvent()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Swift - enums. Enums in Swift are more powerful than in most other similar languages. Each enum case can have any number of variously typed parameters, which is nice for our case. User's are not able to add cases outside of the enum.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public enum AvoEvent: Equatable {
    case userSubscribed(userType: String, subscriptionType: String);
    case commentAdded(authorId: String, mentionedUserIds: [String]);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Here things are quite even, since classes are a bit more flexible (more on it in the next section) and also in Kotlin you use common &lt;code&gt;class&lt;/code&gt; interface for most things, while in Swift you have to use different entities - &lt;code&gt;classes&lt;/code&gt; / &lt;code&gt;structs&lt;/code&gt; and &lt;code&gt;enums&lt;/code&gt;. On the other hand Swift code looks cleaner.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Making the types equitable
&lt;/h4&gt;

&lt;p&gt;In Kotlin we use data classes. Every data class automatically gets &lt;code&gt;equals&lt;/code&gt; method implementation without the need to write any code based on the primary constructor values.&lt;br&gt;
In Swift we set our enum to conform the &lt;code&gt;Equitable&lt;/code&gt; protocol. In modern Swift if all the used types of a thing we add &lt;code&gt;Equitable&lt;/code&gt; protocol to are &lt;code&gt;Equitable&lt;/code&gt; you don't need to write any implementation. This is similar for both languages.&lt;br&gt;
Everything is great until we get a enum member with an &lt;code&gt;Any&lt;/code&gt; type parameter.&lt;br&gt;
The problem in Swift is that the &lt;code&gt;Any&lt;/code&gt; type is not &lt;code&gt;Equitable&lt;/code&gt;. And once it appears you have to implement the compare method (&lt;code&gt;==&lt;/code&gt;) manually. Moreover, once you have the compare method you have to manually implement comparison of each enum case. (In Kotlin for example we can implement the equality method on a separate single child class of our sealed class, that's the advantage of sealed classes over enums I mentioned in the previous section).&lt;br&gt;
In Kotlin &lt;code&gt;Any&lt;/code&gt; type is equitable out of the box. Since it's has &lt;code&gt;equals&lt;/code&gt; method it is designed to be.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This point is won by Kotlin.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Picking what to do based on the provided parameter
&lt;/h4&gt;

&lt;p&gt;Here everything is quite simple:&lt;br&gt;
In Kotlin we use &lt;code&gt;when&lt;/code&gt; statement.&lt;br&gt;
In Swift we use &lt;code&gt;switch&lt;/code&gt; statement.&lt;br&gt;
The good thing about the &lt;code&gt;switch&lt;/code&gt; statements in Swift is that they are required to be exhaustive. This makes perfect sense in a statically typed languages - I want to be sure that if I add a new case to my enum and not add it to the &lt;code&gt;switch&lt;/code&gt; I'm alarmed by the compiler.&lt;br&gt;
Unfortunately it is not the case in Kotlin. When you use &lt;code&gt;when&lt;/code&gt; as a statement, not assigning it's result to a variable or using it in some other way, which is a default way for those who come from Java and many other C-like languages, it is not required to be exhaustive. You can use &lt;code&gt;when&lt;/code&gt; as expression and then it becomes &lt;code&gt;exhaustive&lt;/code&gt;, but that's not enough. &lt;a href="https://proandroiddev.com/til-when-is-when-exhaustive-31d69f630a8b" rel="noopener noreferrer"&gt;Here is a bit more on that topic&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In this part I give the point to Swift.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;All in all, it is a draw in out little face off, Kotlin is a winner on the data structure design side and Swift wins in the operator design.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>swift</category>
    </item>
    <item>
      <title>What are great developer docs? Looking at Stripe here, let's discuss</title>
      <dc:creator>Aleks Verein</dc:creator>
      <pubDate>Tue, 16 Mar 2021 09:43:30 +0000</pubDate>
      <link>https://dev.to/tpom6oh/what-are-great-developer-docs-looking-at-stripe-here-let-s-discuss-1eo9</link>
      <guid>https://dev.to/tpom6oh/what-are-great-developer-docs-looking-at-stripe-here-let-s-discuss-1eo9</guid>
      <description>&lt;p&gt;Recently I had a chance to work with one of the most honored developer experiences out there - with Stripe, &lt;a href="https://stripe.com/docs" rel="noopener noreferrer"&gt;https://stripe.com/docs&lt;/a&gt;&lt;br&gt;
Here are a few things I really liked about the docs there and a few flaws I found.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But to be clear, overall I rate Stripe docs very high.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;(+) First of all, it's awesome. Human readable prefixes in the API keys, omg, why does not everyone do it?!! I.e. &lt;code&gt;price_******&lt;/code&gt; for a price key and &lt;code&gt;sub_*******&lt;/code&gt; for a subscription key&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(+) Docs are user story based, which is very cool. It's easy to go with the flow and find what you need. Would totally adapt that. Search is also good, but it is a must nowadays&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(-) The subject area is huge, some specific things are hard to find though, i.e. subscription statuses are teased here and there, but the whole list is only in the API docs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(-) Some cherry picked dev docs/references are available through the main docs entry point, but others live at &lt;a href="https://stripe.dev" rel="noopener noreferrer"&gt;https://stripe.dev&lt;/a&gt; and there are no easily findable direct links to the server sdks from the main docs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(+) Server (at least Node.js I worked with) SKDs are exactly like the API reference. This is insanely convenient. I suspect this is one of the reason why the server SDKs are not featured in the main docs&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What do you like and dislike about developer docs, for Stripe or any other product? Share some examples!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>devrel</category>
      <category>documentation</category>
      <category>devlive</category>
    </item>
    <item>
      <title>Public ReasonML Code Style Guide @Avo</title>
      <dc:creator>Aleks Verein</dc:creator>
      <pubDate>Tue, 27 Oct 2020 08:58:54 +0000</pubDate>
      <link>https://dev.to/tpom6oh/public-reasonml-code-style-guide-avo-1pad</link>
      <guid>https://dev.to/tpom6oh/public-reasonml-code-style-guide-avo-1pad</guid>
      <description>&lt;p&gt;Just released a &lt;a href="https://www.avo.app/blog/reasonml-code-style-guide" rel="noopener noreferrer"&gt;blog post&lt;/a&gt; about our Code Style Guide approach.&lt;/p&gt;

&lt;p&gt;Last week we've open sourced the guide itself &lt;a href="https://github.com/avohq/reasonml-code-style-guide" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Contributions are adoptions are more than welcome, let's build a canonical ReasonML &amp;amp; ReScript code style guide together! &lt;/p&gt;

</description>
      <category>reason</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
