<?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: Viljami Kuosmanen</title>
    <description>The latest articles on DEV Community by Viljami Kuosmanen (@anttiviljami).</description>
    <link>https://dev.to/anttiviljami</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171224%2Fb0344331-1500-47ee-ae6d-9e7f671b0045.jpg</url>
      <title>DEV Community: Viljami Kuosmanen</title>
      <link>https://dev.to/anttiviljami</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anttiviljami"/>
    <language>en</language>
    <item>
      <title>Our Entire Company Ships Code Now. 40 PRs from Non-Engineers in 60 Days.</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Mon, 13 Apr 2026 13:06:30 +0000</pubDate>
      <link>https://dev.to/epilot/our-entire-company-ships-code-now-40-prs-from-non-engineers-in-60-days-jo5</link>
      <guid>https://dev.to/epilot/our-entire-company-ships-code-now-40-prs-from-non-engineers-in-60-days-jo5</guid>
      <description>&lt;p&gt;In February, I opened our entire codebase to the company. PMs, designers, projects, customer success, and support all got access to 219 repositories and over a million lines of production code. I handed them powerful coding agents and told them to start contributing.&lt;/p&gt;

&lt;p&gt;I've been writing about product engineering for years. The core idea: engineers should understand the whole product, the customer, the business problem. I wanted to test the reverse. Can non-engineers contribute to the codebase if you give them the right tools?&lt;/p&gt;

&lt;p&gt;Two months of real data delivered a clear answer: yes. And it may be the most powerful shortcut I've found to building capable, business-aware product teams who truly care about what they ship.&lt;/p&gt;

&lt;p&gt;Here is what that looked like at epilot: 629 merged PRs in 60 days. &lt;strong&gt;40 PRs were from 11 non-engineers&lt;/strong&gt;. All teams have at least one person who contributed to our codebase with Claude Code.&lt;/p&gt;

&lt;p&gt;We're not alone in seeing this shift. &lt;a href="https://stripe.dev/blog/minions-stripes-one-shot-end-to-end-coding-agents" rel="noopener noreferrer"&gt;Stripe ships over a thousand agent-produced PRs per week&lt;/a&gt;. &lt;a href="https://openai.com/index/introducing-codex/" rel="noopener noreferrer"&gt;Superhuman uses Codex&lt;/a&gt; to let product managers contribute lightweight code changes without pulling in an engineer (except for code review). &lt;a href="https://ideas.fin.ai/p/we-gave-claude-code-to-everyone-at" rel="noopener noreferrer"&gt;Intercom gave Claude Code to everyone in the company&lt;/a&gt;, over 1,000 non-engineers (PMs, designers, support, marketers, and more), and more than 300 became active weekly users.&lt;/p&gt;

&lt;p&gt;This post is a detailed, honest look at how we set it up, what actually worked, the mistakes we made, and the deeper lessons that emerged.&lt;/p&gt;




&lt;h2&gt;
  
  
  The starting point
&lt;/h2&gt;

&lt;p&gt;epilot is a B2B SaaS platform for energy companies. We run a fully remote team of 40+ product engineers with no engineering managers and no dedicated platform team. Everyone owns end-to-end ownership. We already ship to production 150+ times per week on AWS serverless.&lt;/p&gt;

&lt;p&gt;Our entire engineering team was already using AI coding agents daily. Claude Code, Codex, Cursor. Engineers had adopted them fast and the productivity gains were obvious. The question I wanted to answer next: what happens when you expand codebase access via coding agents to the rest of the company? PMs, designers, customer success, support. Not as a one-off hack day, but as a fully supported, production-grade workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The infrastructure that turned agents into teammates
&lt;/h2&gt;

&lt;p&gt;Claude Code and Codex still only ship connectors to GitHub, and our entire codebase lives in GitLab. So we created a single GitHub repo that bootstraps a developer sandbox with a shallow copy of all 219 repositories. This allows both AI agents or engineers to spin up a fully functioning developer environment with everything cloned &amp;amp; tools set up within minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Agents live in Slack
&lt;/h3&gt;

&lt;p&gt;We created &lt;strong&gt;#dev-squad-agents&lt;/strong&gt; alongside our regular squad channels. Anyone could join via Claude Code, Codex, or GitHub Codespaces. I ran three one-hour onboarding sessions to showcase the tooling and make sure everyone had the required access: one for design, one for support, one for go-to-market. The PMs didn't need their own session. Their engineering teams had already invited them and they were eager to start.&lt;/p&gt;

&lt;p&gt;This single decision drove adoption more than anything else.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. One-click preview environments
&lt;/h3&gt;

&lt;p&gt;Every PR automatically generates a live preview link in CI. Click it, see the change, test it immediately. No local setup required.&lt;/p&gt;

&lt;p&gt;For engineers this is convenient. For non-engineers it is essential. If they cannot see and interact with their change, they can't meaningfully contribute.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Deep institutional context
&lt;/h3&gt;

&lt;p&gt;We built an indexed knowledge base called &lt;strong&gt;&lt;a href="https://www.linkedin.com/pulse/we-made-coding-agents-actually-reliable-fixing-one-thing-kuosmanen-oa2of/" rel="noopener noreferrer"&gt;how-to-everything&lt;/a&gt;&lt;/strong&gt;. It contains our API patterns, backend conventions, code style, CI/CD and testing strategy, full business context, domain terminology, and our entire RFC archive.&lt;/p&gt;

&lt;p&gt;Stripe solved the same problem by connecting agents to 400+ internal tools. We chose comprehensive indexing. The insight is identical: &lt;strong&gt;agents without your company’s context produce garbage. Agents with it produce work that feels native.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Design system in context
&lt;/h3&gt;

&lt;p&gt;Our Volt UI component library is baked into the agent prompt. Claude now generates frontend code that respects the correct components, spacing, colours, and patterns from the first try. Consistent UI without forcing a designer to review every small change.&lt;/p&gt;




&lt;h2&gt;
  
  
  Claude as a coworker: the Slack pattern
&lt;/h2&gt;

&lt;p&gt;Claude quickly became the most active “team member.” People tag &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/claude"&gt;@claude&lt;/a&gt;&lt;/strong&gt; the same way they tag colleagues, and they expect results just as fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  How engineers use it
&lt;/h3&gt;

&lt;p&gt;Simple tasks look like: “&lt;a class="mentioned-user" href="https://dev.to/claude"&gt;@claude&lt;/a&gt; fix EPI-5660.” A PR appears.&lt;/p&gt;

&lt;p&gt;More powerful uses scale across the organization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;“&lt;a class="mentioned-user" href="https://dev.to/claude"&gt;@claude&lt;/a&gt; which microfrontends still use the legacy editor?”&lt;/em&gt; → instant audit of all 219 repos.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;“&lt;a class="mentioned-user" href="https://dev.to/claude"&gt;@claude&lt;/a&gt; migrate 13 backend repos from file-client to lambda-adapter.”&lt;/em&gt; → completed in one session.&lt;/li&gt;
&lt;li&gt;Mass upgrades across 20+ repositories: one message triggers 6 parallel sub-agents that handle changes, tests, and PRs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What once took a full day of tedious cross-repo work now happens in hours. Agents worked weekends. Engineers didn't have to.&lt;/p&gt;

&lt;h3&gt;
  
  
  How non-engineers use it
&lt;/h3&gt;

&lt;p&gt;They speak in plain product language:&lt;br&gt;
&lt;em&gt;- “&lt;a class="mentioned-user" href="https://dev.to/claude"&gt;@claude&lt;/a&gt; disable drag and drop of entity table columns for embedded tables.”&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;“&lt;a class="mentioned-user" href="https://dev.to/claude"&gt;@claude&lt;/a&gt; when creating a new family in the Label Builder, the drawer should close automatically.”&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude figures out the right repositories and implementation details. Non-engineers don't need to know our tech stack or repo structure. They describe the desired outcome.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production impact
&lt;/h3&gt;

&lt;p&gt;We added Claude to &lt;strong&gt;#alerts-production&lt;/strong&gt; on day two. It investigates incidents, reads logs, traces errors, and proposes fixes before most engineers open the dashboard. When a bulk action hammered Elasticsearch with 100 parallel requests, Claude designed an org-level job queue with concurrency limits that cut peak load by 90%. Engineers started replying “another one bites the dust” to resolved alerts.&lt;/p&gt;

&lt;p&gt;Within a week, Claude felt like a trusted junior-to-senior coworker: fast executor, deep historian, and reliable pair programmer. Usage spread organically to every squad.&lt;/p&gt;




&lt;h2&gt;
  
  
  What people actually built
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Non-engineer contributions (40 merged PRs from 11 people)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feature work&lt;/strong&gt;: One PM built auto-tagging for file uploads (a feature he had spec’d three months earlier). Another shipped 13 PRs on messaging (bulk email templates, sidebar toggles, drawer behaviour, i18n). A go-to-market colleague delivered entire features, like pivot tables for displaying time-series data in epilot tables, that are now live for customers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily improvements&lt;/strong&gt;: Customer success shipped portal config changes they handle every day. Designers and support added FullStory tracking and started prototyping new UI flows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Translations&lt;/strong&gt;: Native speakers cleared 116 German translation improvements with almost no engineering involvement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UX via vibecoding&lt;/strong&gt;: A designer shipped a UX improvement to our Flow Hub before heading into the weekend: when creating a new Flow, users now get prompted to enter a name first. She described it as "vibe coding" and the change reduced friction in a way she'd been wanting to fix for a while.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These were not toy changes. Several were meaningful, customer-facing updates. One PM even asked Claude to create a demo video of the feature it just built, so he could share it with the team. The full cycle from spec to demo, handled through conversation with an agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Engineer contributions (589 merged PRs)
&lt;/h3&gt;

&lt;p&gt;Engineers use agents across the full lifecycle. Writing RFCs and technical designs. Implementing multi-service features. Running tests. Shipping to production. Auditing feature flag usage across 15 repos and cleaning up stale flags. Investigating production incidents from alert channels before anyone opens a dashboard.&lt;/p&gt;

&lt;p&gt;Some of the most valuable uses are research and diagnostics. "Which services listen to the file upload event?" "How many microfrontends still use the legacy editor?" "Audit all listSchemas calls and upgrade to the new summary API where safe." These are questions that used to take half a day of grepping across 219 repos. Claude answers them in minutes.&lt;/p&gt;

&lt;p&gt;GitHub Codespaces turned out to be a key piece for engineers too. Running Claude Code in auto-mode in a cloud sandbox means you can kick off a multi-repo migration and let it run without risking your work laptop. No local state to corrupt, no accidental changes to your working branch. The sandbox spins up with the full codebase mirrored and Claude works through the task autonomously. Engineers now run 6 parallel sub-agents in Codespaces for bulk upgrades across 20+ repos: package bumps, migration scripts, test updates, PRs opened. What used to be a full day of copy-paste across repos is done in one session.&lt;/p&gt;

&lt;h3&gt;
  
  
  The new collaboration model
&lt;/h3&gt;

&lt;p&gt;Non-engineer describes the problem in business terms → Claude implements → engineer reviews for architecture and quality. The person closest to the customer now helps ship the solution. Feedback loops tightened dramatically.&lt;/p&gt;

&lt;p&gt;A designer and engineer even deployed &lt;a href="https://www.agentation.com/" rel="noopener noreferrer"&gt;Agentation&lt;/a&gt; (a prompt-structuring tool) in 2.5 hours. The designer now uses it daily and calls it a “dream collaboration.”&lt;/p&gt;




&lt;h2&gt;
  
  
  Guardrails: the hard lesson
&lt;/h2&gt;

&lt;p&gt;A few weeks in, one non-engineer with full GitLab push access bypassed our CI pipeline and deployed code to production without review. No damage, but it was exactly the wake-up call we needed.&lt;/p&gt;

&lt;p&gt;We immediately tightened permissions: non-engineers and agents create PRs; engineers review and merge. No direct push to protected branches.&lt;/p&gt;

&lt;p&gt;But that incident was just one piece. When you give AI agents to 50+ non-engineers, you need a proper governance framework. We built one.&lt;/p&gt;

&lt;h3&gt;
  
  
  What we had from day one
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sandboxed execution only.&lt;/strong&gt; Agents run in Claude Code Web, Codex sandbox, or GitHub Codespaces. No production infrastructure access. No deployment outside CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dedicated bot users.&lt;/strong&gt; Limited API scopes. Code-level access only. Zero access to customer data, session tokens, or production databases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public channels only.&lt;/strong&gt; All agent interactions happen in shared Slack channels. Engineers see everything and can intervene. No private DMs with agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human responsibility.&lt;/strong&gt; You trigger the agent, you own the output. No exceptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What we added after
&lt;/h3&gt;

&lt;p&gt;We published a formal &lt;strong&gt;Agentic AI Tool Usage Guideline&lt;/strong&gt;. The core principle: give the agent the minimum access it needs for the task at hand, and nothing more.&lt;/p&gt;

&lt;p&gt;The guideline includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A three-tier data classification.&lt;/strong&gt; Red (never share with AI): customer PII, session tokens, credentials, security documents. Yellow (anonymise first): user research transcripts, survey responses, usage metrics with identifiers. Green (safe): public docs, your own drafts, anonymised research, process docs. Hard line on red: no exceptions, no "just this once."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An approved connector matrix.&lt;/strong&gt; Every tool combination (Claude + Figma, Claude + Atlassian, Claude + Miro, etc.) classified by risk level with specific conditions and recommended settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt injection awareness.&lt;/strong&gt; Use a separate browser profile for Claude browser extension. Don't paste content from untrusted sources into agent prompts. Disconnect MCP connectors when not in use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit dealbreakers.&lt;/strong&gt; Leaking customer personal data, unauthorized code deployment, and feeding company data into model training are not allowed regardless of how useful the outcome might be.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GDPR and EU AI Act compliance.&lt;/strong&gt; The guideline maps our practical rules to specific legal obligations: data minimisation (Art. 5), DPA requirements (Art. 28), AI literacy obligations (Art. 4), transparency requirements (Art. 50). We're a European company serving energy utilities. Regulatory compliance is table stakes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: Lock down merge and push permissions &lt;em&gt;before&lt;/em&gt; opening access. We got lucky. And build the governance framework early. Guardrails didn't slow adoption; they accelerated trust and usage.&lt;/p&gt;




&lt;h2&gt;
  
  
  What surprised us most
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adoption speed&lt;/strong&gt;: Three one-hour onboarding sessions and people were off. Every team across the company had active contributors within three weeks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-engineers shipping real features&lt;/strong&gt;: I expected small fixes and translations. Instead, people from across the company delivered complete, production features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude as institutional memory&lt;/strong&gt;: Support now asks Claude product questions instead of hunting down engineers. It has become the fastest way to understand how anything works across five years of code history.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Beyond code
&lt;/h2&gt;

&lt;p&gt;This is just one layer. My colleague Suresh built &lt;strong&gt;Vigilos&lt;/strong&gt;, an internal BI agent that lets anyone query our data warehouse in natural language. Designers check average journey name lengths for UX decisions. Customer success identifies accounts with AI features disabled. Product managers run customer segment analysis in minutes.&lt;/p&gt;

&lt;p&gt;We'll share that story soon.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where this goes
&lt;/h2&gt;

&lt;p&gt;Two years ago I published the Product Engineer Manifesto: engineers should care about the customer, the business outcome, and the whole product.&lt;/p&gt;

&lt;p&gt;What these two months taught me is that the same mindset now applies in reverse. Give non-engineers the right tools, deep context, and sensible guardrails, and they will deliver.&lt;/p&gt;

&lt;p&gt;We're still hiring product-minded engineers. That hasn't changed. Engineers at epilot own the full product lifecycle: customer understanding, architecture, quality, reliability, and shipping. Non-engineer contributions don't reduce what we expect from engineers. They amplify it. The entire organization now ships alongside them.&lt;/p&gt;

&lt;p&gt;629 merged PRs in 60 days. 40 from non-engineers.&lt;/p&gt;




&lt;p&gt;We're hiring all product roles who thrive on full ownership in an AI-native environment. Remote-first. &lt;a href="https://www.epilot.cloud/en/company/careers" rel="noopener noreferrer"&gt;epilot.cloud/careers&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>product</category>
    </item>
    <item>
      <title>We Made Coding Agents Actually Reliable By Fixing One Thing</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Wed, 04 Feb 2026 15:55:45 +0000</pubDate>
      <link>https://dev.to/epilot/we-made-coding-agents-actually-reliable-by-fixing-one-thing-525b</link>
      <guid>https://dev.to/epilot/we-made-coding-agents-actually-reliable-by-fixing-one-thing-525b</guid>
      <description>&lt;p&gt;Last week, Vercel published &lt;a href="https://vercel.com/blog/agents-md-outperforms-skills-in-our-agent-evals" rel="noopener noreferrer"&gt;research showing that giving coding agents a compact index of your documentation dramatically outperforms letting them search for answers on demand&lt;/a&gt;. Their eval results: 100% task success rate with the map approach, versus only 79% when agents had to actively look things up.&lt;/p&gt;

&lt;p&gt;Same agent, same tasks, different approach to context. The difference between working and not working.&lt;/p&gt;

&lt;p&gt;The insight clicked immediately. If we could give Claude Code reliable access to this institutional knowledge without forcing it to decide when to look things up, it would fundamentally change how people work in our codebase.&lt;/p&gt;

&lt;p&gt;So we built it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Context Problem
&lt;/h2&gt;

&lt;p&gt;Coding agents have a token limit. A ceiling on how much information they can process at once. Think of it like working memory. You can't hand Claude Code your entire codebase and documentation library upfront. It's too much.&lt;/p&gt;

&lt;p&gt;The traditional solution is skills: the coding agent decides when it needs information and actively looks it up. "I need to know about authentication, let me search for that." Sounds reasonable. In practice it creates three problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Decision paralysis&lt;/strong&gt; - the agent has to decide &lt;em&gt;when&lt;/em&gt; to look up docs, and it often guesses wrong&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async delay&lt;/strong&gt; - every lookup is a round-trip, breaks flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sequencing conflicts&lt;/strong&gt; - exploring code vs. consulting docs creates timing issues&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Vercel's approach flips this: give Claude Code a compressed index of what documentation exists and where to find it, &lt;em&gt;before&lt;/em&gt; it starts work. The index is small enough to fit in context every turn, so it always knows what's available. When it needs details, it reads the specific file directly. No decisions, no lookups, no conflicts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Compression Matters
&lt;/h2&gt;

&lt;p&gt;The key innovation is compression. A full documentation tree - all the folder structures, file names, categories - takes significant space. Too much to include in every conversation turn.&lt;/p&gt;

&lt;p&gt;The compressed index uses a simple pipe-delimited format that shrinks this by ~80%:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[epilot Docs Index]|root: ./.epilot-docs|00-general:{tech-stack.md,business-context.md,ci-cd.md}|01-apis:{api-design.md,calling-apis.md}|02-epilot360-microfrontends:{env-vars.md,local-dev.md}|...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single line tells the agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where the docs live (&lt;code&gt;.epilot-docs/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;What categories exist (&lt;code&gt;00-general&lt;/code&gt;, &lt;code&gt;01-apis&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;What files are in each category&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a table of contents, not the full book. But it's enough. The agent sees the map, understands what's available, and pulls specific files when needed. The decision-making load disappears.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2smftr4lr0o3jpr0xtxp.png" class="article-body-image-wrapper"&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.amazonaws.com%2Fuploads%2Farticles%2F2smftr4lr0o3jpr0xtxp.png" alt="Claude code actually reading docs for once before jumping into code" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;The accuracy improvement is significant (100% vs 79% task success), but it's not the real story.&lt;/p&gt;

&lt;p&gt;The real story is what happens when you lower the barrier to contribution. Proper context enables the person closest to the problem to fix it, regardless of job title. Your PM can fix bugs. Designers can adjust component behavior. Support engineers can patch data issues. You remove bottlenecks. Context and authority live in the same person.&lt;/p&gt;

&lt;p&gt;Coding agents are the equalizer. But they're only as good as the context you give them.&lt;/p&gt;

&lt;p&gt;Most companies will throw Claude Code at their codebase and wonder why results are inconsistent. The agent hallucinates patterns. Makes incorrect assumptions. Writes code that doesn't match conventions.&lt;/p&gt;

&lt;p&gt;The difference is context. Structured, compressed, always-available context about how &lt;em&gt;your&lt;/em&gt; codebase works.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Build Your Own
&lt;/h2&gt;

&lt;p&gt;The pattern is straightforward. Here's what we did at epilot:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Curate agent-friendly documentation&lt;/strong&gt; - organize your internal knowledge: conventions, APIs, architectural patterns, framework usage, code style&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structure by domain&lt;/strong&gt; - group related docs (general, backend, frontend, infrastructure, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use descriptive filenames&lt;/strong&gt; - the agent sees filenames in the compressed index before opening files. &lt;code&gt;api-design.md&lt;/code&gt; is better than &lt;code&gt;guidelines.md&lt;/code&gt;. &lt;code&gt;error-handling.md&lt;/code&gt; is better than &lt;code&gt;errors.md&lt;/code&gt;. Make filenames searchable and specific.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate updates&lt;/strong&gt; - pull live data where possible (OpenAPI specs, schema definitions, framework docs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate compressed index&lt;/strong&gt; - use a simple format (pipe-delimited works well) that reduces the doc tree by ~80%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embed in agent context&lt;/strong&gt; - add the index to your CLAUDE.md or AGENTS.md file (the context files Claude Code reads)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One thing worth highlighting: we don't just include our internal documentation. We also package docs for the frameworks and libraries we heavily use - single-spa, openapi-backend, openapi-client-axios, i18next, and Volt UI (our custom design system). When Claude Code needs to know how i18next pluralization works or how to register a single-spa parcel, it already has the answer. No hallucination, no outdated Stack Overflow posts, just accurate framework documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Enables
&lt;/h2&gt;

&lt;p&gt;We're already seeing daily usage across the team. Developers context-switch between services faster. Non-engineers contribute directly instead of filing tickets.&lt;/p&gt;

&lt;p&gt;But the real potential is broader: if compressed context improves coding agents for technical documentation, why stop there?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runbooks and incident response&lt;/strong&gt; - on-call engineers with instant access to procedures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer domain knowledge&lt;/strong&gt; - support teams with context on product behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business logic&lt;/strong&gt; - product decisions and their rationale, preserved and accessible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern is the same: curate the knowledge, compress it, embed it in context, let the agent work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Constraints Are Disappearing
&lt;/h2&gt;

&lt;p&gt;For decades, contributing to a codebase required deep technical knowledge. You needed to understand the language, the frameworks, the architectural patterns, the implicit conventions. The barrier was high.&lt;/p&gt;

&lt;p&gt;Coding agents lower it. Claude Code, Cursor, and similar tools don't replace engineers. They make technical knowledge more accessible. With the right tooling and the right context, a PM can fix bugs. A designer can adjust styling logic. A support engineer can patch data issues.&lt;/p&gt;

&lt;p&gt;The question isn't whether this is possible. It's how fast you can adapt.&lt;/p&gt;

&lt;p&gt;Organizations which enable broader contribution will move faster than those that don't. The tools exist. The research is clear. What's missing is execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Simple
&lt;/h2&gt;

&lt;p&gt;You don't need to document everything upfront. Start with the knowledge that causes the most friction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code style conventions&lt;/strong&gt; - how you write TypeScript, naming patterns, file structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Common patterns&lt;/strong&gt; - how you handle authentication, API calls, error handling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework specifics&lt;/strong&gt; - non-obvious usage of your frameworks and libraries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal APIs&lt;/strong&gt; - if you have OpenAPI specs, even better&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a simple doc structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/
  00-general/
    code-style.md
    tech-stack.md
  01-apis/
    api-design.md
    calling-apis.md
  02-backend/
    error-handling.md
    database-patterns.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate the compressed index (pipe-delimited format, one line per directory). Add it to your CLAUDE.md or AGENTS.md file - the context files that Claude Code and other coding agents read on startup. Done.&lt;/p&gt;

&lt;p&gt;The compressed index approach works! 🎉 Vercel's research proved it: 100% task success versus 79% without it. We've validated it internally. Now it's about whether you'll adopt it before your competitors do.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>coding</category>
      <category>documentation</category>
    </item>
    <item>
      <title>Dealing with Pushback to Product Engineering</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Tue, 08 Apr 2025 13:34:33 +0000</pubDate>
      <link>https://dev.to/epilot/dealing-with-pushback-to-product-engineering-431o</link>
      <guid>https://dev.to/epilot/dealing-with-pushback-to-product-engineering-431o</guid>
      <description>&lt;p&gt;I was recently confronted by a product engineer colleague here at epilot, frustrated with some of his non-engineer colleagues who didn't seem to buy into the idea of involving engineers in the product process from the start.&lt;/p&gt;

&lt;p&gt;An all too familiar and frustrating situation for many of us.&lt;/p&gt;

&lt;p&gt;You think of yourself as a proud product engineer wanting to solve meaningful problems but then get slapped with a detailed feature specification designed by a group of non-developers without your input. Now they expect you to go deliver their vision.&lt;/p&gt;

&lt;p&gt;This is very much the reality in most product teams. Calling yourself a product engineer doesn’t automatically mean your voice will be welcomed. And that’s totally okay.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ideal vs. the Reality
&lt;/h2&gt;

&lt;p&gt;In my past writings, I've painted the ideal: engineers who understand customer needs, question roadmaps, challenge designs, and contribute beyond code. But the reality is often much messier.&lt;/p&gt;

&lt;p&gt;Some PMs and designers love working closely with engineers. Others are still adjusting to the idea. And that’s fair. The product engineer mindset definitely isn’t the norm.&lt;/p&gt;

&lt;p&gt;Let’s not forget, PMs and designers are often under pressure too. It’s only natural they sometimes default to the most familiar and streamlined path. One that doesn’t always include engineers in the early stages.&lt;/p&gt;

&lt;p&gt;And let’s be honest. Sometimes engineers haven’t yet built the trust or skills to contribute meaningfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Friction Is Normal
&lt;/h2&gt;

&lt;p&gt;The moment you step outside your lane, you shouldn’t be surprised when the reaction isn’t overwhelmingly supportive.&lt;/p&gt;

&lt;p&gt;You will face skepticism.&lt;/p&gt;

&lt;p&gt;You might be seen as overstepping.&lt;/p&gt;

&lt;p&gt;You will encounter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requests to give estimates for implementing someone else's design&lt;/li&gt;
&lt;li&gt;Roadmaps shared as top-down mandates&lt;/li&gt;
&lt;li&gt;UI prototypes handed over "ready for dev", expecting pixel-perfect implementation&lt;/li&gt;
&lt;li&gt;Pushback from asking too many questions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the price of wanting to do more than just execute. And if we’re honest, many of us haven’t always shown up in these conversations in a way that earns trust.&lt;/p&gt;

&lt;p&gt;Is this a culture problem? Not necessarily. Most teams don’t have a rule against engineers joining product discussions. It’s just not the default. It’s less about policy and more about patterns. Changing those patterns takes trust, initiative, and persistence.&lt;/p&gt;

&lt;p&gt;At the end of the day, it’s the product engineer’s job to show that product engineering actually works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Earn the Trust
&lt;/h2&gt;

&lt;p&gt;Calling yourself a product engineer isn’t a free pass. No one hands you a seat at the product table just because you want it. You must earn it. Show, don’t tell.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do the homework. Know the names of your customers. Know the business domain.&lt;/li&gt;
&lt;li&gt;Talk to your colleagues, not just other devs. Find opportunities to interact with customers.&lt;/li&gt;
&lt;li&gt;Ask helpful questions that sharpen the team's product thinking.&lt;/li&gt;
&lt;li&gt;Dive into data. Gather insights. Find new metrics and ways to collect useful signals.&lt;/li&gt;
&lt;li&gt;Bring value to the table. Demonstrate you understand the customer problem by making thoughtful proposals that move the product forward.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You need to show up in demos, RFCs, testing sessions, and reviews. Not just in code commits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bother?
&lt;/h2&gt;

&lt;p&gt;Because it’s worth it.&lt;/p&gt;

&lt;p&gt;We do this for our own professional pride. To put great products into the hands of happy customers. And into our portfolios.&lt;/p&gt;

&lt;p&gt;We don’t challenge product decisions because we want to take over the PM’s job or undermine the work of our teammates. We do it because we care about impact. Because we want our effort to count.&lt;/p&gt;

&lt;p&gt;Because it hurts to pour weeks of your life into something that doesn't work, only to discover it failed because no engineer was involved in the concept phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Leverage
&lt;/h2&gt;

&lt;p&gt;And here’s something to remember: &lt;strong&gt;We, as engineers, hold real leverage.&lt;/strong&gt; We are the only ones who can actually turn product decisions into reality. No idea ships without us.&lt;/p&gt;

&lt;p&gt;So while we may not always get a say by default, we do get a say in how we show up and how deeply we choose to care.&lt;/p&gt;

&lt;p&gt;Use that leverage wisely. And proudly.&lt;/p&gt;

</description>
      <category>productengineer</category>
      <category>career</category>
    </item>
    <item>
      <title>The Sauna Epiphany: How I Got Product Engineering Wrong</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Sun, 13 Oct 2024 12:23:43 +0000</pubDate>
      <link>https://dev.to/epilot/the-sauna-epiphany-how-i-got-product-engineering-wrong-35jg</link>
      <guid>https://dev.to/epilot/the-sauna-epiphany-how-i-got-product-engineering-wrong-35jg</guid>
      <description>&lt;p&gt;If you've seen my posts lately you've probably seen a lot of talk about &lt;em&gt;Product Engineers&lt;/em&gt;: software engineers who talk in customer problems and take pride in the products they build, not only the code and technologies they use.&lt;/p&gt;

&lt;p&gt;My core thesis is that with the rise of AI, the expectations for software engineers are being redefined, moving away from narrow programming roles: backend, frontend, C#, Java, React, etc. fast becoming obsolete due to AI tools like &lt;a href="https://www.cursor.com/" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt; lowering the barrier of entry and unlocking productivity with any technology.&lt;/p&gt;

&lt;p&gt;The days when you could coast on your ability to churn out code are over. If you're still clinging to the idea that you're safe just because you know how to write code in a widely used language or framework you're in for a rude awakening.&lt;/p&gt;

&lt;p&gt;I believe this trend is likely to be the biggest industry shift in my lifetime, even surpassing the agile movement of the last 20 years. And I'm not the only one talking about it. (&lt;a href="https://blog.pragmaticengineer.com/the-product-minded-engineer/" rel="noopener noreferrer"&gt;#1&lt;/a&gt;, &lt;a href="https://hybridhacker.email/p/how-to-become-a-product-engineer" rel="noopener noreferrer"&gt;#2&lt;/a&gt;, &lt;a href="https://thesoftwareengineeringtimes.substack.com/p/are-product-engineers-replacing-software" rel="noopener noreferrer"&gt;#3&lt;/a&gt;, &lt;a href="https://saranga.dev/from-code-monkey-to-product-engineer-the-evolution-of-software-engineering-in-the-age-of-llms-3c79a508464d" rel="noopener noreferrer"&gt;#4&lt;/a&gt;, &lt;a href="https://thesoftwareengineeringtimes.substack.com/p/are-product-engineers-replacing-software" rel="noopener noreferrer"&gt;#5&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;But I got it wrong.&lt;/p&gt;

&lt;p&gt;Not entirely wrong, but I made it more complicated than it needed to be. In my quest to define what it means to be a product engineer, I overlooked the power of simplicity and ironically did not think enough about the customer: the ambitious software engineer thinking strategically about their careers.&lt;/p&gt;

&lt;h2&gt;
  
  
  I overengineered it
&lt;/h2&gt;

&lt;p&gt;In my earlier attempts to help engineers break out from purely technical roles, I published an extensive checklist to help engineers think and ask questions as product engineers. It covered everything from understanding the user and the market to measuring success and staying ahead of industry trends.&lt;/p&gt;

&lt;p&gt;Here's a taste of that checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#1-understand"&gt;1 Understand&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#11-whos-the-user"&gt;1.1 Who's the user?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#12-whos-the-customer"&gt;1.2 Who's the customer?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#13-whats-the-market"&gt;1.3 What's the market?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#14-ask-why"&gt;1.4 Ask Why&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#15-what-do-we-already-know"&gt;1.5 What do we already know?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#2-craft"&gt;2 Craft&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#21-am-i-proud-of-what-im-building"&gt;2.1 Am I proud of what I'm building?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#22-does-the-product-feel-good"&gt;2.2 Does the product feel good?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#23-how-do-i-get-there-faster"&gt;2.3 How do I get there faster?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#24-teamwork"&gt;2.4 Teamwork&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#3-growth"&gt;3 Growth&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#31-how-do-i-measure-the-success-of-my-work"&gt;3.1 How do I measure the success of my work?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#32-how-do-i-maximise-the-impact-of-my-work"&gt;3.2 How do I maximise the impact of my work?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#33-how-do-i-stay-ahead-of-the-curve"&gt;3.3 How do I stay ahead of the curve?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#4-product-vision"&gt;4 Product Vision&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#41-whats-our-north-star"&gt;4.1 What’s our North Star?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#42-how-does-my-work-impact-the-overall-design-of-the-product"&gt;4.2 How does my work impact the overall design of the product?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/epilot/the-product-engineer-checklist-469d#43-whats-the-ambition-level"&gt;4.3 What's the ambition level?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Great stuff, but let's be honest — no engineer is going to run through a 15-point checklist to make a product decision. Just seeing this long list of questions can be totally overwhelming, especially if you're used to being in a technical role.&lt;/p&gt;

&lt;p&gt;If we expect engineers to actually start doing this stuff, the core idea needs to be simple and easy to remember.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wake-Up Call in the Sauna
&lt;/h2&gt;

&lt;p&gt;As I'm writing this post, I'm enjoying a company working vacation in a nice hotel in Mallorca with my epilot colleagues. I was having a conversation in the hotel sauna with a principal engineer where something he said in passing suddenly clicked for me.&lt;/p&gt;

&lt;p&gt;He was venting about some engineers on his team who seemed to be diving head first into coding without bothering to understand the problem. &lt;em&gt;"It's so easy. Every engineer should be able to answer what problem they're solving, who the customer is, and what the impact of the work they're doing is."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That hit me like a splash of cold water in a 100°C Finnish sauna.&lt;/p&gt;

&lt;p&gt;He was totally right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boiling It Down to 3 Essential Questions
&lt;/h2&gt;

&lt;p&gt;To think like a product engineer, it's already enough to start with just three simple questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What's the problem?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For who?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why is this important?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dive a bit deeper into each one.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. What's the problem?
&lt;/h3&gt;

&lt;p&gt;Stop coding for a second. Do you really know what you're trying to solve? Not the ticket description in Jira, but the real-world issue. If you can't articulate the problem in simple plain English, you have no business writing a single line of code.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. For who?
&lt;/h3&gt;

&lt;p&gt;Identify your user and customer. Sometimes they're the same person; other times, they're not. Understanding who will use your product (and who will pay for it) is crucial. It shapes the way you approach the solution and helps you tailor the experience to meet their needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Why is this important?
&lt;/h3&gt;

&lt;p&gt;As engineers there's never a shortage of things we could improve or implement. If solving the problem doesn't make a meaningful difference, why are you wasting your valuable time? We're not here to build features that nobody uses or cares about. Connect your work to something that actually matters and helps build your track record.&lt;/p&gt;

&lt;p&gt;By anchoring your work in these three questions, you immediately move from code monkey to a high value product-minded engineer. Still a rare breed. You're not just implementing features someone else decided to build; you're elevating yourself to a position to influence product decisions and build smarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leverage Your Team—They're There for a Reason
&lt;/h2&gt;

&lt;p&gt;The biggest mistake engineers make is thinking they have to find all the answers themselves.&lt;/p&gt;

&lt;p&gt;Most of us are lucky to work in a product team with other disciplines like UX researchers, designers, PMs and business stakeholders whose job is to help answer these questions.&lt;/p&gt;

&lt;p&gt;By leaning on your team, you not only find better answers but also foster a more collaborative and innovative environment.&lt;/p&gt;

&lt;p&gt;Product engineering is a team sport.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking Action: Start Asking the Right Questions Today
&lt;/h2&gt;

&lt;p&gt;So, the next time you tackle a new topic, pause for a moment before diving into code. Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What's the problem?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For who?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why is this important?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write down your answers. If you don't know, reach out to your team and find out. This simple practice can transform your approach to work, leading to better decisions, more impactful solutions, and a greater sense of ownership.&lt;/p&gt;

&lt;p&gt;Congratulations, you just became a Product Engineer! &lt;/p&gt;

&lt;h2&gt;
  
  
  Join the Conversation
&lt;/h2&gt;

&lt;p&gt;I'd love to hear your thoughts on this simplified approach to product engineering. Have you tried asking these three questions in your work? What impact did it have? Share your experiences in the comments below.&lt;/p&gt;

&lt;p&gt;Consider giving the &lt;a href="https://github.com/anttiviljami/product-engineer-manifesto" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; a star if the product engineer role resonates with you!&lt;/p&gt;

</description>
      <category>product</category>
      <category>ai</category>
      <category>sauna</category>
    </item>
    <item>
      <title>Bullshit Tech Roles (satire)</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Tue, 09 Jul 2024 23:50:55 +0000</pubDate>
      <link>https://dev.to/anttiviljami/bullshit-tech-roles-satire-54f</link>
      <guid>https://dev.to/anttiviljami/bullshit-tech-roles-satire-54f</guid>
      <description>&lt;p&gt;In any sufficiently well-funded or otherwise successful tech company, a set of new roles will inevitably emerge—so crucial and revered by our industry that they've practically transcended the need to produce any tangible work. These roles specialize in the fine art of enabling others, in the hopes that, one day, the actual builders might be enabled enough to deliver products to customers.&lt;/p&gt;

&lt;p&gt;I'm talking, of course, about the agile coaches and scrum masters, the architects and platform engineers; the growth hackers and data-driven researchers. These vanguards of innovation are vital to any team that wants to maintain a perpetual state of being maximally enabled, well-informed, and facilitated to perform their work.&lt;/p&gt;

&lt;p&gt;Let's begin with the often underappreciated roles of agile coaches and scrum masters, the only people in a company actually certified™️ to set up the correct processes and tools to run an agile team. This, of course, is paramount for implementing agile—the popular software development philosophy that explicitly tells us to avoid focusing on processes and tools.&lt;/p&gt;

&lt;p&gt;Agile coaches and scrum masters are professionals whose primary job is to ensure all work in teams is performed in sprints, with daily stand-up meetings to guarantee everyone is constantly enabled. This allows the velocity of a team to be meticulously measured in story points, which no one quite understands, but hey, at least we're definitely data-driven.&lt;/p&gt;

&lt;p&gt;Surely, without their meticulous facilitation, teams would be left wandering aimlessly, unsure of how to break down their work into JIRA tickets. Their presence ensures that everyone stays aligned and that every team member is reminded of their blockers and sprint goals every single morning. Because nothing screams productivity like a daily stand-up where everyone takes turns saying, "no updates from my side."&lt;/p&gt;

&lt;p&gt;Next, we have the architects. These exceptionally gifted, usually very senior engineers haven't touched any production code in the current decade. They are often found in their natural habitat, PowerPoint, where they sketch out their grand visions of future systems and envision platform rewrites for actual software engineers to implement.&lt;/p&gt;

&lt;p&gt;Their role is to think so far ahead that their ideas become completely theoretical, creating software designs that are so advanced, they may never actually be implemented. But that's not the point. The point is to have a shared vision, to inspire, to draw boxes and lines that will one day guide the hands of actual engineers who might one day understand what they were trying to convey.&lt;/p&gt;

&lt;p&gt;Then, there are the platform engineers. A demanding role with zero responsibility to deliver anything of value to customers. These unsung heroes dedicate their time to building and maintaining the internal tools and infrastructure that supposedly makes everyone else's job easier. Yet, their true skill lies in making things so complicated that only they can understand and manage them.&lt;/p&gt;

&lt;p&gt;They manage infrastructure, design intricate CI/CD pipelines, common libraries and tools that add layers upon layers of necessary abstraction, which they insist must be adopted and standardized across all teams. The result? All teams having to learn and depend on custom in-house tools so complex that even the slightest changes require a detailed consultation with the platform team, ensuring their perpetual job security.&lt;/p&gt;

&lt;p&gt;And then we have the growth hackers, the avant-garde marketers of the tech world. Their job is to come up with innovative ways to "hack" company growth, often resorting to questionable methods that straddle the line between clever marketing and outright deceit. They dive into data, running A/B tests, tweaking landing pages, and optimizing user funnels to squeeze out the tiniest incremental gains.&lt;/p&gt;

&lt;p&gt;Of course, the real growth usually comes from the core product being genuinely useful, but why let that overshadow the need for an entire team devoted to marginal tweaks and vanity metrics?&lt;/p&gt;

&lt;p&gt;Data-driven researchers are the prophets of the modern tech age. Armed with vast amounts of data and research, they uncover profound insights such as "users prefer faster load times" or "clearer buttons improve user engagement." Their work truly brings scientific rigor, managing to bring impressive-sounding numbers and great data visualizations to argue for any side of a decision, usually the one they already went with before doing any research.&lt;/p&gt;

&lt;p&gt;These bullshit roles are the pillars upon which modern tech companies stand. They enable a culture where productivity is constantly measured, documented, and discussed, albeit often at the expense of actual productivity.&lt;/p&gt;

&lt;p&gt;Without them, who would ensure that calendars get filled with back-to-back meetings so that everyone is too busy to notice no work is getting done? Who would write all the documents and Slack messages, ensuring no detail is left unshared or undiscussed? In doing so, these roles truly create a seamless, endless flow of communication, although one might argue that less talk and more doing might yield better results. &lt;/p&gt;

&lt;p&gt;But where's the fun in that?&lt;/p&gt;

</description>
      <category>satire</category>
      <category>techjobs</category>
    </item>
    <item>
      <title>The Product Engineer Checklist</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Tue, 04 Jun 2024 09:34:22 +0000</pubDate>
      <link>https://dev.to/epilot/the-product-engineer-checklist-469d</link>
      <guid>https://dev.to/epilot/the-product-engineer-checklist-469d</guid>
      <description>&lt;p&gt;&lt;em&gt;Download the PDF at &lt;a href="https://productengineer.org" rel="noopener noreferrer"&gt;productengineer.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Think Like a Product Engineer
&lt;/h2&gt;

&lt;p&gt;The following is a checklist of questions for product engineers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
1 Understand

&lt;ul&gt;
&lt;li&gt;1.1 Who's the user?&lt;/li&gt;
&lt;li&gt;1.2 Who's the customer?&lt;/li&gt;
&lt;li&gt;1.3 What's the market?&lt;/li&gt;
&lt;li&gt;1.4 Ask Why&lt;/li&gt;
&lt;li&gt;1.5 What do we already know?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

2 Craft

&lt;ul&gt;
&lt;li&gt;2.1 Am I proud of what I'm building?&lt;/li&gt;
&lt;li&gt;2.2 Does the product feel good?&lt;/li&gt;
&lt;li&gt;2.3 How do I get there faster?&lt;/li&gt;
&lt;li&gt;2.4 Teamwork&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

3 Growth

&lt;ul&gt;
&lt;li&gt;3.1 How do I measure the success of my work?&lt;/li&gt;
&lt;li&gt;3.2 How do I maximise the impact of my work?&lt;/li&gt;
&lt;li&gt;3.3 How do I stay ahead of the curve?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

4 Product Vision

&lt;ul&gt;
&lt;li&gt;4.1 What’s our North Star?&lt;/li&gt;
&lt;li&gt;4.2 How does my work impact the overall design of the product?&lt;/li&gt;
&lt;li&gt;4.3 What's the ambition level?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  1 Understand
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1.1 Who's the user?
&lt;/h2&gt;

&lt;p&gt;As a product engineer, your #1 goal is to create happy users. These are your fans! Always start with the user!&lt;/p&gt;

&lt;p&gt;Your user is the person that primarily interacts with your product and whose experience your work will directly impact. &lt;/p&gt;

&lt;p&gt;You may have multiple user groups. People who may have varying reasons to use your product or might interact with it in different ways from different angles, maybe on different kinds of devices.&lt;/p&gt;

&lt;p&gt;You should understand how to help these users. What drives them to use your product? What delights them? What are their pains?&lt;/p&gt;

&lt;p&gt;As a product engineer you should demand and support your team find answers to these questions before jumping into writing code. &lt;/p&gt;

&lt;h2&gt;
  
  
  1.2 Who's the customer?
&lt;/h2&gt;

&lt;p&gt;Yes, this is a different question to "Who’s the user?". The customer is whoever pays for your product, not always who uses it.&lt;/p&gt;

&lt;p&gt;You should know what makes your product valuable to your customers to make better decisions on what to invest your time.&lt;/p&gt;

&lt;p&gt;Hint: If you're in B2B the answer always has to do with helping your customers save money or make more money. Understanding your customers' core business is key to understanding why they would pay for your product.&lt;/p&gt;

&lt;p&gt;Most importantly, you want to make whoever is paying for your product look good. After all, they're the ones taking a risk by picking your product. You ALWAYS want to reward them for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.3 What's the market?
&lt;/h2&gt;

&lt;p&gt;Zooming out, let's take a look at the wider market landscape. Who are the potential customers we haven’t captured yet? Why would a customer pick a competitor’s product vs. mine? Are we leaving opportunities on the table?&lt;/p&gt;

&lt;p&gt;What can I learn from similar products in the market? What are our USPs? How do I create a competitive advantage against competition?&lt;/p&gt;

&lt;p&gt;Are there rules to the market? Are there regulations or industry standards I need to know about? Does my product have to look or feel a certain way to be taken seriously?&lt;/p&gt;

&lt;p&gt;Knowing the market and regularly bechmarking yourself against other players helps become aware of your strengths and weaknesses and give ideas for where to invest strategically in your own product.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.4 Ask Why
&lt;/h2&gt;

&lt;p&gt;This is a bit of a product thinking cliche but still holds true: always pays to ask “why” a few times to uncover root causes of problems and underlying motivations.&lt;/p&gt;

&lt;p&gt;Asking why can be helpful in almost any situation to build understanding in your team. Some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why should we invest into building this feature?&lt;/li&gt;
&lt;li&gt;Why are customers asking for this feature?&lt;/li&gt;
&lt;li&gt;Why is this a pain for our users?&lt;/li&gt;
&lt;li&gt;Why do users give us that feedback?&lt;/li&gt;
&lt;li&gt;Why now?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1.5 What do we already know?
&lt;/h2&gt;

&lt;p&gt;It’s smart to build on what’s already known rather than always starting from scratch.&lt;/p&gt;

&lt;p&gt;Always leverage the existing knowledge and experience of peers and leaders: founders, product leadership, designers, other product engineers, etc.&lt;/p&gt;

&lt;p&gt;Examine the status quo to see how a problem is currently solved. Look at ideas, feedback, metrics, KPIs already collected in the past.&lt;/p&gt;

&lt;p&gt;Do we have users already doing something like this? What are their existing workflows? How could we improve their experience?&lt;/p&gt;

&lt;p&gt;Am I duplicating or potentially deprecating some functionality that already exists? Could this be achieved by extending or leveraging existing features? How are competitors solving this?&lt;/p&gt;

&lt;h2&gt;
  
  
  2 Craft
&lt;/h2&gt;

&lt;h2&gt;
  
  
  2.1 Am I proud of what I'm building?
&lt;/h2&gt;

&lt;p&gt;Your track record as a product engineer is the products and features you've delivered. Your last feature represents your professional competence level. No excuses.&lt;/p&gt;

&lt;p&gt;Ask yourself what quality standard do I want to set for the work I put out there?&lt;/p&gt;

&lt;p&gt;Can I be proud of the product I worked on? Is my work well tested and polished? Did I cut corners where I shouldn't have?&lt;/p&gt;

&lt;p&gt;As a highly paid professional engineer your craft is to produce high quality software which includes avoiding the creation of technical debt. Never ask for permission to improve quality!&lt;/p&gt;

&lt;p&gt;What makes a great product engineer stand out from the average software engineer is an intense sense of professional pride in their work and product.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.2 Does the product feel good?
&lt;/h2&gt;

&lt;p&gt;This may be a slightly controversial take, but I believe a surprisingly large part of building great products is about developing a good taste for it.&lt;/p&gt;

&lt;p&gt;Simply knowing the difference between great vs. average and not settling for just ”ok” helps tremendously in making good decisions as a product engineer.&lt;/p&gt;

&lt;p&gt;Does the product feel smooth and consistent? Is it intuitive, simple, and familiar to the user? Or does it feel cheap and janky?&lt;/p&gt;

&lt;p&gt;Note that this doesn’t only concern the visual aspects of your product. Just slapping a fancy UI design on a shaky foundation doesn’t create a great experience.&lt;/p&gt;

&lt;p&gt;Simple. Elegant. Clean. This is what we're after as product engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.3 How do I get there faster?
&lt;/h2&gt;

&lt;p&gt;The pace of innovation especially in software is so rapid that in order to be competitive you must deliver fast, early and often.&lt;/p&gt;

&lt;p&gt;Too slow and your customers will lose trust in you while your competitors overtake you.&lt;/p&gt;

&lt;p&gt;What many get wrong about agile and building products is optimizing for predictability with estimates and roadmaps. Rather, what you really should care about is visible and continuous progress towards product goals.&lt;/p&gt;

&lt;p&gt;The goal of estimates should not be to try to be as accurate as possible but rather to set ambitious and yet achievable goals for yourself.&lt;/p&gt;

&lt;p&gt;The question is not how long you think it will take to build, but how long should it take? What’s an acceptable amount of time and effort I should invest on this?&lt;/p&gt;

&lt;p&gt;What’s the rollout strategy? How do I get this into customers' hands as soon as possible? What’s the MVP?&lt;/p&gt;

&lt;h2&gt;
  
  
  2.4 Teamwork
&lt;/h2&gt;

&lt;p&gt;Building products is a team sport. &lt;/p&gt;

&lt;p&gt;You are absolutely not expected to work alone and do everything yourself from writing code to doing user research. &lt;/p&gt;

&lt;p&gt;Am I effectively communicating with my team? Am I leveraging my team members' strengths? Are we celebrating our successes?&lt;/p&gt;

&lt;p&gt;Great teamwork results in great products. Invest in your team, and you will see the dividends in your product's success.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 Growth
&lt;/h2&gt;

&lt;h2&gt;
  
  
  3.1 How do I measure the success of my work?
&lt;/h2&gt;

&lt;p&gt;Our work as product engineers is not just about building and shipping feature after feature. &lt;/p&gt;

&lt;p&gt;We make educated guesses about the most valuable thing to work on, so we should also be able to answer the question: What’s the impact of my work?&lt;/p&gt;

&lt;p&gt;How many customers did we talk to to validate our progress? Are they coming back? How much money does it generate?&lt;/p&gt;

&lt;p&gt;Use analytics tools and user feedback to help you understand what’s working and what’s not. Talk to real users to get qualitative insights about the product.&lt;/p&gt;

&lt;p&gt;Most importantly, make sure to share your outcomes openly and transparently. What did I ship in the last few months? What were the results?&lt;/p&gt;

&lt;h2&gt;
  
  
  3.2 How do I maximise the impact of my work?
&lt;/h2&gt;

&lt;p&gt;The most important question you should regularly ask yourself is: am I focused on the right thing?&lt;/p&gt;

&lt;p&gt;Being a good engineer is finding the biggest bottlenecks that hold us back and figuring out how to solve them. You should prioritise your efforts ruthlessly.&lt;/p&gt;

&lt;p&gt;Building products is a team sport. You should actively communicate what you’re working on and why, so that others can help you and keep you accountable. Demo progress frequently and actively seek feedback.&lt;/p&gt;

&lt;p&gt;Don’t fear taking risks. Being bold and taking the lead on delivering new and innovative features you believe in can lead to big wins.&lt;/p&gt;

&lt;p&gt;Ask yourself: How can I align my work with our company goals? How does my work directly benefit our users? Is there a way I can communicate my work better to others to get better feedback?&lt;/p&gt;

&lt;h2&gt;
  
  
  3.3 How do I stay ahead of the curve?
&lt;/h2&gt;

&lt;p&gt;Stay updated on market trends. Attend conferences, read up, follow experts.&lt;/p&gt;

&lt;p&gt;Make sure to research and benchmark competitor products, or other similar products whenever possible.&lt;/p&gt;

&lt;p&gt;Hold frequent retrospectives and brainstorming sessions. Experiment with new ideas. Encourage creativity in your team.&lt;/p&gt;

&lt;p&gt;What are the latest trends in my industry? How can I encourage innovation within my team? Are we taking enough time to learn from our successes &amp;amp; failures?&lt;/p&gt;

&lt;h2&gt;
  
  
  4 Product Vision
&lt;/h2&gt;

&lt;h2&gt;
  
  
  4.1 What’s our North Star?
&lt;/h2&gt;

&lt;p&gt;To align your work in the context of the broader product vision, you should deeply care about what others in the company are doing and saying, making sure you fully understand and are committed to the overall product strategy. Asking “why” is crucial here.&lt;/p&gt;

&lt;p&gt;What are our current product goals? What’s our growth strategy? Where do we want to be in the next 2-5 years?&lt;/p&gt;

&lt;p&gt;When presenting your work it always helps to put it in the context of how it pushes us forward in the big picture. How does my work help us reach our North Star?&lt;/p&gt;

&lt;h2&gt;
  
  
  4.2 How does my work impact the overall design of the product?
&lt;/h2&gt;

&lt;p&gt;Understanding the existing software’s design and architecture decisions helps make sure that your work fits well within the larger product design. Always consider how your work influences and is influenced by other components. &lt;/p&gt;

&lt;p&gt;When adding new functionality, you should ask: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Could this be achieved by extending or leveraging existing core features?&lt;/li&gt;
&lt;li&gt;Does my design follow a consistent style to the rest of the product?&lt;/li&gt;
&lt;li&gt;Am I adding complexity or reducing it? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simplicity is worth fighting for.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.3 What's the ambition level?
&lt;/h2&gt;

&lt;p&gt;It’s a good idea to define the ambition level when setting off to build something new. Are you aiming for an incremental improvement or a revolutionary new functionality? &lt;/p&gt;

&lt;p&gt;Is this feature a USP or a basic expectation? What’s the ROI on building this feature? Does it make sense to spend the effort building this ourselves, or could we use an off the shelf library or service?&lt;/p&gt;

&lt;p&gt;Your time is extremely valuable. Think like an owner: Would you invest your salary to build the feature, or rather on something else?&lt;/p&gt;

&lt;h2&gt;
  
  
  Product Engineer Mindset
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this checklist, you might also like the &lt;a href="https://github.com/anttiviljami/product-engineer-manifesto" rel="noopener noreferrer"&gt;Product Engineer Manifesto on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Consider giving the repository a star if the Product Engineering philosophy resonates with you!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhmagl9ajfaijqjslx0t.png" class="article-body-image-wrapper"&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.amazonaws.com%2Fuploads%2Farticles%2Fuhmagl9ajfaijqjslx0t.png" alt="Product Engineer Mindset" width="677" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>product</category>
      <category>engineer</category>
    </item>
    <item>
      <title>What is a Product Engineer?</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Thu, 29 Feb 2024 08:04:56 +0000</pubDate>
      <link>https://dev.to/epilot/what-is-a-product-engineer-1kpg</link>
      <guid>https://dev.to/epilot/what-is-a-product-engineer-1kpg</guid>
      <description>&lt;p&gt;&lt;em&gt;Read the full Product Engineer Manifesto at &lt;a href="https://productengineer.org" rel="noopener noreferrer"&gt;productengineer.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Not Just Coders, but Builders
&lt;/h2&gt;

&lt;p&gt;Picture this: engineers who don't just speak in code but in product design and customer problems. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Product Engineers&lt;/em&gt; are a special breed of engineers that don't just see themselves as coders or developers but as builders who deeply care about the products they build. &lt;/p&gt;

&lt;p&gt;They're driven by a professional pride and desire to build great products, transcending the traditional developer role to become genuine drivers who go on to put their names behind great products they themselves played a key role in shaping.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Counter to Hyperspecialisation
&lt;/h2&gt;

&lt;p&gt;The tech world has seen for a long time a trend towards hyperspecialisation, with engineering roles becoming increasingly narrow. &lt;/p&gt;

&lt;p&gt;We have &lt;em&gt;frontend engineers, backend engineers, iOS engineers, DevOps engineers&lt;/em&gt;. We have developers defining their careers with a specific language: &lt;em&gt;JavaScript engineers, Swift engineers, C# engineers, Python engineers&lt;/em&gt;. We even have developers that seemingly dedicate their entire careers to a single framework or tool: &lt;em&gt;React Engineers, .NET engineers, Unity Engineers, Ruby on Rails engineers&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Feels like it's only a matter of time until we see job postings seeking &lt;em&gt;for-loop engineers&lt;/em&gt; and &lt;em&gt;variable naming&lt;/em&gt; engineers.&lt;/p&gt;

&lt;p&gt;Jokes aside, specialisation isn't totally without its merits as it has allowed engineers to build deep expertise in specific technologies, a key component in building quality software. However, it also lead to silos where collaboration and broader product understanding became a nice-to-have, and often not even an expectation or focus for engineering roles. &lt;/p&gt;

&lt;p&gt;Product Engineers stand as a counter-movement to this trend. They embody a holistic approach to engineering, where understanding the entire product and context around it is just as important as the technical skills required to build it. This broad perspective enables them to bridge gaps between different technical domains and ensure that the product serves its customers effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI: The New Playground
&lt;/h2&gt;

&lt;p&gt;The rise of artificial intelligence (AI) tools in software development is rapidly setting new expectations for engineers. With AI tools becoming more sophisticated and capable, engineers are now expected to leverage these tools to enhance their work, not just in terms of speed and efficiency but also in terms of broadening their area of responsibilities.&lt;/p&gt;

&lt;p&gt;Engineers in a post- ChatGPT and GitHub Copilot world are now expected to be able to work in more languages, incorporate more tools and libraries, and simply be able to deliver more, using a broader range of technologies and disciplines in their daily work.&lt;/p&gt;

&lt;p&gt;It's probably not a great time to be the platform engineer whose job is to set up Jenkins pipelines for the product teams, when ChatGPT can easily help teams do it themselves.&lt;/p&gt;

&lt;p&gt;For Product Engineers however this has unlocked a higher level of abstraction. With AI tools handling more of the routine and specialised tasks, engineers can allocate more time to creative problem-solving, ideation, and exploring new ways to meet customer needs. &lt;/p&gt;

&lt;p&gt;This new level of abstraction allows Product Engineers to concentrate on product strategy, user experience, and overall system architecture without being bogged down by the intricacies of individual technologies.&lt;/p&gt;

&lt;p&gt;The incorporation of AI into software development encourages a broader perspective, where the choice of technology becomes a means to an end, rather than an end in itself.&lt;/p&gt;

&lt;p&gt;While AI didn't create the Product Engineer role (examples have been around for much longer); AI has made becoming a true Product Engineer much more accessible as a career path for software engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Combining Product Thinking and Technical Execution
&lt;/h2&gt;

&lt;p&gt;Product thinking involves understanding the user's needs, the market demands, and the business goals that drive a product's development. It's about seeing beyond the immediate task to grasp how each piece fits into the broader puzzle of the user experience. &lt;/p&gt;

&lt;p&gt;Product Engineers ask the crucial questions: "How does this feature add value to the user? What impact will this improvement have on the product's overall vision? How can we measure the success of our work?"&lt;/p&gt;

&lt;p&gt;They don't just build features based on specifications; they contribute to the design and roadmap of the product through a robust understanding of the customer's needs and business strategy.&lt;/p&gt;

&lt;p&gt;This approach requires a balance of skills: the ability to dive deep into coding and system architecture, while also keeping an eye on the product roadmap and customer feedback.&lt;/p&gt;

&lt;p&gt;By combining this mindset with quality technical execution, Product Engineers can uniquely ensure the product is headed to the right direction both technically and strategically, ensuring that their work directly contributes to the product's long term success.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Manifesto: A call to Product Engineers
&lt;/h2&gt;

&lt;p&gt;I've published a &lt;a href="https://github.com/anttiviljami/product-engineer-manifesto" rel="noopener noreferrer"&gt;Product Engineer Manifesto&lt;/a&gt; on GitHub to more formally define the Product Engineer mindset. &lt;/p&gt;

&lt;p&gt;Consider giving the repository a star if Product Engineering philosophy resonates with you!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/anttiviljami/product-engineer-manifesto" 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.amazonaws.com%2Fuploads%2Farticles%2Fz1yxmqp0dtrbo6qjiqq7.png" alt="Manifesto" width="677" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>product</category>
      <category>ai</category>
    </item>
    <item>
      <title>After 3 years: Bets I made as Head of Engineering rewriting the epilot SaaS – worth it?</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Thu, 15 Feb 2024 21:56:48 +0000</pubDate>
      <link>https://dev.to/epilot/after-3-years-bets-i-made-as-head-of-engineering-rewriting-the-epilot-saas-worth-it-2bc1</link>
      <guid>https://dev.to/epilot/after-3-years-bets-i-made-as-head-of-engineering-rewriting-the-epilot-saas-worth-it-2bc1</guid>
      <description>&lt;p&gt;In this post, we take a look back at some of the most influential decisions I implemented early on in our SaaS rewrite journey at &lt;a href="https://epilot.cloud/en" rel="noopener noreferrer"&gt;epilot&lt;/a&gt; and evaluate how well each one has played out after 3 years.&lt;/p&gt;

&lt;p&gt;Skip ahead or read on until the conclusion for a full verdict of whether rewriting our app was a good idea to begin with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doubling down on AWS &amp;amp; serverless
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To be fair, AWS was already the de-facto cloud platform used by the epilot team before I joined.&lt;/p&gt;

&lt;p&gt;My contribution was to convince the team to go all in on a serverless architecture with an ambitious strategy to rewrite and replace our proprietary Java-based 3rd party monolith running on EC2, piece by piece with functionalities leveraging serverless AWS offering.&lt;/p&gt;

&lt;p&gt;After 3 years, there are no regrets to choosing to be fully vendor-locked with AWS for the speed, scalability and minimal operations overhead it provides.&lt;/p&gt;

&lt;h2&gt;
  
  
  Microfrontends with single-spa
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The decision early on to take a microservices approach in our frontend was made out of purely practical reasons.&lt;/p&gt;

&lt;p&gt;Frankly our small team who lead the work on the new platform didn't have the time, the confidence, nor the desire to make long term decisions on the frontend tech stack, tooling and important design decisions on behalf of all our other teams, present and future.&lt;/p&gt;

&lt;p&gt;I'm extremely happy we went down this path instead of imposing one framework and toolset for everyone. The &lt;em&gt;single-spa&lt;/em&gt; approach lets us improve our frontend game each time a new microfrontend gets added to our application, which by now has happened more than 30 times! We've even ended up replacing entire MFEs (microfrontends) a few times, which isn't as bad as it sounds when the codebases are kept relatively small.&lt;/p&gt;

&lt;p&gt;Notably the microfrontend approach also helped us support the transition from the legacy product to the new one, as we were able to treat the legacy app as just one of our many (micro)frontends, and slowly replace functionalities one by one by shipping new microfrontends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using React without a framework
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bad bet 💸&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I know, &lt;em&gt;"skill issue"&lt;/em&gt;, right? But honestly I've found that even the really senior (read: expensive) React engineer hires tend to struggle with performance and end up wasting a lot of time on fixing major performance issues with React applications when they start to do anything meaningful.&lt;/p&gt;

&lt;p&gt;Starting over, I would probably spend a bit more time choosing a React framework that works well in a microfrontend environment rather than encouraging all teams to start from scratch, and establishing no-framework as the implicit default.&lt;/p&gt;

&lt;p&gt;Controversial: I might not even pick React for most MFEs anymore. We already use &lt;em&gt;Svelte&lt;/em&gt; in parts of our app, and turns out &lt;em&gt;Sveltekit&lt;/em&gt; works super well in a single-page-app environment like ours!&lt;/p&gt;

&lt;h2&gt;
  
  
  RFCs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The practice of writing RFCs to collaborate on software design and async decision making was one of the first and best things I introduced joining epilot.&lt;/p&gt;

&lt;p&gt;To this day we use RFCs as the main way to share ideas and be transparent about the work that our engineers do. I'd consider this one a very good bet and would absolutely recommend a culture of writing RFCs for all product organizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  API First
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We give a ton of freedom to engineers to pick whatever languages, tools and techniques they see fit, but the one thing I've always demanded from our teams has been to design using machine-readable API contracts, such as &lt;em&gt;OpenAPI&lt;/em&gt; or &lt;em&gt;GraphQL&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I would say this is internally the most important way we collaborate on our software's design, using shared types and automated tests to ensure our implementations follow the common API contracts. This approach has radically reduced bugs and allowed our engineers to work together efficiently leveraging platform features built and maintained by other teams.&lt;/p&gt;

&lt;p&gt;On top of that, being API First and publicly building and sharing our API contracts has allowed our customers and partners to effortlessly build on our product, and integrate it deeply with their own IT landscape using our API &amp;amp; SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous production deploys from &lt;code&gt;main&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bad bet 💸&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Turns out our customers simply did not tolerate the frequent changes and inevitable rollbacks of this approach.&lt;/p&gt;

&lt;p&gt;We technically still ship continuously from &lt;code&gt;main&lt;/code&gt; to our production environment, with an average of 150 production deployments every week, (with a lot of tests!), but now ship a monthly stable snapshot release to paying customers, and heavily utilise feature flags to roll out changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not using feature flags from the beginning
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bad bet 💸&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We did use GitLab feature flags on launch, but they were only used to turn features on/off between stages (&lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt;, &lt;code&gt;production&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Turns out this wasn't enough. Our teams really needed better tools to give us fine-grained control over rolling out features to specific customers. &lt;/p&gt;

&lt;p&gt;Going back, I wish we had started earlier with something like &lt;em&gt;LaunchDarkly&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hiring product-focused senior engineers remotely
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a decision I'm very proud of. Keeping an almost unreasonably high bar to getting hired and seeking out individuals who care about the product, our customers and our business has allowed us to build and retain a motivated team with zero managers and architects. &lt;/p&gt;

&lt;p&gt;Making engineer hiring remote-first allowed us to tap into an international pool of senior talent resulting in a team of more than 30 exceptional and motivated hands-on &lt;em&gt;Product Engineers&lt;/em&gt; from more than 10 countries working for us, and growing... ❤️&lt;/p&gt;

&lt;h2&gt;
  
  
  In-house DevOps / platform team
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bad bet 💸&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We tried to establish a platform team on two separate occasions but both times the team struggled to produce value for our teams. The DevOps engineer hired to lead the second platform team ended up leaving us for a bigger company after a few months.&lt;/p&gt;

&lt;p&gt;Looking back, part of the reason for this was likely a combination of leveraging managed/serverless services that don't require much in-house automation work, and hiring senior engineers who can automate things for themselves when needed.&lt;/p&gt;

&lt;p&gt;We've recently started experimenting working with a 3rd party DevOps consultancy to join us on a project-basis to help us with non-product related engineering tasks such as optimising our CI/CD pipelines.&lt;/p&gt;

&lt;p&gt;Regardless, we don't anymore see any need to hire and establish an in-house DevOps team, or get into &lt;em&gt;Platform Engineering&lt;/em&gt; of any sort in the foreseeable future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Weekly Demos
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The all-hands weekly demo is still easily my favourite recurring event at epilot. It's like having a company-wide celebration of shipping things, every week!&lt;/p&gt;

&lt;p&gt;The weekly demo brings not only a positive buzz around all the cool stuff being built, but also the expectation that engineers personally showcase concrete customer value created in their teams every week. It keeps us accountable for consistent delivery and maintains a rapid feedback loop with the rest of the company.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open-Source Engineering Principles
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Transparently laying out our Engineering Principles in a &lt;a href="https://github.com/epilot-dev/engineering-principles" rel="noopener noreferrer"&gt;public GitHub repo&lt;/a&gt; helped set clear expectations for our culture internally, and perhaps even more importantly for engineer candidates, many of whom have testified making the decision to apply at epilot because of our principles resonating with their own beliefs. &lt;/p&gt;

&lt;h2&gt;
  
  
  Hasura
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the early key bets was the decision to use &lt;em&gt;Hasura&lt;/em&gt; to interface with our legacy database to break up the monolith into microservices.&lt;/p&gt;

&lt;p&gt;Event triggers listening on DB changes and pushing messages to SQS while using the GraphQL API to implement 2-way data sync with the legacy app turned out to be a great and reliable event-driven pattern for breaking up the monolith step by step.&lt;/p&gt;

&lt;p&gt;Since shutting down the legacy product last year, &lt;em&gt;Hasura&lt;/em&gt; was decommissioned together with the legacy Postgres database, but it truly served its purpose well during the migration to serverless. 🫡&lt;/p&gt;

&lt;h2&gt;
  
  
  DynamoDB as our go-to database
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We haven’t had any fundamental issues with DynamoDB single table design in our backend microservices. &lt;/p&gt;

&lt;p&gt;Of course it’s not suitable for every use case, and we have turned to &lt;em&gt;Aurora serverless&lt;/em&gt;, &lt;em&gt;Elasticsearch&lt;/em&gt;, and even &lt;em&gt;InfluxDB&lt;/em&gt; in a few special cases, such as for search and analytical needs. But for 80% of the time, DynamoDB is fast, convenient and extremely worry-free as a default application database. &lt;/p&gt;

&lt;h2&gt;
  
  
  AWS OpenSearch service
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bad bet 💸&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We started out on &lt;em&gt;Amazon OpenSearch Service&lt;/em&gt; (still called &lt;em&gt;Elasticsearch service&lt;/em&gt; back then) but were struck with a pretty bad incident where our domain became completely non-responsive in our development environment and the only thing we could do was to contact AWS support to resolve the issue. This was totally unacceptable for us as we heavily rely on Elasticsearch for our main functionalities.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Elastic Cloud&lt;/em&gt; ended up being far more reliable and manageable for us in the end. Having a self-service reboot button on the interface makes all the difference!&lt;/p&gt;

&lt;p&gt;However with both providers rolling out their serverless solutions, which would be extremely attractive to us, we're keeping our eyes open and are open to experimenting again with &lt;em&gt;AWS OpenSearch&lt;/em&gt; offering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datadog for observability &amp;amp; monitoring
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Datadog is one of those tools that once you get used to it, you wonder how you ever lived without it.&lt;/p&gt;

&lt;p&gt;The value we get from Datadog's UI for logs, traces, monitors and dashboards is insane, and absolutely worth every penny.&lt;/p&gt;

&lt;p&gt;We use Datadog RUM for browser &amp;amp; UX monitoring. The RUM sessions and logs are extremely helpful for tracking down frontend crashes and bugs, as well as visually understanding user behaviours.&lt;/p&gt;

&lt;p&gt;On top of that, we use pipeline observability to analyse CI pipelines, custom metrics to track business &amp;amp; application KPIs, and cloud security management for compliance reporting and threat detection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datadog for incident management &amp;amp; post-mortems
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Datadog Incident Management has been absolutely vital in making sure we take the right steps to analyse and learn from our incidents. We use it during incidents for coordination and communication, as well as after the fact for post-mortem and analysis of past incidents and trends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datadog for browser tests
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bad bet 💸&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Datadog synthetic browser tests were great to get started fast but quickly became slow, expensive, hard to expand and simply not good enough for our team. &lt;/p&gt;

&lt;p&gt;We ended up switching over to &lt;em&gt;Playwright&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redshift Serverless
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bad bet 💸&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quite slow. Very expensive. At least for our use case of generating dashboards with Spectrum querying mostly parquet files from S3.&lt;/p&gt;

&lt;p&gt;Our team is currently investigating replacing Redshift with &lt;em&gt;Clickhouse&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Microservices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It's complicated 😎&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At this point I've stopped referring to our product as having a &lt;em&gt;microservices&lt;/em&gt; architecture. I don't find it a very helpful abstraction to understand a large, event-driven, interconnected product that's mostly FaaS.&lt;/p&gt;

&lt;p&gt;Yes, we still develop and deploy our services as independent domain-specific modules with well-defined APIs.&lt;/p&gt;

&lt;p&gt;In reality however our application is used by the customer as one big product with all the pieces needing to connect and work together to provide a service.&lt;/p&gt;

&lt;p&gt;Thus, we must also test and ship the product as one. (Really, we have one large shared e2e test project that blocks all pipelines. When we're shipping our monthly stable release, we take a snapshot of all our bundles and ship those in one atomic import map file.)&lt;/p&gt;

&lt;p&gt;I simply find it more useful to think of our product as one monolith, made up of a large number of independent infrastructure &amp;amp; FaaS modules with APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Was the rewrite a good idea?
&lt;/h2&gt;

&lt;p&gt;If you ask me now I would never recommend any SaaS company take the decision to fully rewrite their software. It's generally just a pretty dumb and painful thing to do. 😅&lt;/p&gt;

&lt;p&gt;For epilot sadly we were left with no other choice.&lt;/p&gt;

&lt;p&gt;The legacy version of our SaaS was built on top of a proprietary 3rd-party low-code platform &lt;em&gt;Axon Ivy&lt;/em&gt;, which by no means was designed to run a multi-tenant SaaS, but that the external epilot dev team from Vietnam (affiliated with Axon) had managed to wrangle to work.&lt;/p&gt;

&lt;p&gt;The fact that epilot was able to build a successful and fast-growing business on top of what's essentially a hacked low-code business process automation tool, is the ultimate proof to me that the tech stack really doesn't determine a company's success!&lt;/p&gt;

&lt;p&gt;But we were seriously starting to hit the limits of our software, especially when it came to scalability and speed of development. We didn't even have access to the source code so that we could take over the development of the core application. All we could do was upgrade to new versions provided by the vendor and continue to hack the software to make it do more things it wasn't designed for.&lt;/p&gt;

&lt;p&gt;Simply put, it wasn't sustainable for a fast growing software company. No developer wants to work on software like this. Especially not the talented and ambitious ones we wanted to work with.&lt;/p&gt;

&lt;p&gt;It took us nearly 3 years, but in the end we managed to reach feature parity, replace, migrate and shut down the legacy app, with very little churn, growing year-over-year and last year &lt;strong&gt;doubling our MRR&lt;/strong&gt; while migrating the last customers over to the new platform.&lt;/p&gt;

&lt;p&gt;Feels good to say we're only getting started with our new 360 platform.&lt;/p&gt;

&lt;p&gt;Looking back at the last 3 years, while I would never recommend anyone pursue a rewrite for a running SaaS business, while simultaneously trying to build a healthy, ambitious engineering team and culture, I'm convinced that for epilot this was the (only) way to go, and we're much better for it.&lt;/p&gt;

&lt;p&gt;In the end we at epilot overwhelmingly consider this a…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good bet 👍&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;To keep things short in this post, I'll publish a separate Part 2 where I share our latest bets focused on building epilot into the next SaaS Unicorn. 🦄&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mandatory recruitment disclaimer&lt;/em&gt;: If this post made you at all curious, please check out our &lt;a href="https://docs.epilot.io/docs/intro" rel="noopener noreferrer"&gt;docs&lt;/a&gt; and check our &lt;a href="https://epilot.cloud/en/career-jobs/#:~:text=Discover%20now-,We%20are%20looking%20for%20you!,-HR" rel="noopener noreferrer"&gt;open positions&lt;/a&gt; for more!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://epilot.cloud/en/career-jobs/#:~:text=Discover%20now-,We%20are%20looking%20for%20you!,-HR" rel="noopener noreferrer"&gt;&lt;img alt="epilot logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcwyl7es5sw89g54t66ky.png" width="506" height="482"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://epilot.cloud/en/career-jobs/#:~:text=Discover%20now-,We%20are%20looking%20for%20you!,-HR" rel="noopener noreferrer"&gt;We’re hiring @ epilot&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>react</category>
      <category>aws</category>
      <category>career</category>
    </item>
    <item>
      <title>Comparing REST, GraphQL &amp; tRPC</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Tue, 10 Oct 2023 10:59:54 +0000</pubDate>
      <link>https://dev.to/anttiviljami/comparing-rest-graphql-trpc-12n8</link>
      <guid>https://dev.to/anttiviljami/comparing-rest-graphql-trpc-12n8</guid>
      <description>&lt;p&gt;As an author and maintainer of &lt;a href="https://openapistack.co/" rel="noopener noreferrer"&gt;open source libraries&lt;/a&gt; to work with REST APIs, and as someone making a living building an API First SaaS product with both REST and GraphQL APIs, I sometimes encounter strange attitudes towards different API styles.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"REST is outdated" "GraphQL is only good for mobile dev" "tRPC is too new for production" "No one likes to work with swagger"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It might be tempting to pit these technologies against each other, but the reality is, these paradigms are not direct competitors. Instead, each has its own unique strengths and use-cases, crafted for specific contexts and developer needs.&lt;/p&gt;

&lt;p&gt;I was reminded of this fact recently when writing comparisons between my own open source REST tooling vs. GraphQL and tRPC:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1711285703840084201-562" src="https://platform.twitter.com/embed/Tweet.html?id=1711285703840084201"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1711285703840084201-562');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1711285703840084201&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Let's take a deeper look at each technology and its strengths:&lt;/p&gt;

&lt;h2&gt;
  
  
  GraphQL
&lt;/h2&gt;

&lt;p&gt;GraphQL is a query language for APIs developed by Facebook. It gives API clients full control over the data they query, making it extremely flexible and efficient for client-centric use cases.&lt;/p&gt;

&lt;p&gt;GraphQL APIs define a strongly typed schema for the data and mutations they support which makes them discoverable and intuitive to develop against.&lt;/p&gt;

&lt;p&gt;Teams building with GraphQL naturally take the API First &lt;em&gt;(or Schema First)&lt;/em&gt; approach where the API contract is treated as a first class citizen in the software design instead of treating it as merely documentation.&lt;/p&gt;

&lt;p&gt;When developing an app with a GraphQL API, it's common to use the GraphQL schema as the single source of truth for data models used within the application, and source types from it used end to end across the codebase.&lt;/p&gt;

&lt;p&gt;GraphQL APIs are often used as gateways, merging multiple downstream APIs into a single, easy to use interface for a great application development experience. I would consider this one of GraphQL's killer apps.&lt;/p&gt;

&lt;p&gt;Facebook's excellent &lt;a href="https://www.apollographql.com/" rel="noopener noreferrer"&gt;Apollo GraphQL&lt;/a&gt; is definitely a best-in-class example of great API development experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  REST
&lt;/h2&gt;

&lt;p&gt;REST has been around for a while now. It's still probably the most widely adopted HTTP API design paradigm perhaps due to its resource-based implementation simplicity and the ability to leverage standard HTTP features directly.&lt;/p&gt;

&lt;p&gt;With widely adopted open standards to define REST APIs, like &lt;a href="https://www.openapis.org/" rel="noopener noreferrer"&gt;OpenAPI specification&lt;/a&gt; (previously known as Swagger), REST can be used much like GraphQL with a single source of truth for the API contract.&lt;/p&gt;

&lt;p&gt;Full disclosure: my own open source work in the last few years has revolved around the mission of bringing a GraphQL-like developer experience and type safety with OpenAPI for REST.&lt;/p&gt;

&lt;p&gt;While REST APIs don't generally provide the same level of control to clients as GraphQL, sometimes this could be seen as a benefit especially in scenarios where strict control over data access and operations is crucial.&lt;/p&gt;

&lt;p&gt;Widespread knowledge around REST contribute to its choice among organizations looking for a tried-and-tested approach to building APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  tRPC
&lt;/h2&gt;

&lt;p&gt;While RPCs are by no means a new idea, &lt;a href="https://trpc.io/" rel="noopener noreferrer"&gt;tRPC&lt;/a&gt; is seen as the new kid on the API block. Much loved by developers who just want to build fast and do it with type safety.&lt;/p&gt;

&lt;p&gt;Designed for full-stack Typescript applications, tRPC allows direct sharing of types between both the client and server, without relying on code generation.&lt;/p&gt;

&lt;p&gt;Unlike GraphQL and REST, tRPC doesn't expose a standard machine-readable API schema to be consumed by clients, instead taking a more straightforward approach of exposing endpoints or procedures, essentially &lt;em&gt;&lt;a href="https://trpc.io/docs/concepts#its-just-functions" rel="noopener noreferrer"&gt;"just functions"&lt;/a&gt;&lt;/em&gt; invoked by the client to the server.&lt;/p&gt;

&lt;p&gt;While the lightweight tRPC approach is optimal for teams just looking to build full stack applications, teams looking to build robust, re-usable APIs may better be served by the API design first approach of GraphQL or OpenAPI.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(I wonder if tRPC will eventually get its own YAML specification language)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In the landscape of software dev, it's easy to get caught up in the rhetoric of one technology being superior to another. But as we dive deeper into the nuances of GraphQL, REST, and tRPC, it becomes evident that each serves its unique purpose and has been created to solve specific problems in API development.&lt;/p&gt;

&lt;p&gt;The right choice of an API paradigm is definitely not a one-size-fits-all solution.&lt;/p&gt;

&lt;p&gt;It's essential to remember that the success of an API doesn't necessarily depend on the technology backing it, but more on its clarity, usability, reliability, and the developer experience it offers.&lt;/p&gt;

&lt;p&gt;Technologies change, but the principles of good API design and the goal to write delightful, working software remains constant.&lt;/p&gt;

&lt;p&gt;If you're interested in my Open Source work around API tooling, check out &lt;a href="https://openapistack.co" rel="noopener noreferrer"&gt;openapistack.co&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rest</category>
      <category>graphql</category>
      <category>trpc</category>
      <category>openapi</category>
    </item>
    <item>
      <title>How we do engineering @ epilot</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Sun, 22 Jan 2023 15:35:57 +0000</pubDate>
      <link>https://dev.to/epilot/how-we-do-engineering-at-epilot-nai</link>
      <guid>https://dev.to/epilot/how-we-do-engineering-at-epilot-nai</guid>
      <description>&lt;p&gt;Ever since open-sourcing our core &lt;a href="https://github.com/epilot-dev/engineering-principles" rel="noopener noreferrer"&gt;Engineering Principles&lt;/a&gt; back in January 2021, I regularly get asked by candidates how and if the principles really work in practice at epilot.&lt;/p&gt;

&lt;p&gt;In this post, I'll attempt to give a glimpse of concrete tools and practices we use in our product team to give an idea of how we apply our principles and what the engineering culture really looks like from the inside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Team Structure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F42k3bz1nb6ycc0xr1pxk.jpg" class="article-body-image-wrapper"&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.amazonaws.com%2Fuploads%2Farticles%2F42k3bz1nb6ycc0xr1pxk.jpg" alt="Engineering team group picture" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At time of writing, the epilot engineering team consists of 25 full-time remote software engineers organized into 6 squads, each with its own Product Manager and a shared design team of 4 talented product &amp;amp; UX designers.&lt;/p&gt;

&lt;p&gt;Each squad is led by an engineer team lead, principally responsible for the team's delivery and engineer wellbeing.&lt;/p&gt;

&lt;p&gt;The product leadership team is responsible for communicating our product strategy and maintains a &lt;a href="https://medium.com/the-creative-strategist/why-now-next-later-is-one-of-the-best-frameworks-for-roadmapping-4d547a2f2692" rel="noopener noreferrer"&gt;Now-Next-Later&lt;/a&gt; roadmap, but ultimately it's the squads that make all delivery decisions.&lt;/p&gt;

&lt;p&gt;Squads are formed around specific business domains within the epilot 360 platform, architected around &lt;a href="https://domaindrivendesign.org/ddd-domain-driven-design/" rel="noopener noreferrer"&gt;Domain Driven Design&lt;/a&gt; and micro-ish services both in the backend and frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show, Don't Tell
&lt;/h2&gt;

&lt;p&gt;We value real concrete working software, not roadmaps and fancy presentations.&lt;/p&gt;

&lt;p&gt;Engineers showcase features in a weekly all-hands Product Demo session: a company-wide celebration and ruthless feedback session. 🎉&lt;/p&gt;

&lt;p&gt;Features being demoed are deployed to production but are usually hidden behind a &lt;a href="https://www.getunleash.io/" rel="noopener noreferrer"&gt;Feature Toggle&lt;/a&gt;, giving demo participants a chance to test and give feedback on features before release.&lt;/p&gt;

&lt;p&gt;Most squads use a Kanban-style flow with a weekly planning cycle, but opt to showcase their progress every 2 weeks, with some squads hosting extra demos called "Open Houses" on off-weeks.&lt;/p&gt;

&lt;p&gt;The engineering team also hosts an internal bi-weekly "Tech Exchange" to wind down with a beer, but also present and demo cool technical things.&lt;/p&gt;

&lt;h2&gt;
  
  
  API-first &amp;amp; serverless
&lt;/h2&gt;

&lt;p&gt;The epilot backend is built as serverless microservices written mostly in Typescript, leveraging services such as AWS Lambda, Step Functions, EventBridge, API Gateway and AppSync.&lt;/p&gt;

&lt;p&gt;DynamoDB is the most popular database solution enhanced by managed data stores such as Elasticsearch Cloud, Aurora Serverless and Redshift Serverless.&lt;/p&gt;

&lt;p&gt;Our backend is pretty event-driven, with heavy use of EventBridge, SQS and Step Functions to implement asynchronous business logic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.epilot.io/docs/architecture/overview" 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.amazonaws.com%2Fuploads%2Farticles%2Fxgjoo96jraez8ar3a8re.png" alt="epilot tech stack" width="800" height="1141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our frontend application consists of microfrontends written in React and Svelte orchestrated by the &lt;a href="https://single-spa.js.org/" rel="noopener noreferrer"&gt;single-spa&lt;/a&gt; framework.&lt;/p&gt;

&lt;p&gt;The epilot frontend is entirely built on the same APIs we expose to our customers and technical partners via our open-source &lt;a href="https://github.com/epilot-dev/sdk-js" rel="noopener noreferrer"&gt;SDK&lt;/a&gt; and public documentation.&lt;/p&gt;

&lt;p&gt;We like open standards, so our APIs are defined using common machine-readable specs like GraphQL and OpenAPI.&lt;/p&gt;

&lt;p&gt;We find the domain-driven architecture approach an efficient way to organize our teams to act independently while collaborating on software design with an &lt;a href="https://dev.to/epilot/why-we-design-apis-first-e85"&gt;API-first&lt;/a&gt; approach.&lt;/p&gt;

&lt;p&gt;Organizing our codebase with microservices helps our fully remote engineering team focus on delivery and minimize &lt;a href="https://en.wiktionary.org/wiki/bikeshedding" rel="noopener noreferrer"&gt;bikeshedding&lt;/a&gt; over non-critical engineering decisions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx4e95wjngxcf7im0z0f.png" class="article-body-image-wrapper"&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.amazonaws.com%2Fuploads%2Farticles%2Fwx4e95wjngxcf7im0z0f.png" alt="Microfrontends" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Freedom and Responsibility
&lt;/h2&gt;

&lt;p&gt;Ok, I freely admit we stole this one from the &lt;a href="https://jobs.netflix.com/culture" rel="noopener noreferrer"&gt;Netflix culture deck&lt;/a&gt;. Shoulders of giants and so on. ♥&lt;/p&gt;

&lt;p&gt;At epilot, every hire is trusted and treated as an adult from day one. We only hire smart people who we can trust and aren't afraid to terminate a relationship if that trust is broken.&lt;/p&gt;

&lt;p&gt;We expect engineers to operate by principles and think strategically to benefit our customers and our business. (Max-the-MRR)&lt;/p&gt;

&lt;p&gt;We intentionally make it very difficult to create company-wide policies to control which tools to use, what employees should be allowed to do and how they should organize their daily work.&lt;/p&gt;

&lt;p&gt;It should be hard to introduce new processes but easy to get rid of existing bad ones.&lt;/p&gt;

&lt;p&gt;The exception to this rule is security.&lt;/p&gt;

&lt;p&gt;We encourage team members to challenge the status quo with RFCs proposing ways to improve the product and our ways of working.&lt;/p&gt;

&lt;h2&gt;
  
  
  RFCs - Solutions Over Problems
&lt;/h2&gt;

&lt;p&gt;Among other things, RFCs written by engineers have so far led us to adopt continuous deployment, harden security, establish new teams, and even &lt;a href="https://dev.to/epilot/my-first-year-as-epilots-head-of-engineering-killing-the-legacy-monolith-25c2#:~:text=The%20radical%20360%20plan"&gt;rewrite the entire product in a different tech stack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These are often simple documents that start out by just describing a problem and expressing a wish or an idea to solve it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05wyg0jyd30oruzonlxr.png" class="article-body-image-wrapper"&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.amazonaws.com%2Fuploads%2Farticles%2F05wyg0jyd30oruzonlxr.png" alt="RFC" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RFCs at epilot have no official approval process. We expect the author to champion their proposal by garnering relevant feedback from peers and stakeholders, and then make an informed decision on how to proceed.&lt;/p&gt;

&lt;p&gt;In most cases, the RFC author leads by example and implements the proposal themselves, usually just within her squad at first.&lt;/p&gt;

&lt;p&gt;Good ideas spread and are adopted through all teams, not by mandate from above, but by actually improving the quality of our work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; A total of 192 RFCs have been published in our Confluence since they were introduced 2 years ago. 🔥&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Every Week is Quality Week
&lt;/h2&gt;

&lt;p&gt;The name of this principle came about after a group of engineers expressed concern about technical debt in their project due to pressure to deliver against deadlines.&lt;/p&gt;

&lt;p&gt;At the time, it was already an established practice to &lt;a href="https://github.com/anttiviljami/romero-programming-principles#principle-6-fix-bugs-immediately" rel="noopener noreferrer"&gt;fix bugs immediately&lt;/a&gt; and treat all types of bugs as critical, but many engineers still felt that they couldn't go against the wishes of product managers to follow the practice.&lt;/p&gt;

&lt;p&gt;It was proposed to have a "quality week" at the end of every quarter to give engineers time to focus on quality topics.&lt;/p&gt;

&lt;p&gt;As the quarter came to a close, we announced the quality week with instructions to all squads to focus solely on bugs, technical debt and other quality improvements they felt were important.&lt;/p&gt;

&lt;p&gt;During the quality week, our engineers were extremely motivated to fix long-time issues that had affected our customers.&lt;/p&gt;

&lt;p&gt;We made real, significant progress that week and everyone could see it.&lt;/p&gt;

&lt;p&gt;On Monday following the first quality week, we opened &lt;a href="https://github.com/epilot-dev/engineering-principles/pull/8" rel="noopener noreferrer"&gt;this PR&lt;/a&gt;, making an announcement that every week from now on would be quality week:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/epilot-dev/engineering-principles/pull/8" 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.amazonaws.com%2Fuploads%2Farticles%2Fmb6wkx3bdlfzoqucdb8d.png" alt="Every Week is Quality Week PR" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It worked. We're still starting a new quality week every Monday.&lt;/p&gt;

&lt;h2&gt;
  
  
  No-Ops &amp;amp; Continuous Deployment
&lt;/h2&gt;

&lt;p&gt;At epilot you will find a distinct lack of epilot-specific shared tooling. We actively avoid building our own tools and standardizing configurations and instead encourage using open-source tools like AWS CDK, &lt;a href="https://github.com/awslabs/aws-lambda-powertools-typescript" rel="noopener noreferrer"&gt;lambda-powertools&lt;/a&gt; and &lt;a href="https://single-spa.js.org" rel="noopener noreferrer"&gt;single-spa&lt;/a&gt; to build our product.&lt;/p&gt;

&lt;p&gt;We don't have dedicated DevOps engineers or a platform team to build custom tools and pipelines or run k8s clusters.&lt;/p&gt;

&lt;p&gt;We expect squads to independently automate testing, deployment and monitoring of their features to minimize the need for manual operational tasks.&lt;/p&gt;

&lt;p&gt;Engineers really get to pick any tools they like to do their job, as long as they weigh tech decisions against our principles.&lt;/p&gt;

&lt;p&gt;I sometimes get engineers pushing me to leverage my position as head of department to standardize tech choices across the entire engineering team, but so far the approach of giving teams radical freedom has yielded organic adoption of best practices and tools where needed anyways.&lt;/p&gt;

&lt;p&gt;Without extra push, all teams have converged to using the same GitLab CI templates, connecting up with &lt;a href="https://docs.datadoghq.com/continuous_integration/" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; to continuously deploy code with synthetic browser tests integrated into the pipeline to make sure we catch problems before they get to production.&lt;/p&gt;

&lt;p&gt;The whole team also uses Datadog (another RFC) as the central observability solution to know what's happening in our platform at all times.&lt;/p&gt;

&lt;p&gt;When stuff goes wrong, engineers owning the feature jump on a Slack huddle using Datadog's incident management feature to coordinate the response, cleanup and write a post-mortem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why principles matter
&lt;/h2&gt;

&lt;p&gt;When I joined epilot, I made it my personal mission to build an engineering culture that I would personally want to join and be part of.&lt;/p&gt;

&lt;p&gt;To me, the &lt;a href="https://github.com/epilot-dev/engineering-principles" rel="noopener noreferrer"&gt;engineering principles&lt;/a&gt; are like a founding document; a source code or DNA of how to build a great engineering team.&lt;/p&gt;

&lt;p&gt;I'm proud of how far we've come, but there's still lots to learn and improve as we grow and mature as a product team.&lt;/p&gt;

&lt;p&gt;I fully expect that in 2 years, writing this blog post would look very different as the industry moves forward with new tools and practices. I hope that these principles will stick.&lt;/p&gt;

&lt;p&gt;If the topics in this post resonated with you, make sure to check out our &lt;a href="https://docs.epilot.io/" rel="noopener noreferrer"&gt;dev docs&lt;/a&gt; and see our &lt;a href="https://epilot.cloud/en/career-jobs/" rel="noopener noreferrer"&gt;open positions&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://epilot.cloud/en/career-jobs/" 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.amazonaws.com%2Fuploads%2Farticles%2Fz5yiudedwkwd5jnceyb0.png" alt="Join our crew!" width="800" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://epilot.cloud/en/career-jobs/" rel="noopener noreferrer"&gt;We're hiring @ epilot!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>discord</category>
      <category>community</category>
    </item>
    <item>
      <title>First year as Head of Engineering @epilot - Killing the Legacy Monolith</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Fri, 17 Jun 2022 08:34:45 +0000</pubDate>
      <link>https://dev.to/epilot/my-first-year-as-epilots-head-of-engineering-killing-the-legacy-monolith-25c2</link>
      <guid>https://dev.to/epilot/my-first-year-as-epilots-head-of-engineering-killing-the-legacy-monolith-25c2</guid>
      <description>&lt;p&gt;This post is a personal account of my experience at &lt;a href="https://epilot.cloud/en/" rel="noopener noreferrer"&gt;epilot.cloud&lt;/a&gt; and our journey rebuilding our legacy Java monolith SaaS from the ground up with AWS, serverless and microfrontends, mostly during 2021.&lt;/p&gt;

&lt;p&gt;The text is written from the perspective of engineering and focuses on the challenges I faced taking on leadership of our growing team of 25+ engineers.&lt;/p&gt;

&lt;p&gt;I fully acknowledge this is not the complete picture of epilot's growth during this time as we have many other amazing departments and individuals working to make epilot the next tech unicorn success story.&lt;/p&gt;

&lt;p&gt;Full disclosure, I love this company and am heavily invested in the product's success after my first year and a half. 💙&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ybon69p9qvdgay6b7vh.jpg" class="article-body-image-wrapper"&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.amazonaws.com%2Fuploads%2Farticles%2F5ybon69p9qvdgay6b7vh.jpg" alt="Cologne Carnival" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(I'm the one dressed up as the doctor for our company's annual Cologne carnival celebration)&lt;/p&gt;

&lt;h2&gt;
  
  
  Beginnings
&lt;/h2&gt;

&lt;p&gt;I joined the Cologne-based startup epilot in October 2020 as a cloud engineer to head a new platform team and aid the product team transition to serverless AWS.&lt;/p&gt;

&lt;p&gt;The task felt right in my wheelhouse.&lt;/p&gt;

&lt;p&gt;By that time I already had three real serverless products under my belt, had experience migrating monoliths to microservices, and had acquired more than 8 years of professional experience in total as a developer and team lead working mostly with AWS and other cloud platforms.&lt;/p&gt;

&lt;p&gt;I knew startups. I had experience with the business domain. I knew the technology well.&lt;/p&gt;

&lt;p&gt;This was my time to shine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build better software, faster.
&lt;/h2&gt;

&lt;p&gt;As our CTO Szilard Toth put it in our first discussions, my job description was to help us "build better software, faster".&lt;/p&gt;

&lt;p&gt;I took that mission statement very seriously.&lt;/p&gt;

&lt;p&gt;Coming off a 4-year stint at &lt;a href="https://futurice.com" rel="noopener noreferrer"&gt;Futurice&lt;/a&gt;, a lean service design focused consultancy, my first instinct was to make a current state analysis of my new company - epilot.&lt;/p&gt;

&lt;p&gt;To get my bearings, I joined one of the engineering teams and got busy.&lt;/p&gt;

&lt;p&gt;I learned about the challenges our teams were facing and got a deeper view into our legacy product, which had already been in active development for more than 3 years.&lt;/p&gt;

&lt;p&gt;We were already doing a lot of things right: All three teams at the time were generally following agile practices, engineers were eager to discuss and learn their new tools, many had even taken the time to get AWS certified.&lt;/p&gt;

&lt;p&gt;But there were certainly some big concerns.&lt;/p&gt;

&lt;p&gt;At the end of my first full month, I was ready to present my learnings to the company.&lt;/p&gt;

&lt;h2&gt;
  
  
  First insights
&lt;/h2&gt;

&lt;p&gt;I published an internal document titled "epilot Tech Review" detailing my assessment of the current state of epilot's engineering.&lt;/p&gt;

&lt;p&gt;These were the main findings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The decision made (before my time) to pick AWS, serverless and React as our foundation was a good one for what the team wanted to achieve: Low operating costs and high development speed. This was especially great for hiring due to many candidates being attracted to these modern technologies.&lt;/li&gt;
&lt;li&gt;Our teams lacked experience working with these technologies. Progress was slow and unfortunate decisions were made with the very first small scale serverless projects.&lt;/li&gt;
&lt;li&gt;Alarmingly, the engineering team had no viable plan or strategy to migrate the legacy product to the new serverless architecture. Everyone was excited about the new tech but we clearly had no clue how to actually build our product with it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I emphasised in the document how important it was for epilot's success to move away from the legacy technology stack, a proprietary monolithic Java framework which had already proven to be a poor fit for our use case, difficult to run and extremely slow to develop new features on.&lt;/p&gt;

&lt;p&gt;Our ability to deliver as an engineering team was looking pretty grim. The company had already invested a full year into going serverless with not much to show for it.&lt;/p&gt;

&lt;p&gt;To make matters worse, some of our key engineers had just announced they were leaving the company.&lt;/p&gt;

&lt;p&gt;In spite of our woes on the engineering side, epilot had a rare advantage:&lt;/p&gt;

&lt;p&gt;A proven product-market fit – Even with our product leaving much to be desired, our paying customers were becoming fans!&lt;/p&gt;

&lt;p&gt;Yes, they were sometimes frustrated with the quality of the software and our inability to deliver features they were asking for, but they were totally bought into the vision of what epilot could be and we were clearly delivering value for them.&lt;/p&gt;

&lt;p&gt;I think this was thanks to our visionary leadership with deep industry knowledge knowing which problems to solve along with a great sales team and a MacGyver-like customer success team working around the limitations of our software.&lt;/p&gt;

&lt;p&gt;We had the right idea, just not a great technical execution yet.&lt;/p&gt;

&lt;p&gt;Luckily I knew I could make a difference when it comes to execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  RFCs and API first
&lt;/h2&gt;

&lt;p&gt;I went on to establish the platform team I was hired for. We started small with myself and an SRE who had been at epilot a year before me.&lt;/p&gt;

&lt;p&gt;The first things the team tackled were improvements to developer workflows such as enabling an &lt;a href="https://dev.to/epilot/why-we-design-apis-first-e85"&gt;API Design First approach&lt;/a&gt; for our serverless APIs and building common CI/CD pipelines for the tools our teams were using.&lt;/p&gt;

&lt;p&gt;I introduced RFCs for the teams as a tool to discuss designs and proposals to improve our product and work.&lt;/p&gt;

&lt;p&gt;With key engineers leaving us, it was important to establish an open culture with teams making independent decisions while focusing on good software design and communication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6ofxs17i2550m8mttjq.png" class="article-body-image-wrapper"&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.amazonaws.com%2Fuploads%2Farticles%2Fs6ofxs17i2550m8mttjq.png" alt="RFCs" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As one of the very first RFCs shared, I laid out my admittedly optimistic plan to move away from our legacy monolith app.&lt;/p&gt;

&lt;h2&gt;
  
  
  The radical 360 plan
&lt;/h2&gt;

&lt;p&gt;I brought my plan directly to senior company leadership triggering a series of discussions in late 2020 to figure out our legacy migration strategy.&lt;/p&gt;

&lt;p&gt;In sessions with our CEO Michel, CTO Szilard and head of sales Marlon, it became very clear this would not be just a migration from monolith to serverless. We needed to build the new version of epilot SaaS with a radically different design, starting from a new flexible data layer to power the diverse set of use cases our customers were asking for.&lt;/p&gt;

&lt;p&gt;We called it epilot 360. And it would be my job to build it.&lt;/p&gt;

&lt;p&gt;From the start of 2021, we established a new strike team to head the effort of building 360. I doubled as the leader of both the platform team and the new 360 team.&lt;/p&gt;

&lt;p&gt;The 360 plan was radical. We would completely rebuild our main portal interface using frontend microservices and embed the old product into the new portal as a microfrontend to provide backwards compatibility while we rebuild and migrate features one by one in the new serverless world.&lt;/p&gt;

&lt;p&gt;Getting the old monolith to work in the new portal was our first big technical hurdle. We developed a "headless" mode for the old app, where the UI was modified to fit into the new portal layout and implemented secure communication with the parent 360 app to pass information like the current user's session to the legacy app.&lt;/p&gt;

&lt;p&gt;From the data side, we continued to split up the legacy SQL database into serverless microservices. We introduced &lt;a href="https://hasura.io/" rel="noopener noreferrer"&gt;Hasura&lt;/a&gt; to act as the gateway to synchronise data between the legacy database and our new serverless services.&lt;/p&gt;

&lt;p&gt;By March 2021, we had migrated our first module to 360 using the new flexible data model and had shipped a new portal microfrontend for it.&lt;/p&gt;

&lt;p&gt;We introduced &lt;a href="https://www.datadoghq.com/" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; for centralised logging and monitoring, as well as to provide crucial analytics and observability tools for our new serverless product.&lt;/p&gt;

&lt;p&gt;Finally in July of 2021, we greeted all our users with a whole new 360  login and portal experience, wrapping the old familiar app in our brand new look with serverless features already replacing many legacy views.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw624qiz00mq762xdyh7o.png" class="article-body-image-wrapper"&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.amazonaws.com%2Fuploads%2Farticles%2Fw624qiz00mq762xdyh7o.png" alt="New 360 Login" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This felt like the first big launch of 360. Although lots of work was still ahead to fully get rid of our legacy app, our users were happy to see us start to deliver on our promises with a new major release of the epilot product.&lt;/p&gt;

&lt;p&gt;From here on the rate of new releases in our app would radically increase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Head of Engineering
&lt;/h2&gt;

&lt;p&gt;In May of 2021, I was officially promoted to head of engineering which meant I was no longer just in charge of the platform team and the 360 team. I was now in charge of the entire engineering team with our CTO shifting his focus away from engineering to product management.&lt;/p&gt;

&lt;p&gt;In the meantime we had also ramped up our recruitment efforts. We published our in-house &lt;a href="https://github.com/epilot-dev/engineering-principles" rel="noopener noreferrer"&gt;engineering principles&lt;/a&gt; and built a new recruitment landing page &lt;a href="https://promise.epilot.cloud/" rel="noopener noreferrer"&gt;promise.epilot.cloud&lt;/a&gt; to showcase our culture. As a result, we managed to acquire some amazing new engineering talent during 2021. &amp;lt;3&lt;/p&gt;

&lt;p&gt;So far it had been mostly just my small team of 4 developers working on 360. Now as the new head of department, I needed to shift the focus of all our by now 25+ engineers and 6 teams to work on the new 360 platform.&lt;/p&gt;

&lt;p&gt;This came with some major challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling the team
&lt;/h2&gt;

&lt;p&gt;One of the biggest challenges was the radically different underlying design of 360 with its flexible data model as opposed to our legacy product's traditional static data model.&lt;/p&gt;

&lt;p&gt;Teams initially struggled to wrap their heads around the new &lt;a href="https://docs.epilot.io/docs/entities/flexible-entities" rel="noopener noreferrer"&gt;flexible entities&lt;/a&gt;; not least because of my struggle to communicate it properly. Through some much needed visual design support and hands-on experience with the product, we slowly built up an understanding of our new 360 product together.&lt;/p&gt;

&lt;p&gt;A major focus of the architectural design of 360 was on modularity by utilising frontend and backend microservices combined with our API First software design approach.&lt;/p&gt;

&lt;p&gt;This was to allow teams to work independently giving them the freedom to choose their own tools and ways to solve problems.&lt;/p&gt;

&lt;p&gt;We found this approach to be a big success as it kept our projects small with teams motivated to try out new technologies, share and learn from other teams, and quickly change approaches when needed.&lt;/p&gt;

&lt;p&gt;After the first few months of teams working on 360 it was clear that we were able to move much faster than ever before with our new tech stack.&lt;/p&gt;

&lt;p&gt;We adopted continuous deployment across all teams and quickly surpassed an average of &amp;gt;100 production releases each week. This was a huge achievement considering that back when I joined we were able to deploy only 1-2 times per week during a pre-defined maintenance window!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8bt6azzs70scun0o57v.png" class="article-body-image-wrapper"&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.amazonaws.com%2Fuploads%2Farticles%2Fp8bt6azzs70scun0o57v.png" alt="Production Deployments Graph" width="794" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By the end of 2021, all our teams had shipped major features on the 360 product and we had reached enough feature parity for the first new users to be onboarded to epilot completely on 360 with no trace of the legacy product.&lt;/p&gt;

&lt;p&gt;We had an MLP - Minimum Lovable Product!&lt;/p&gt;

&lt;p&gt;Things would speed up even more throughout the first half of 2022 with teams getting comfortable with 360, shipping more serverless features to get us closer to the magical feature parity state with our rather large legacy product.&lt;/p&gt;

&lt;p&gt;We opened up the 360 platform to external developers and partners with our &lt;a href="https://docs.epilot.io/" rel="noopener noreferrer"&gt;public developer docs&lt;/a&gt; and &lt;a href="https://github.com/epilot-dev/sdk-js/" rel="noopener noreferrer"&gt;open source SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the meantime our sales and customer success teams have been actively engaged with existing customers to help them migrate to 360. More and more users are now adopting the new features each week and we’re learning from them to make 360 even better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways from the first year
&lt;/h2&gt;

&lt;p&gt;As I'm writing this post in June 2022, after my first full year as head of engineering and after almost a year of running the main epilot application in production on AWS serverless and frontend microservices, I can't help but ask myself:&lt;/p&gt;

&lt;p&gt;Was 360 a success?&lt;/p&gt;

&lt;p&gt;While my ego would love to give a resounding "Yes!" as the answer, I can't be fully satisfied until we've fully completed the migration of all features from the legacy app and have successfully shut down the old monolith and moved on with happy users.&lt;/p&gt;

&lt;p&gt;We're not quite there yet.&lt;/p&gt;

&lt;p&gt;Are we building better software, faster? – Yes! The feedback from our customers is very positive and our product teams are delivering features 10x faster than we were back in 2020 when I joined. We're demoing new features every week now!&lt;/p&gt;

&lt;p&gt;Are we on track getting rid of our legacy monolith? – Yes! At the time of writing, we're close to 90% feature parity with more users hopping over to 360 each week.&lt;/p&gt;

&lt;p&gt;Was it way more difficult than initially thought? – Heck yes! The people side of things turned out to be much more complex than the technical side – as always.&lt;/p&gt;

&lt;p&gt;It isn’t easy to align 5 remote product teams to work on a new product redesigned and rebuilt from the ground up.&lt;/p&gt;

&lt;p&gt;It isn't easy to introduce big changes to our tech stack, product, and engineering culture.&lt;/p&gt;

&lt;p&gt;It isn't easy to keep our users happy while introducing a new product with major design changes and new concepts to learn.&lt;/p&gt;

&lt;p&gt;While none of these things are easy, they are surely worthwhile and we strive to get better every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Looking back, I've learned a lot in the past year about leadership, engineering and building products.&lt;/p&gt;

&lt;p&gt;With our engineer teams now working well, I've been able to focus my daily work on helping our customers and technical partners hands-on with their adoption of 360. This has really helped me gain better perspective on where the 360 product stands today from our users' perspective.&lt;/p&gt;

&lt;p&gt;I've received a ton of feedback; from customers, from colleagues, and from our leadership team.&lt;/p&gt;

&lt;p&gt;I’m glad to say things are looking bright for epilot 360!&lt;/p&gt;

&lt;p&gt;Still lots to learn and build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://epilot.cloud/en" 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.amazonaws.com%2Fuploads%2Farticles%2Fq660re5susj1a8efggrd.png" alt="epilot logo" width="800" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://promise.epilot.cloud/" rel="noopener noreferrer"&gt;We're hiring @ epilot!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>career</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Surprising Performance Lessons from React Microfrontends in Production</title>
      <dc:creator>Viljami Kuosmanen</dc:creator>
      <pubDate>Sun, 22 May 2022 12:35:48 +0000</pubDate>
      <link>https://dev.to/epilot/surprising-performance-lessons-from-react-microfrontends-in-production-528a</link>
      <guid>https://dev.to/epilot/surprising-performance-lessons-from-react-microfrontends-in-production-528a</guid>
      <description>&lt;p&gt;The epilot engineering team stands at 27 developers 1 year after the launch of our rewritten portal built on mostly* React &lt;a href="https://docs.epilot.io/docs/portal/microfrontends" rel="noopener noreferrer"&gt;microfrontends&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.epilot.io/docs/portal/microfrontends" 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.amazonaws.com%2Fuploads%2Farticles%2Faym8yh77ndlw26rfv0nn.png" alt="Microfrontends screenshot" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*Part of our app is written using other frontend frameworks, most notably the sidebar navigation written in Svelte.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since the initial launch a year ago, our teams have gained a lot of experience running React microfrontends in production using &lt;a href="https://single-spa.js.org/" rel="noopener noreferrer"&gt;single-spa&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While we expected to face challenges with our new frontend microservices architecture, after solving a few initial problems we haven't hit any major snags with single-spa in the first year.&lt;/p&gt;

&lt;p&gt;To my surprise, most issues that have emerged in our codebase are general React pain points not specific to microfrontend architecture at all.&lt;/p&gt;

&lt;p&gt;In an effort to share knowledge, I'll address the most common React performance issue we've seen reemerge in our teams in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The state management problem
&lt;/h2&gt;

&lt;p&gt;Here's a really common hook pattern I've seen emerge at one point in most of our React microfrontend projects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// useFormState.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FormContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GlobalFormStateProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFormState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFormState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;FormContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useFormState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FormContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GlobalFormStateProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./useFormState&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GlobalFormStateProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;GlobalFormStateProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Form.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFormState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./useFormState&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;formState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFormState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/v1/submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FirstFormGroup&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SecondFormGroup&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FirstFormGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFormState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFormState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
          &lt;span class="nf"&gt;setFormState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;field1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
          &lt;span class="nf"&gt;setFormState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;field2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SecondFormGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFormState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFormState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field3&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
          &lt;span class="nf"&gt;setFormState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;field3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Many readers will immediately recognize antipatterns in the above example, but entertain the naïve perspective:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;useFormState()&lt;/code&gt; hook is very useful. No prop drilling. No fancy global state management libraries needed. Just native &lt;code&gt;React.useState()&lt;/code&gt; shared in a global Context.&lt;/p&gt;

&lt;p&gt;What's not to love here?&lt;/p&gt;

&lt;h2&gt;
  
  
  Perf issues
&lt;/h2&gt;

&lt;p&gt;As nice as &lt;code&gt;useFormState()&lt;/code&gt; seems, we'd quickly face performance issues due to components using it having to render on every &lt;code&gt;setFormState()&lt;/code&gt; causing unnecessary, potentially expensive re-renders.&lt;/p&gt;

&lt;p&gt;This is because we've subscribed all our Form components to re-render on all changes in &lt;code&gt;FormContext&lt;/code&gt; by using &lt;code&gt;React.useContext(FormContext)&lt;/code&gt; inside &lt;code&gt;useFormState()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You might think &lt;code&gt;React.memo&lt;/code&gt; to the rescue, but reading the &lt;a href="https://reactjs.org/docs/hooks-reference.html#usecontext" rel="noopener noreferrer"&gt;React docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the nearest  above the component updates, this Hook will trigger a re-render with the latest context value passed to that MyContext provider. Even if an ancestor uses React.memo or shouldComponentUpdate, a re-render will still happen starting at the component itself using useContext.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Further, we're unnecessarily depending on the full &lt;code&gt;formState&lt;/code&gt; object in all our form components.&lt;/p&gt;

&lt;p&gt;Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// formState is a dependency:&lt;/span&gt;
&lt;span class="nf"&gt;setFormState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;field1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;
&lt;span class="c1"&gt;// formState not a dependency:&lt;/span&gt;
&lt;span class="nf"&gt;setFormState&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;field1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this time, I would consider Context Providers using &lt;code&gt;React.useState&lt;/code&gt; to store complex global app state a general React performance antipattern.&lt;/p&gt;

&lt;p&gt;However, if React adds &lt;code&gt;useContextSelector&lt;/code&gt; (&lt;a href="https://github.com/reactjs/rfcs/pull/119" rel="noopener noreferrer"&gt;RFC&lt;/a&gt;) I am positive the situation could change. 🤞&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learned
&lt;/h2&gt;

&lt;p&gt;Seeing antipatterns like these emerge in React projects even with fairly experienced frontend developers (think 5+ years of React) has lead me to consider performance as a topic that unfortunately requires pretty significant investment to produce quality output when working with React in general.&lt;/p&gt;

&lt;p&gt;As always, there is &lt;a href="https://en.wikipedia.org/wiki/No_Silver_Bullet" rel="noopener noreferrer"&gt;No Silver Bullet&lt;/a&gt;. However, our frontend microservices architecture has enabled us to cheaply experiment with different approaches in different teams who have produced quite a few competing strategies to solve form performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use of global state management libraries e.g. &lt;a href="https://redux.js.org/" rel="noopener noreferrer"&gt;Redux&lt;/a&gt;, &lt;a href="https://mobx.js.org/README.html" rel="noopener noreferrer"&gt;MobX&lt;/a&gt; and &lt;a href="https://xstate.js.org/" rel="noopener noreferrer"&gt;XState&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use of dedicated form libraries e.g. &lt;a href="https://react-hook-form.com/" rel="noopener noreferrer"&gt;react-hook-form&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use of this implementation of &lt;a href="https://github.com/dai-shi/use-context-selector" rel="noopener noreferrer"&gt;useContextSelector&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Avoiding controlled form inputs (Leverage the web platform! 👐)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, thanks to the flexibility of &lt;a href="https://single-spa.js.org/" rel="noopener noreferrer"&gt;single-spa&lt;/a&gt; we've been able to experiment outside of the React ecosystem with frameworks like &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; and others which has been extremely promising and rewarding for our engineers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://epilot.cloud/en" 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.amazonaws.com%2Fuploads%2Farticles%2Fq660re5susj1a8efggrd.png" alt="epilot logo" width="800" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://promise.epilot.cloud/" rel="noopener noreferrer"&gt;We're hiring @ epilot!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>performance</category>
      <category>microservices</category>
      <category>svelte</category>
    </item>
  </channel>
</rss>
