<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://blog.jenyay.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.jenyay.com/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-04-22T00:18:25+00:00</updated><id>https://blog.jenyay.com/feed.xml</id><title type="html">Jenya Y.</title><subtitle>Personal blog of Jenya Y. — software engineering, AI, agents, cloud.</subtitle><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><entry><title type="html">“GPT Said” Is Not a Reference</title><link href="https://blog.jenyay.com/gpt-said-is-not-a-reference/" rel="alternate" type="text/html" title="“GPT Said” Is Not a Reference" /><published>2026-03-03T10:00:00+00:00</published><updated>2026-03-24T23:27:07+00:00</updated><id>https://blog.jenyay.com/gpt-said-is-not-a-reference</id><content type="html" xml:base="https://blog.jenyay.com/gpt-said-is-not-a-reference/"><![CDATA[<p>It keeps popping up in engineering discussions - design reviews, architecture threads, PR comments. Someone drops a take, and when asked to elaborate, the backup is: “Well, ChatGPT said…” or “According to Claude…”</p>

<p>As the industry matures with these tools, it’s getting better - but it’s worth addressing directly because the habit reveals something deeper than just sloppy attribution.</p>

<h2 id="llms-are-tools-not-sources">LLMs Are Tools, Not Sources</h2>

<p>When you say “GPT said X,” you’re doing two things at once, and both are wrong.</p>

<p>First, you’re treating an LLM as a source of authority. It’s not. An LLM is a tool that generates plausible text based on statistical patterns. It has no expertise, no reputation to protect, and no accountability. It can produce correct, well-reasoned output - and it can produce confident-sounding nonsense. Often in the same conversation.</p>

<p>Second, you’re deflecting ownership. “GPT said” is a subtle way of saying “don’t blame me if this is wrong.” But you’re the one who chose to bring it into the discussion. You’re the one presenting it. It’s your statement now.</p>

<h2 id="three-anti-patterns">Three Anti-Patterns</h2>

<h3 id="1-citing-the-oracle">1. Citing the Oracle</h3>

<blockquote>
  <p>“According to Claude, the best approach here is to use event sourcing.”</p>
</blockquote>

<p>This carries zero weight. You can’t trace it. You can’t reproduce it - ask the same question tomorrow and you might get the opposite recommendation. There’s no paper, no documentation, no implementation behind it. It’s an opinion from a next-token predictor dressed up as expert advice.</p>

<p>If event sourcing is the right call, explain <em>why</em> it’s the right call. What are the trade-offs? What alternatives did you consider? If you can’t do that, you don’t understand the recommendation well enough to make it.</p>

<h3 id="2-the-ai-pass-through">2. The AI Pass-Through</h3>

<p>This one is sneakier. Someone gets feedback from a senior or peer engineer. Instead of thinking it through, understanding the concern, and responding with their own reasoning - they copy the feedback into an LLM chat or agent, then copy-paste the response back.</p>

<p>The result reads fine. Grammatically correct. Technically plausible. But it’s empty calories. The person never actually engaged with the feedback. They outsourced the thinking, not just the typing.</p>

<p>This is worse than the oracle pattern because it breaks the feedback loop entirely. The whole point of a code review or design discussion is that two humans reason together. When you insert an LLM as a proxy, nobody is actually thinking.</p>

<h3 id="3-stopping-at-plausible">3. Stopping at Plausible</h3>

<p>LLMs are extremely good at producing answers that <em>sound</em> right. That’s literally what they’re optimized for. And that’s exactly what makes them dangerous when you stop at “sounds right” instead of pushing to “is right.”</p>

<p>You ask Claude about a race condition. It gives you a confident explanation with a clean code fix. You paste it in, tests pass, ship it. Three weeks later it blows up in production because the LLM’s mental model of your concurrency setup was subtly wrong. It didn’t know about that one edge case in your custom executor. It can’t - it never saw your runtime.</p>

<p>The plausible answer was the starting point, not the finish line.</p>

<h2 id="validation-is-the-actual-work">Validation Is the Actual Work</h2>

<p>Using agents and LLMs to get answers faster is fine. Obviously. But faster access to <em>candidate</em> answers means the bottleneck shifts to validation. And validation is now your job.</p>

<p><strong>Write a test.</strong> This is the easiest one. If an LLM tells you X is true about your system, write a small test that proves it. Ironically, the same AI tools are great at writing these validation tests - so use the agent to prove the agent isn’t lying. And honestly, this part is kinda satisfying. You can ask it to write a quick one-off script in whatever language - Python, Go, a shell one-liner - just to prove or disprove a single point. You look at it, run it, get your answer, and throw it away a minute later. Disposable code as a verification tool. Which is cool.</p>

<p><strong>Ask for sources, then check them.</strong> LLMs can often point you to documentation, RFCs, or source code that backs their claim. But here’s the thing - when you actually ask “where did you get this?”, a decent chunk of the time you’ll get either a real reference you can verify, or a sudden “Actually…” Which tells you everything you need to know.</p>

<p><strong>Read the code.</strong> AI tools are good at navigating and explaining source code. But don’t stop at the explanation - open the actual implementation, read it, run and debug. The code is the ground truth. The explanation is a hypothesis.</p>

<p><strong>Cross-reference.</strong> If you’re making an architectural decision based on something an LLM told you, spend five minutes checking docs or other sources. If you can’t find independent confirmation, that’s a signal.</p>

<h2 id="this-isnt-about-being-anti-ai">This Isn’t About Being Anti-AI</h2>

<p>I use these tools constantly. They’re genuinely useful for moving faster, exploring unfamiliar codebases, generating boilerplate, rubber-ducking ideas. The productivity gains are real.</p>

<p>But there’s a difference between using a tool and hiding behind one. A calculator doesn’t make you a mathematician. An LLM doesn’t make you an architect. The value you bring is judgment - knowing when the output is right, when it’s subtly wrong, and when the question itself needs rethinking.</p>

<p>So next time you catch yourself reaching for “according to GPT…” or “Claude thinks…” - just don’t. If you believe the statement, own it. Explain your reasoning. If you can’t explain it without citing the AI, you haven’t done the work yet.</p>]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="ai" /><category term="software-engineering" /><category term="agents" /><summary type="html"><![CDATA[It keeps popping up in engineering discussions - design reviews, architecture threads, PR comments. Someone drops a take, and when asked to elaborate, the backup is: “Well, ChatGPT said…” or “According to Claude…”]]></summary></entry><entry><title type="html">Agents are fast. You’re responsible.</title><link href="https://blog.jenyay.com/agents-are-fast-youre-responsible/" rel="alternate" type="text/html" title="Agents are fast. You’re responsible." /><published>2026-01-22T10:00:00+00:00</published><updated>2026-04-22T00:09:55+00:00</updated><id>https://blog.jenyay.com/agents-are-fast-youre-responsible</id><content type="html" xml:base="https://blog.jenyay.com/agents-are-fast-youre-responsible/"><![CDATA[<p>If you’ve been shipping software for a while, you’ve seen this movie: memory management got abstracted, compilers got smarter, the web happened, containers happened. Each wave has people who already onboarded and are running - and people who are skeptical, didn’t have time, or are stuck trying to figure out what the “right” workflow even looks like.</p>

<p>Agentic coding is the same. The tool is real. The manual is… crowd-sourced.</p>

<hr />

<h2 id="november-2025-the-inflection-point">November 2025: The Inflection Point</h2>

<p>The CLI agentic tools started appearing in early 2025. <a href="https://claude.com/product/claude-code">Claude Code</a> launched in February as a research preview. Cursor shipped agent mode. OpenAI released Codex CLI. <a href="https://aider.chat/">Aider</a> had been around since 2023, quietly building a following. The tooling was ready.</p>

<p>But the models weren’t there yet. If you tried these tools in early 2025, results were hit-or-miss. Agents would confidently produce code that didn’t quite work, hallucinate APIs, or get stuck in loops. Andrej Karpathy <a href="https://www.dwarkesh.com/p/andrej-karpathy">captured the sentiment</a> many developers felt: agents “just don’t work” because “they don’t have enough intelligence, they’re not multimodal enough” and “they’re cognitively lacking.” For many, autocomplete was the sweet spot - anything more autonomous felt like a dead end.</p>

<p>Then November 2025 happened.</p>

<p>Within weeks of each other, three major model releases landed: <a href="https://www.anthropic.com/news/claude-sonnet-4-5">Claude Sonnet 4.5</a> (late September), <a href="https://blog.google/products/gemini/gemini-3/">Gemini 3.0</a> (November 18), and <a href="https://www.anthropic.com/news/claude-opus-4-5">Claude Opus 4.5</a> (November 24). GPT-5.2 followed in December. These weren’t incremental improvements - they crossed a threshold. The models could reliably understand context, make coherent multi-file changes, recover from errors, and complete agentic workflows end-to-end.</p>

<p>The CLI tools that had been waiting for capable models suddenly had them. The shift happened, but it took a few weeks for people to notice. Most of us, myself included, only realized somewhere around Christmas that we had something fundamentally new in our hands. Not “better autocomplete” - a different tool entirely.</p>

<p>By the time the holidays ended, the reactions from people who’ve been writing code for decades started pouring in:</p>

<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin: 30px 0; font-size: 0.95em;">
  <div style="background: #1e1e1e; padding: 20px; border-radius: 8px; border-left: 3px solid #4a9eff;">
    <p style="margin: 0 0 12px 0; line-height: 1.5; color: #e0e0e0;">"It does not matter if AI companies will not be able to get their money back and the stock market will crash. All that is irrelevant, in the long run.... Programming changed forever, anyway."</p>
    <p style="margin: 0; color: #888; font-size: 0.9em;">— <strong>Salvatore Sanfilippo</strong>, creator of Redis</p>
  </div>
  <div style="background: #1e1e1e; padding: 20px; border-radius: 8px; border-left: 3px solid #4ade80;">
    <p style="margin: 0 0 12px 0; line-height: 1.5; color: #e0e0e0;">"Software engineering is radically changing, and the hardest part even for early adopters and practitioners like us is to continue to re-adjust our expectations."</p>
    <p style="margin: 0; color: #888; font-size: 0.9em;">— <strong>Boris Cherny</strong>, author of Programming TypeScript</p>
  </div>
  <div style="background: #1e1e1e; padding: 20px; border-radius: 8px; border-left: 3px solid #f4a261; grid-column: span 2;">
    <p style="margin: 0 0 12px 0; line-height: 1.5; color: #e0e0e0;">"Clearly some powerful alien tool was handed around, except it comes with no manual and everyone has to figure out how to hold and operate it while the resulting magnitude 9 earthquake is rocking the profession. Roll up your sleeves to not fall behind."</p>
    <p style="margin: 0; color: #888; font-size: 0.9em;">— <strong>Andrej Karpathy</strong>, former Tesla AI Director</p>
  </div>
  <div style="background: #1e1e1e; padding: 20px; border-radius: 8px; border-left: 3px solid #e63946;">
    <p style="margin: 0 0 12px 0; line-height: 1.5; color: #e0e0e0;">"LLMs are going to help us to write better software, faster, and will allow small teams to have a chance to compete with bigger companies. The same thing open source software did in the 90s."</p>
    <p style="margin: 0; color: #888; font-size: 0.9em;">— <strong>Linus Torvalds</strong></p>
  </div>
  <div style="background: #1e1e1e; padding: 20px; border-radius: 8px; border-left: 3px solid #9d4edd;">
    <p style="margin: 0 0 12px 0; line-height: 1.5; color: #e0e0e0;">"I don't want to be too dramatic, but y'all have to throw away your priors. The cost of software production is trending towards zero."</p>
    <p style="margin: 0; color: #888; font-size: 0.9em;">— <strong>Malte Ubl</strong>, former Google engineering lead</p>
  </div>
</div>

<p>If you’re still skeptical, you’re out of step with where a lot of serious builders already are. The people above aren’t easily impressed, and they’re not selling anything. The shift is already underway. The question is whether you’ll adopt it intentionally or accidentally.</p>

<h2 id="the-agent-loop">The Agent Loop</h2>

<p>Forget magic. An agent is a <code class="language-plaintext highlighter-rouge">while</code> loop.</p>

<p>You give it a goal. It calls an LLM. The LLM either produces a response (done) or requests a tool call (read a file, run a command, make an API request). The tool executes, the result goes back to the LLM, and the loop continues. That’s it. No neural networks communicating telepathically. Just a loop.</p>

<div style="float: right; width: 286px; margin: 0 0 10px 20px;">
  <a href="javascript:void(0)"><img src="/content/images/2026/01/just-a-while-loop.jpg" alt="Just a while loop" style="border-radius: .625rem;" /></a>
</div>

<div style="max-width: calc(100% - 310px);" class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
  <span class="n">response</span> <span class="o">=</span> <span class="n">llm</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
  <span class="k">if</span> <span class="n">response</span><span class="p">.</span><span class="n">has_tool_call</span><span class="p">:</span>
    <span class="n">result</span> <span class="o">=</span> <span class="nf">execute_tool</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">tool_call</span><span class="p">)</span>
    <span class="n">context</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
  <span class="k">else</span><span class="p">:</span>
   <span class="k">return</span> <span class="n">response</span><span class="p">.</span><span class="n">text</span>
</code></pre></div></div>

<div style="clear: both;"></div>

<p>If you’ve written a CI pipeline, a bash script that retries on failure, or a REPL - you already understand this. Same pattern: automated execution with feedback. The difference is the decision-making happens via LLM inference rather than hard-coded <code class="language-plaintext highlighter-rouge">if</code> statements.</p>

<p>All major vendors document this loop explicitly:</p>

<ul>
  <li>Anthropic’s <a href="https://code.claude.com/docs/en/how-claude-code-works">How Claude Code works</a> describes it as a “single-threaded master loop” - <code class="language-plaintext highlighter-rouge">while(tool_use) → execute → feed results → repeat</code></li>
  <li>OpenAI’s <a href="https://openai.com/index/unrolling-the-codex-agent-loop/">Codex agent loop</a> documentation walks through the same pattern</li>
</ul>

<p>The industry converged on this design because it works. Simple and debuggable.</p>

<blockquote>
  <p><strong>“Isn’t this just Copilot with extra steps?”</strong>
No. Copilot predicts your next few characters. Agents execute multi-step workflows - refactoring across files, running tests, fixing failures, iterating until tests pass. Different category entirely.</p>
</blockquote>

<h2 id="typing-was-never-the-job">Typing Was Never the Job</h2>

<p>Here’s something nobody told you in university: typing code was always a waste of time.</p>

<p>Think about it. CS programs teach algorithms, data structures, system design, discrete math. They don’t teach you to type faster. Why? Because typing was never the core skill. It was just… overhead. A necessary friction between the idea in your head and the running system.</p>

<p>We figured this out decades ago. Assembly programmers wrote one line per CPU instruction. Then we invented higher-level languages where a single line compiles into hundreds of instructions. Then we added frameworks, libraries, ORMs - each layer letting us type less while doing more. The entire history of programming is a march toward typing less. Agents are just the next step.</p>

<p>The best engineers I’ve worked with aren’t fast typists. They’re fast thinkers. They spend more time at whiteboards, in design docs, reading existing code - and less time with their fingers on the keyboard. The typing part was always the easy part. The thinking was hard.</p>

<p>Agents just made this obvious.</p>

<div style="display: flex; flex-direction: column; align-items: center; margin: 20px 0;">
<div style="width: 75%">
  <a href="javascript:void(0)"><img src="/content/images/2026/01/bottleneck-shift.jpg" alt="Bottleneck Shift" /></a></div>
  <em style="margin-top: 8px;">Where you spend time has fundamentally changed</em>
</div>

<p>Agents are extremely good at the mechanical parts of coding:</p>

<ul>
  <li>Writing boilerplate</li>
  <li>Refactoring across files</li>
  <li>Navigating large codebases</li>
  <li>Applying patterns consistently</li>
</ul>

<p>They’re bad at:</p>

<ul>
  <li>Knowing what to build</li>
  <li>Understanding why something matters</li>
  <li>Making trade-off decisions</li>
  <li>Recognizing when requirements are wrong</li>
</ul>

<p>The bottleneck moved. It used to be typing. Now it’s thinking.</p>

<p>This has a practical implication: the few minutes you spend thinking before opening an agent session will save hours of cleanup. The agent will happily generate 500 lines of code that solves the wrong problem. Faster.</p>

<h2 id="youre-the-tech-lead-now">You’re the Tech Lead Now</h2>

<p>Agents don’t replace developers. They behave like very fast, very junior, very confident engineers who never push back, never ask clarifying questions, and never tell you your requirements are wrong.</p>

<p>Sound familiar? That’s a junior dev who needs supervision. Except this one types at 10,000 words per minute.</p>

<p>Your job changed. You now:</p>

<ul>
  <li>Define intent and scope</li>
  <li>Break down work into digestible pieces</li>
  <li>Review outputs critically</li>
  <li>Correct direction when it drifts</li>
  <li>Make judgment calls the agent can’t</li>
</ul>

<p>That’s tech lead work. Every developer working with agents is now managing a tireless but context-blind junior. The question isn’t whether you can code faster - it’s whether you can think clearly enough to direct that speed productively.</p>

<p>There’s an old IBM training slide from 1979:</p>

<div style="display: flex; flex-direction: column; align-items: center; margin: 20px 0;">
  <a href="javascript:void(0)"><img src="/content/images/2026/01/accountable.jpg" alt="IBM 1979: A computer can never be held accountable" style="border-radius: .625rem;" /></a>
</div>

<p>Replace “computer” with “agent” and nothing changes. Agents are tools, not authors. You’re still accountable for what gets committed.</p>

<p>This matters because agents are genuinely bad at things that require judgment:</p>

<ul>
  <li>Understanding product intent (why are we building this?)</li>
  <li>Evaluating architectural tradeoffs (is this the right abstraction?)</li>
  <li>Recognizing non-obvious constraints (will this scale? Is this secure?)</li>
  <li>Considering long-term consequences (how will this affect the codebase in a year?)</li>
</ul>

<p>They optimize for local correctness and surface-level patterns. They’ll write code that compiles, passes the tests you gave them, and completely misses the point.</p>

<p>Human judgment remains irreplaceable: defining what matters, rejecting wrong-but-working solutions, keeping systems coherent over time. AI makes it trivially easy to produce code you don’t understand. This is technical debt in its purest form - you’ll pay for it during debugging, maintenance, and every code review.</p>

<blockquote>
  <p><strong>“Won’t this destroy code quality?”</strong>
Only if we let it. Agents don’t remove responsibility - they concentrate it.</p>
</blockquote>

<h2 id="work-in-phases-not-prompts">Work in Phases, Not Prompts</h2>

<p>Here’s the mistake most people make: they treat agents like a chat interface. Type a prompt, get code, paste it somewhere. That’s not agentic coding. That’s autocomplete with extra steps.</p>

<p>Real agentic work is phased. You don’t write a novel in one sentence, and you don’t build software in one prompt. The phases matter because they force you to think before generating, and because agents perform dramatically better when you separate concerns.</p>

<p><strong>The four phases:</strong></p>

<h3 id="1-problem-definition">1. Problem Definition</h3>

<p>Before touching any code, clarify what you’re actually building. This happens in a separate conversation or an explicit “planning mode.”</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I need to implement [feature]. Here's the context:
- Current state: [what exists]
- Requirements: [what it should do]
- Constraints: [performance, compatibility, security]

What are my options? What trade-offs should I consider?
</code></pre></div></div>

<p>This phase is cheap. A few minutes of thinking. The agent helps you explore the problem space, surface edge cases you hadn’t considered, identify risks early. No code written yet.</p>

<h3 id="2-design-refinement">2. Design Refinement</h3>

<p>Once you have options, interrogate them. Push back. Ask hard questions.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Option B looks promising. But:
- How would this handle [edge case]?
- What's the failure mode if [scenario]?
- How does this integrate with [existing component]?
</code></pre></div></div>

<p>This is iterative. The agent proposes, you challenge, it refines. Still no implementation. You’re building a mental model and a shared understanding of what “done” looks like.</p>

<h3 id="3-implementation">3. Implementation</h3>

<p>Only now do you write code. And critically - you write it with explicit constraints from the previous phases.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Let's implement the approach we discussed. Starting with [component].
Key decisions we made:
- [Decision 1]: [rationale]
- [Decision 2]: [rationale]

Do not deviate from these without asking first.
</code></pre></div></div>

<p>The agent has context. It knows what you decided and why. It’s not guessing anymore.</p>

<h3 id="4-review--validation">4. Review &amp; Validation</h3>

<p>Never accept generated code blindly. Review the diff. Run the tests. Verify it actually does what you discussed.</p>

<p>This is also where testing happens. Some prefer test-driven development - writing tests before implementation. Either way, you need to be explicit with agents about testing:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Write tests for [component]. Specifically:
- Test [happy path scenario]
- Test [edge case 1]
- Test [error handling scenario]
- Mock [external service] - don't hit real endpoints
- Use real [database/cache] - no mocking for integration tests
- Do NOT test [implementation details that might change]
</code></pre></div></div>

<p>Agents will happily generate 50 tests that all test the same thing, or mock everything including the code you’re actually trying to verify. Be specific about what to test, how to test it, what to mock, and what should stay real.</p>

<p>This is where most time savings evaporate if you skip phases 1-3 - you end up debugging code you don’t understand that solves a problem you didn’t fully define.</p>

<hr />

<p>These phases aren’t bureaucracy. They’re how you turn a chaotic code generator into a reliable collaborator. Skip them and you’ll spend more time fixing agent output than you saved generating it.</p>

<h2 id="prompts-are-contracts">Prompts Are Contracts</h2>

<div style="float: right; margin: 0 0 10px 20px; max-width: 280px;">
  <a href="javascript:void(0)"><img src="/content/images/2026/01/the-new-language.jpg" alt="Karpathy tweet: The hottest new programming language is English" style="border-radius: .625rem;" /></a>
</div>

<p>Prompting is API design, not conversation.</p>

<p>Think about what makes a good API: clear inputs, defined outputs, explicit constraints, predictable behavior. Bad APIs accept anything and return surprises. Good APIs are strict about what they accept and consistent in what they return.</p>

<p>Same with prompts. “Fix this bug” is a bad API - undefined input, no constraints, unpredictable output. “This endpoint returns 500 when the user ID is null. Here’s the error log and the handler code. What’s causing this and what are my options?” is a good API - scoped input, clear context, defined expectation.</p>

<p>The difference in output quality is dramatic. Vague prompts produce vague code. Specific prompts produce specific solutions.</p>

<p>A few principles that help:</p>

<p><strong>Scope aggressively.</strong> Don’t let agents roam freely across your codebase. Tell them exactly which files to touch and which to leave alone. “Modify only <code class="language-plaintext highlighter-rouge">src/handlers/payment.ts</code>” beats “fix the payment flow.” Smaller blast radius means easier review and fewer surprises.</p>

<p><strong>Make constraints explicit.</strong> Agents don’t know your conventions unless you tell them. “Use our existing error format from <code class="language-plaintext highlighter-rouge">src/errors.ts</code>” or “Don’t add new dependencies” or “Keep the public API unchanged.” These aren’t obvious to an agent looking at your code for the first time.</p>

<p><strong>Define what done looks like.</strong> “Implement caching” is ambiguous. “Add Redis caching for the <code class="language-plaintext highlighter-rouge">/users/:id</code> endpoint with 5-minute TTL, using our existing Redis client in <code class="language-plaintext highlighter-rouge">src/infra/cache.ts</code>” is actionable. The agent can verify its own work against concrete criteria.</p>

<p><strong>Separate concerns.</strong> Avoid implementation and tests in the same prompt. The agent will write tests that pass its own code - which tells you nothing. Generate code, review it, then separately ask for tests with explicit guidance on what to cover.</p>

<blockquote>
  <p><strong>“What about security?”</strong>
Same as any automation. Scope, permissions, review. The danger is pretending agents are harmless because they feel conversational.</p>
</blockquote>

<h2 id="the-agent-instructions-file">The Agent Instructions File</h2>

<p>The instructions file (<code class="language-plaintext highlighter-rouge">AGENTS.md</code>, <code class="language-plaintext highlighter-rouge">CLAUDE.md</code>, <code class="language-plaintext highlighter-rouge">.cursorrules</code>, etc.) is the single most impactful thing you can optimize. This file affects every interaction the agent has with your codebase. A well-crafted file multiplies the effectiveness of every prompt you write.</p>

<table>
  <thead>
    <tr>
      <th>Do</th>
      <th>Don’t</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Keep it short and scannable</td>
      <td>Write walls of text</td>
    </tr>
    <tr>
      <td>Be specific and actionable</td>
      <td>Use vague guidance</td>
    </tr>
    <tr>
      <td>Explain <em>why</em> behind rules</td>
      <td>Just list rules without context</td>
    </tr>
    <tr>
      <td>Update it constantly</td>
      <td>Set and forget</td>
    </tr>
    <tr>
      <td>Focus on this repo’s specifics</td>
      <td>Repeat generic coding standards</td>
    </tr>
  </tbody>
</table>

<h3 id="global-instructions">Global Instructions</h3>

<p>You should define global instructions that apply across all your projects - personal preferences, coding style, behavioral defaults. These are “how I work” regardless of what codebase I’m in.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># Global Instructions</span>

<span class="gu">## Communication Style</span>
<span class="p">-</span> Write as if talking to a peer engineer
<span class="p">-</span> Avoid filler, hype, or disclaimers
<span class="p">-</span> Ask for clarification when context is ambiguous
<span class="p">-</span> Don't restate the obvious

<span class="gu">## Coding Conventions</span>
<span class="p">-</span> Keep code clean and modular, but aim for simplicity
<span class="p">-</span> Add comments only for unusual logic or rationale
<span class="p">-</span> Always include type annotations
<span class="p">-</span> Assume every project has linter and styling rules

<span class="gu">## Architecture Principles</span>
<span class="p">-</span> Prefer composition over inheritance
<span class="p">-</span> Use dependency injection for testability
<span class="p">-</span> Adhere to SOLID principles

<span class="gu">## Behavioral Defaults</span>
<span class="p">-</span> Prefer compact answers unless detail is essential
<span class="p">-</span> When adding tests, always find a way to run them
<span class="p">-</span> Keep documentation in sync with code changes
</code></pre></div></div>

<h3 id="project-instructions">Project Instructions</h3>

<p>Project files layer specifics on top - “how this codebase works.”</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># Project: my-service</span>

Backend service handling payment processing.

<span class="gs">**Tech Stack:**</span> Node.js 22.x, TypeScript, Express, PostgreSQL

<span class="gu">## Development Setup</span>

npm install
docker-compose up -d # starts Postgres
npm start # runs on port 4024

<span class="gu">## Testing</span>

npm test # runs all tests (requires Postgres)
npm test -- path/to/file.spec.ts # single file

<span class="gu">## Architecture</span>

<span class="gu">### Entry Points</span>
<span class="p">
1.</span> <span class="gs">**REST API**</span> - Handler: <span class="sb">`apiHandler`</span>
<span class="p">2.</span> <span class="gs">**Event Consumer**</span> - Handler: <span class="sb">`eventProcessor`</span>
<span class="p">   -</span> Trigger: SQS messages from <span class="sb">`payments-queue`</span>

<span class="gu">### Key Patterns</span>
<span class="p">
-</span> All handlers use dependency injection via constructor
<span class="p">-</span> Database access only through repository classes
<span class="p">-</span> External API calls wrapped in circuit breakers

<span class="gu">## Conventions</span>
<span class="p">
-</span> Error responses use RFC 7807 format
<span class="p">-</span> All amounts stored as integers (cents)
<span class="p">-</span> Timestamps in UTC, ISO 8601 format
</code></pre></div></div>

<p>Treat both as API contracts for agents. Changes should be intentional and reviewed, just like code.</p>

<h2 id="context-management">Context Management</h2>

<p>A critical insight: context degradation begins around 70% usage, not at 100%. Long conversations lead to:</p>

<ul>
  <li>Forgotten earlier instructions</li>
  <li>Contradictory suggestions</li>
  <li>Repeated mistakes you already corrected</li>
  <li>Declining code quality</li>
</ul>

<p><strong>Signs your context is degraded:</strong></p>

<ul>
  <li>Agent forgets constraints you stated earlier</li>
  <li>Suggestions contradict previous decisions</li>
  <li>Quality noticeably drops from earlier in the conversation</li>
  <li>Agent starts “looping” on the same approaches</li>
</ul>

<h3 id="strategies">Strategies</h3>

<p><strong>1. Scope Conversations Tightly</strong></p>

<p>One task per conversation. Don’t let sessions sprawl across unrelated concerns.</p>

<ul>
  <li>Good: “Implement the payment validation endpoint”</li>
  <li>Bad: “Let’s work on the payment service” → then drift through five different features</li>
</ul>

<p><strong>2. The Copy-Paste Reset Technique</strong></p>

<p>When context is degraded but you have useful progress:</p>

<ol>
  <li>Ask the agent to summarize the current state, decisions made, and remaining work</li>
  <li>Start a fresh conversation</li>
  <li>Paste the summary as your opening context</li>
  <li>Continue with a clean context window</li>
</ol>

<p>This gives you the benefits of accumulated progress without the degradation.</p>

<p><strong>3. Use External Memory</strong></p>

<p>Don’t rely solely on conversation history. Externalize important decisions:</p>

<ul>
  <li>Update your instructions file with new patterns or constraints discovered during work</li>
  <li>Maintain a scratchpad file for complex multi-step tasks</li>
  <li>Document architectural decisions in your design docs</li>
</ul>

<h2 id="when-youre-stuck">When You’re Stuck</h2>

<p>If you find yourself:</p>

<ul>
  <li>Asking the same question multiple ways</li>
  <li>Getting similar unhelpful responses</li>
  <li>Watching the agent repeat the same mistake</li>
  <li>Feeling frustrated with the output</li>
</ul>

<p>You’re in a loop. Don’t keep iterating - change your approach.</p>

<p><strong>Breaking Out:</strong></p>

<ol>
  <li>
    <p><strong>Clear and Restart</strong> - Start a fresh conversation. Rephrase your goal from scratch. Often the accumulated context is the problem.</p>
  </li>
  <li>
    <p><strong>Simplify the Problem</strong> - Can you solve a smaller version first? Can you isolate the confusing part? Are you asking multiple things at once?</p>
  </li>
  <li>
    <p><strong>Show, Don’t Tell</strong> - Instead of explaining what you want, show an example. Provide a working snippet and ask for something similar.</p>
  </li>
  <li>
    <p><strong>Reframe the Problem</strong> - Instead of “how do I fix X” → “what are the possible causes of X”. Instead of “implement feature Y” → “what’s the simplest way to achieve Y given these constraints”.</p>
  </li>
  <li>
    <p><strong>Change Tools</strong> - Different LLMs have different strengths. If one isn’t working, try another.</p>
  </li>
</ol>

<hr />

<h2 id="the-title-revisited">The Title, Revisited</h2>

<p>Agents are fast. That part is obvious now. They’ll generate code faster than you can read it, refactor entire modules in seconds, and never complain about tedious tasks.</p>

<p>But speed without direction just gets you lost faster.</p>

<p>The title of this post isn’t “Agents are fast, isn’t that great?” It’s “Agents are fast. You’re responsible.” The period matters. These are two separate statements. The first is a fact about the tool. The second is a fact about you.</p>

<p>Everything I’ve described - the phases, the contracts, the instructions files, the context management - exists to bridge that gap. To turn raw speed into directed progress. To ensure that when code hits production, someone understood it, validated it, and chose to ship it.</p>

<p>The tools will keep getting better. The models will keep improving. What won’t change is accountability. You’re still the engineer. You still own what gets committed. The agent is just a very fast, very eager collaborator that needs clear direction and constant supervision.</p>

<p>Use that speed wisely.</p>]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="ai" /><category term="agents" /><category term="software-engineering" /><summary type="html"><![CDATA[If you’ve been shipping software for a while, you’ve seen this movie: memory management got abstracted, compilers got smarter, the web happened, containers happened. Each wave has people who already onboarded and are running - and people who are skeptical, didn’t have time, or are stuck trying to figure out what the “right” workflow even looks like.]]></summary></entry><entry><title type="html">Technical Design Documents</title><link href="https://blog.jenyay.com/technical-design-docs/" rel="alternate" type="text/html" title="Technical Design Documents" /><published>2022-09-10T09:00:00+00:00</published><updated>2022-09-10T09:00:00+00:00</updated><id>https://blog.jenyay.com/technical-design-docs</id><content type="html" xml:base="https://blog.jenyay.com/technical-design-docs/"><![CDATA[<p><img src="/content/images/2022/09/design-docs-kid-drawing.jpg" alt="Kids working on a design" class="right" width="250" /></p>

<p>Design docs get a bad rap. Some teams treat them like bureaucratic overhead, others like sacred scripture that must be followed to the letter. Both miss the point.</p>

<p>The real purpose of design documentation isn’t uniformity or process compliance. It’s about articulating, sharing, and refining ideas <em>before</em> you start writing code. Whether that’s a 10-page spec or a whiteboard sketch - the format matters less than the thinking it forces you to do.</p>

<p>These documents - whether a brief outline, a structured specification, or simply a whiteboard sketch - serve to capture core objectives, constraints, and anticipated challenges early on. This proactive approach improves alignment, reduces misunderstandings, and ultimately increases the quality of the end product.</p>

<h2 id="why-bother">Why Bother?</h2>

<p>The cost of fixing mistakes grows exponentially as a project moves through its lifecycle. <a href="https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670">Code Complete</a> famously illustrates this with the “cost of mistake” curve:</p>

<div style="text-align:center">
  <img src="/content/images/2022/09/design-docs-cost-table.jpg" alt="Cost of mistake table" style="width: 75%; display: block; margin: auto" />
  <br /><em>Cost multipliers for fixing defects found at different phases (from Code Complete)</em>
</div>
<p><br />
A requirements mistake caught during requirements costs 1x to fix. Catch it post-deploy? That’s 10-100x. Design mistakes follow a similar pattern. Design documents act as an early safeguard - catching issues before they multiply in cost and complexity. Nothing fancy here.</p>

<h2 id="when-to-write-one">When to Write One</h2>

<p>Not every task needs a design doc. Here’s when it actually helps:</p>

<p><strong>1. New Features or Major Enhancements.</strong>
Documenting the design clarifies functionality, dependencies, and architectural impact. The trigger is obvious, but some folks skip this step and regret it later.</p>

<p><strong>2. Complex Dependencies or Cross-Team Integration.</strong>
Features that touch multiple teams or rely on external systems need extra clarity. A design doc helps map out dependencies, integration points, and cross-functional impacts. Reduces last-minute surprises.</p>

<p><strong>3. Significant Refactoring.</strong>
Major refactoring efforts - especially those impacting core architecture or shared components - benefit from documented objectives and anticipated outcomes. It also lets teammates discuss alternative approaches before anyone writes code.</p>

<p><strong>4. Technical Challenges and Unknowns.</strong>
POCs, feasibility studies, creative problem-solving under constraints. A design doc becomes a platform to hypothesize solutions, evaluate feasibility, and gather feedback. Particularly valuable when choosing between multiple approaches.</p>

<p><strong>5. High-Impact or Customer-Facing Changes.</strong>
Anything that directly impacts user experience or has high bug risk. Design documentation helps anticipate issues and evaluate risks upfront.</p>

<h2 id="when-to-skip-it">When to Skip It</h2>

<p>Sometimes the design you create in your head is enough. What matters is that you’ve thought through the approach before diving in.</p>

<p><strong>Design docs are overhead.</strong> If the task is small, well-understood, and unlikely to benefit from broader discussion, skip the doc. For trivial fixes, minor tweaks, or isolated refactoring - just write good comments in your code explaining the reasoning.</p>

<p><strong>When it reads like an implementation manual.</strong> If your design document feels like step-by-step instructions, stop. Break the work into tickets instead. Design docs should focus on “what” and “why”, not granular “how”.</p>

<p><strong>Known problems.</strong> For routine problems already solved repeatedly in similar ways, just refer to existing templates or past solutions. Don’t duplicate effort.</p>

<h2 id="types-of-design-documents">Types of Design Documents</h2>

<p>Three practical options:</p>

<p><strong>1. High-Level Overview.</strong>
For early brainstorming or stakeholder alignment. Captures main goals, constraints, and basic technical direction. No formal structure needed - its purpose is capturing and communicating key ideas. This is probably the most common type. Typically 3-7 pages, balancing clarity and detail. Good enough for most scenarios.</p>

<p><strong>2. Detailed Design Specification.</strong>
When technical depth or cross-team coordination is essential. Includes specific functional requirements, architectural considerations, and diagrams for complex data flows. Follows a more formal structure.</p>

<p><strong>3. Whiteboard Sketch or Quick Diagram.</strong>
Sometimes a photo of a whiteboard is all you need. Great for simple tasks or ideation sessions. Less formal but effective for getting ideas across quickly.</p>

<blockquote>
  <p>💡 The goal is to make documenting your design simple and approachable. Choose the type that fits your needs. There’s no rigid template.</p>
</blockquote>

<h2 id="writing-good-design-docs">Writing Good Design Docs</h2>

<p><strong>Start with the Problem.</strong>
A good design document starts with a clear articulation of the problem, the context, and why it matters. If product requirements exist, translate them into technical terms:</p>

<ul>
  <li><strong>Product Requirement</strong>: “Users should be able to see their recent transactions instantly.”</li>
  <li><strong>Technical Problem Statement</strong>: “Design a low-latency API and caching strategy to retrieve and display recent transactions within 200ms.”</li>
</ul>

<p><strong>Clarity Over Perfection.</strong>
A design doesn’t need to be perfect - it needs to be understandable. Focus on communicating core ideas, key decisions, and trade-offs. Use simple terms and visualize whenever possible, even if you feel uncomfortable drawing. Diagrams and flowcharts often communicate complex ideas more effectively than text.</p>

<p><strong>Provide a High-Level Overview.</strong>
Focus on which parts of the system will be created or modified and how they relate to each other. Prioritize logical relationships over technical details like protocols or database types.</p>

<div style="display:flex; flex-direction:column;align-items: center;margin-bottom: 15px">
  <div style="background: #121212; padding: 5px 10px; border: 1px solid #444;max-width: 80%">
    <img src="/content/images/2022/09/system-diagram.jpg" alt="High-level system diagram" style="" />
  </div>
  <div><i>Example: High-level system diagram showing component relationships</i></div>
</div>

<p>It’s also valuable to include a System Context Diagram showing how the solution fits into the overall platform:</p>

<div style="display:flex; flex-direction:column;align-items: center;margin-bottom: 15px">
  <div style="background: #121212; padding: 5px 10px; border: 1px solid #444;">
    <img src="/content/images/2022/09/design-docs-context-diagram.jpg" alt="System Context Diagram" />
  </div>
  <div><i>System Context Diagram - shows interactions between your solution and external systems</i></div>
</div>

<p><strong>Document Key Decisions and Trade-offs.</strong>
A design isn’t just about “what” you’re building but also “why”. Capture the reasoning behind major decisions, including alternatives you considered and why you rejected them.</p>

<p>For example:</p>
<ul>
  <li><strong>Decision</strong>: Cache the last 50 transactions per user in an in-memory store</li>
  <li><strong>Trade-off</strong>: Improves API response time but introduces stale data risk if cache invalidation is delayed</li>
  <li><strong>Alternative Considered</strong>: Query database directly for each request. Rejected due to performance degradation under heavy load.</li>
</ul>

<blockquote>
  <p>💡 Every decision involves a trade-off. Capturing these ensures transparency and avoids revisiting the same discussions later.</p>
</blockquote>

<p><strong>Consider Your Audience.</strong>
Some designs are reviewed by deeply technical teammates. Others need to be presented to product teams or stakeholders with minimal technical background. Tailor accordingly.</p>

<p><strong>Iterate.</strong>
Don’t aim for a complete final document on your first try. Begin with a rough draft, refine based on feedback. Share for feedback once the main idea is communicated clearly - not while it’s half-baked. Think through potential challenges reviewers may raise and address them preemptively.</p>

<p>Design documents are living artifacts. Update them as the project evolves or new decisions are made. They should remain a reliable source of truth throughout the project lifecycle.</p>

<h2 id="references">References</h2>

<p><strong>Books and Articles</strong></p>
<ul>
  <li><a href="https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670">Code Complete</a> by Steve McConnell - practical advice on software construction</li>
  <li><a href="https://www.amazon.com/Designing-Data-Intensive-Applications-Reliable-Maintainable/dp/1449373321">Designing Data-Intensive Applications</a> by Martin Kleppmann - system design challenges and trade-offs</li>
  <li>Martin Fowler’s <a href="https://martinfowler.com/articles/scaling-architecture-conversationally.html">Architecture Decision Records</a> - documenting architectural decisions effectively</li>
</ul>

<p><strong>Online Resources</strong></p>
<ul>
  <li><a href="https://github.com/donnemartin/system-design-primer">System Design Primer</a> (GitHub) - system design resources and examples</li>
  <li><a href="https://aws.amazon.com/architecture/well-architected/">AWS Well-Architected Framework</a> - best practices for scalable cloud systems</li>
  <li><a href="https://sre.google/sre-book/table-of-contents/">Google’s Site Reliability Engineering Guide</a> - engineering reliable systems</li>
</ul>

<p><strong>Diagrams and Visualization Tools</strong></p>
<ul>
  <li><a href="https://www.lucidchart.com/">Lucidchart</a>, <a href="https://app.diagrams.net/">draw.io</a>, <a href="https://www.websequencediagrams.com/">WebSequenceDiagrams</a> - clear, shareable visuals</li>
  <li><a href="https://c4model.com/">C4 Model</a> - lightweight approach to architecture diagrams focusing on clarity and hierarchy</li>
</ul>

<p><strong>Case Studies</strong></p>
<ul>
  <li><a href="https://www.uber.com/blog/engineering/">Uber Engineering Blog</a> - large-scale system design challenges</li>
  <li><a href="https://netflixtechblog.com/">Netflix Tech Blog</a> - architectural patterns and trade-offs at scale</li>
  <li><a href="https://highscalability.com/">High Scalability</a> - real-world architectural examples</li>
</ul>]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="software-engineering" /><category term="architecture" /><category term="documentation" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Web UI widget</title><link href="https://blog.jenyay.com/web-ui-widget/" rel="alternate" type="text/html" title="Web UI widget" /><published>2020-05-17T21:20:48+00:00</published><updated>2026-04-21T23:48:31+00:00</updated><id>https://blog.jenyay.com/web-ui-widget</id><content type="html" xml:base="https://blog.jenyay.com/web-ui-widget/"><![CDATA[<script>
      (function (w, d, s, o, f, js, fjs) {
          w[o] = w[o] || function () { (w[o].q = w[o].q || []).push(arguments) };
          js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
          js.id = o; js.src = f; js.async = 1; fjs.parentNode.insertBefore(js, fjs);
      }(window, document, 'script', '_hw', 'https://static.jenyay.com/help-widget/widget.js'));
      _hw('init', { minimized: true, text: { minimizedTitle: 'This is a demo widget' }, element: document.getElementById('site-main') });
</script>

<p>This is sort of the second part of the <a href="/building-javascript-widget/">post I wrote</a> a while ago about building JavaScript widget. To my surprise, I received a lot of valuable feedback and some questions on how to deal with some specific scenarios:  </p>

<ul>
  <li>How to use it with UI framework (e.g. React or Angular)</li>
  <li>What is the best way to manage configurations</li>
  <li>How to serve multiple instances from the same page</li>
  <li>How the deployment of such thing looks like</li>
</ul>

<p>Those are all valid questions. So the idea here is to extend the original example and make from it an actual deployable widget:</p>

<p><img src="/content/images/2020/05/widget_screenshot_light-2.png" alt="Demo widget" />
<em>Widget that is shown on bottom right of the page (it may look dark if you are into dark theme)</em></p>

<p>Go ahead and play around with this. This is the most basic example I came up with and it has:</p>

<ul>
  <li>Basic form with validation</li>
  <li>Some list that fetched from remote endpoint</li>
  <li>A concept of multiple views/pages</li>
  <li>Styles that are responsive for viewport and dark/light themes. A couple of SVG icons and yet everything is loaded in a single round trip to CDN.</li>
</ul>

<p>Like in original post, same non-functional requirements apply:</p>

<ul>
  <li>A hosting website shouldn’t be affected by adding the widget. It cannot negatively affect page load latency and performance in general. It may not conflict with existing code and styling of the page. In fact, the result you are seeing on this page is under 30KB and served in a single request (including embedded SVGs).</li>
  <li>The embeddable snippet must be simple to integrate, hard to make mistakes while embedding it, but allow to extend the functionality or change the look of the widget.</li>
  <li>It should be a joy to develop while supporting (with certain trade offs) to wide versions of browsers.</li>
</ul>

<h2 id="application">Application</h2>

<p>Now that it is clear what is the end result, let’s take a look on the building blocks of our code:</p>

<p><img src="/content/images/2020/05/help-widget-app-source-2.svg" alt="Source code structure" /></p>

<p>So, there are basically 2 parts - the installation script on the left side of the diagram and the widget application itself on the right side.</p>

<h3 id="installation-script">Installation Script</h3>

<p>I wrote in details why it looks like this <a href="/building-javascript-widget/#the-embeddable-part">here</a>, so it is basically the same thing with a minor changes:</p>

<p><img src="/content/images/2020/05/image-2.png" alt="Widget loader" /></p>

<p>The highlighted parts are:</p>

<ul>
  <li>In red is the instance name. It only matters when a multiple instances of the widget needs to be loaded into a page, then each instance requires a unique name. This way it allows us interact (initialize settings and call methods) with the specific instance.</li>
  <li>In yellow is the method to execute in a widget. <code class="language-plaintext highlighter-rouge">init</code> is a special method and the only one required to “start” widget. There can be other methods (not in my example) called immediately or much later, which is the way to interact with the widget.</li>
  <li>Optional parameters are in green. <code class="language-plaintext highlighter-rouge">init</code> method’s parameter has a <a href="https://github.com/jenyayel/help-widget/blob/master/src/models.ts#L10">defined structure</a> which “configures” the widget.</li>
  <li>And in blue we have a full URL to the location where the widget is hosted. In some cases site owners prefer to host the widget in different location (e.g. under their own host name), but this obviously means they will lose updates of the widget that will be pushed to CDN.</li>
</ul>

<h3 id="widget-application">Widget Application</h3>

<p>The source code of the widget that you see on this page is located at <a href="https://github.com/jenyayel/help-widget">this git repository</a>. This is a fairly standard client-side application written in TypeScript. It is not far away from my <a href="https://github.com/jenyayel/js-widget">original example</a>, except that this time I took the example all the way to be more realistic in terms of functionality and “deployability” (I may have invented this word just now).</p>

<blockquote>
  <p>Please take into account that although the widget is fully functional, it is still for demonstration purposes and you should adjust it to your production realities.</p>
</blockquote>

<p><strong>Skeleton</strong>
If I peel all UI and state management from it, you will find the main difference of this application from other client-based applications - the main entry point to the application, AKA <code class="language-plaintext highlighter-rouge">static void main()</code> in other well known languages.</p>

<p><img src="/content/images/2020/05/help-widget-diagrams-application-2.svg" alt="Bootstrap" /></p>

<p>The module that handles loading of the application is <code class="language-plaintext highlighter-rouge">/src/loader.ts</code>, which consist of:</p>

<ul>
  <li>Figure out the instance name (there can be multiple instances). The trick for this part is that the installation script will place an id attribute to <code class="language-plaintext highlighter-rouge">script</code> tag with value being unique name of the widget’s instance. Later on, when the widget loads it will get a hold of the “current” instance name via instance of script tag by using  <code class="language-plaintext highlighter-rouge">document.currentScript</code> API.</li>
  <li>Start processing all methods that were called while <code class="language-plaintext highlighter-rouge">widget.js</code> was asynchronously downloaded (basically those that are called in the installation script). One of those methods is <code class="language-plaintext highlighter-rouge">init</code>, which is where we start our “rendering” (or not, if the widget is UI-less).</li>
  <li>Store indication that the instance was “started”. The purpose of this is to prevent accidental multiple initializations of the same instance.</li>
</ul>

<blockquote>
  <p>Note, <code class="language-plaintext highlighter-rouge">currentScript</code> is totally unsupported by IE11 (funny thing that it does in older versions of IE). This means that multi-instance of a widget with this implementation won’t work in IE11. There are ways to solve it, but I’m leaving it out of scope of the article.</p>
</blockquote>

<p><strong>Adding UI</strong>
I decided to use <a href="https://preactjs.com/">Preact</a>, because it’s just insanely small, which is really important for the widget. But nothing prevents you from using any other UI library.</p>

<blockquote>
  <p>If you are not familiar with Preact, it is basically React with the same JSX syntax, but much smaller because it <a href="https://preactjs.com/guide/v8/differences-to-react/">doesn’t implement</a> all features that React has.</p>
</blockquote>

<p>Once we reach up to <code class="language-plaintext highlighter-rouge">App.tsx</code>, you will find a React-like application which leverage <a href="https://preactjs.com/guide/v10/context/">Context</a> for global state, Layout to hold a common components, “pages views” which are loaded via a light in-memory router:</p>

<p><img src="/content/images/2020/05/help-widget-diagrams-application-preact.svg" alt="Widget application structure" />
<em>Widget application structure</em></p>

<p>I intentionally decided not to use <a href="https://github.com/preactjs/preact-router">preact-router</a>, because it adds event listeners to all anchors on <a href="https://github.com/preactjs/preact-router/blob/5f00182f82eb5e062926aa8af4b3cacf0332dce2/src/index.js#L137">document level</a>, which is not acceptable for widget (remember not to mess with the hosting page). Since this router doesn’t use any shared resource of the page (e.g. URL, history, document event listeners), it’s scoped nicely to a single widget instance.</p>

<p>The last thing that is worth mentioning is an extensive usage of CSS modules. You will find the “main” styles in  <code class="language-plaintext highlighter-rouge">/src/layout/main.css</code>, which also has styles-reset which should prevent page’s styles from affecting the widget. This reset is fairly basic, and if you are looking for more “aggressive” isolation from styles defined on a page, I would recommend <a href="https://cleanslatecss.com/">Cleanslate</a>.</p>

<p><strong>Tooling</strong>
As in a regular node.js application, you can start a widget in your local environment via  <code class="language-plaintext highlighter-rouge">npm start</code>, which will launch a <em>demo</em> HTML page <code class="language-plaintext highlighter-rouge">/dev/index.html</code>. The whole purpose of the page is to render the widget while <strong>developing</strong> it. The page contains an installation script, which embeds a version that is compiled from source each time changes are detected.</p>

<p>Everything that is related to building files, both for <em>dev</em> and <em>release</em>, into single-js-file is located in <code class="language-plaintext highlighter-rouge">/webpack.config.js</code>. This file contains similar configurations as in my <a href="/building-javascript-widget#building-and-running">previous post</a>, except for the TypeScript compilation and instructions how to compile JSX via Preact.</p>

<p><strong>Backend Interaction</strong>
<em>help-widget</em> is also invokes REST remote APIs - sends contact form data and queries a list of FAQ questions. The backend itself is not interesting in scope of the widget. Yours probably will look very different in terms of language &amp; runtime choice, persistence type, authorization, etc. But just for a sake of a fully functional example of the widget, I needed something simple, so I included it and it is hosted on <a href="https://glitch.com/~help-widget-backend">Glitch</a>.</p>

<h2 id="deployment">Deployment</h2>

<p>For this demo I decided to use AWS for hosting the widget and GitHub Actions for building and deploying it. There is nothing special in those two vendors to achieve the task, you can easily pick any other vendors, the concepts are pretty much the same.</p>

<p>Since the widget itself is no more than a static JavaScript file, I’m going to host it in S3 bucket and serve it via CloudFront - AWS CDN service. The way the file will get there, is that once we <code class="language-plaintext highlighter-rouge">tag</code> a particular commit in git, a workflow in GitHub’s Actions will grab the source, compile it and upload to AWS. The extended explanation of the same is on this diagram:</p>

<p><img src="/content/images/2020/05/help-widget-deployment-3.svg" alt="deployment" /></p>

<p>Workflows for GitHub Actions configured by adding files to <code class="language-plaintext highlighter-rouge">/.github/workflows</code> folder. Each file defines a workflow - <code class="language-plaintext highlighter-rouge">ci.yml</code> for build, <code class="language-plaintext highlighter-rouge">release.yml</code> for creating a new release and <code class="language-plaintext highlighter-rouge">deploy.yml</code> for uploading latest release to AWS.</p>

<p><code class="language-plaintext highlighter-rouge">ci.yml</code> is pretty straight forward. Its whole purpose is to validate style and correctness of the code. It will be triggered on a new Pull Request, run lint, test &amp; build and report the status back to Pull Request, so you can decide whether to merge the changes.</p>

<p><code class="language-plaintext highlighter-rouge">release.yml</code> is triggered when a new tag is pushed. So, at some stage you decide that <code class="language-plaintext highlighter-rouge">master</code> branch is in a good shape to create a new version, thus you will tag it with tag in format of <code class="language-plaintext highlighter-rouge">v*</code>. For instance:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git tag v0.0.2
git push origin v0.0.2
</code></pre></div></div>

<p>The workflow then perform a build in “release” mode, which will output a single optimized JavaScript file, and attach the file as an asset to release:</p>

<p><img src="/content/images/2020/05/image-6.png" alt="Release example" /></p>

<p>Now that the release is persisted, a <em>deploy</em> workflow will be triggered.</p>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">deploy.yml</code> is very specific to the hosting model I chose - AWS S3 with CloudFront. Most likely you will need to change it to your scenario, or all together drop, if deployment is handled manually.</p>
</blockquote>

<p>The workflow downloads a newly added release, uploads the JS file to S3 bucket and calls CloudFront <a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html">cache invalidation</a> API. Invalidation is not synchronous, but once finished a latest version of the widget will be available through CDN.</p>

<p>The required resources in AWS for hosting the widget, can be created with AWS CloudFormation template similar to <a href="https://github.com/sjevs/cloudformation-s3-static-website-with-cloudfront-and-route-53/blob/master/s3-static-website-with-cloudfront-and-route-53.yaml">this one</a>.</p>

<h2 id="summary">Summary</h2>

<p>In this article I tried to cover all the missing parts from my previous post - the result is <a href="https://github.com/jenyayel/help-widget">GiHub repository</a> that contains all sources for  building and deploying a fully functional web widget.</p>

<p>The widget is built using TypeScript and Preact, deployed by GitHub Actions and hosted in AWS.</p>]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="typescript" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Practical rules for serverless functions</title><link href="https://blog.jenyay.com/rules-for-serverless-functions/" rel="alternate" type="text/html" title="Practical rules for serverless functions" /><published>2019-09-08T18:17:07+00:00</published><updated>2024-05-12T19:06:10+00:00</updated><id>https://blog.jenyay.com/rules-for-serverless-functions</id><content type="html" xml:base="https://blog.jenyay.com/rules-for-serverless-functions/"><![CDATA[<p>Gartner <a href="https://www.gartner.com/smarterwithgartner/top-trends-in-the-gartner-hype-cycle-for-emerging-technologies-2017/">predicted</a> a few years ago that by <strong>now</strong> Serverless PaaS will reach its plateau of productivity. If you try to search which cloud providers have Serverless offering, you instantly get a feeling that we are there - in plateau. I mean besides the dominating clouds, such as AWS, Azure and GCP, there are also a large number of other neat providers and platforms like <a href="https://zeit.co">ZEIT</a>, <a href="https://kubeless.io/">Kubeless</a>, <a href="https://fnproject.io/">Fn Project</a>, <a href="https://www.openfaas.com/">OpenFaaS</a>, <a href="https://www.cloudflare.com/products/cloudflare-workers/">Cloudflare Workers</a> and many many others.</p>

<p><img src="/content/images/2019/07/Emerging-Technology-Hype-Cycle-for-2017_Infographic_R6A-1024x866.jpg" alt="Emerging-Technology-Hype-Cycle-for-2017_Infographic_R6A-1024x866" /></p>

<blockquote>
  <p>Source: <a href="https://www.gartner.com/smarterwithgartner/top-trends-in-the-gartner-hype-cycle-for-emerging-technologies-2017/">The Gartner Hype Cycle for Emerging Technologies, 2017</a></p>
</blockquote>

<p>There is also a huge amount of <a href="https://martinfowler.com/articles/serverless.html">posts</a>, <a href="https://www.amazon.com/s?k=serverless">books</a> and <a href="https://www.youtube.com/results?search_query=serverless">videos</a> about and how to “serverless”. You can literally drown in this amount of information without finding the <strong>essential</strong> parts.</p>

<p>I see many developers (including me not that along ago) either struggle with understanding which use cases it fits the best, or misuse it in such way, that it is near impossible to maintain.</p>

<h2 id="my-golden-rules">My Golden Rules</h2>

<p>While there are many guidelines that tries to cover all of the aspects of Serverless technology, I wanted to catch things that are most (or sometimes the only) things that important.</p>

<p>Below you will find essentials things to hold in your head while, or even before you starting, implementing application using Serverless mechanism.</p>

<h4 id="web-interface-trap">Web interface trap</h4>

<p>It is really easy to start with Serverless, while ignoring a few, or all, of the principles of software development for writing SOLID and clean code. For instance, both AWS and Azure allow to create functions directly from their web portals. Very easy to start. But man, oh man, your colleagues won’t thank you later. Maintenance, team collaboration, testing and code sharing with this approach are very challenging.</p>

<p>So rule #1 try to avoid creating function from the web interface, unless it is something you want to play around or you know that the lifetime of the function will be short.</p>

<h4 id="minimal-work">Minimal work</h4>

<p>Each function should do as minimal work as possible. This is intentionally the second rule. While in “normal” application this is obvious to all of us, in Serverless people tend to abuse a single function.</p>

<p>An example will be appropriate now :) Let’s say you need to call some API after a message arrives to a queue, and store the result in database. You can do it all in single function, and there might be cases when it makes sense, but I would suggest to break it apart into 3 separate functions (just like you will do in a “normal world”):</p>

<ul>
  <li>First function triggered by a message in that queue. It will parse the message, may be filter out, may be reduce several messages into one operation. Once done, call next function (usually by placing a message to another queue).</li>
  <li>Next function will call 3rd party API (whether it is HTTP, RPC or something else). After it gets OK from this API, it can pass the result of the API call to the next function</li>
  <li>The last function will write to database the result</li>
</ul>

<p>It is very simple - every function handles something very specific and no more than this. If you are straggling to brake a part the functionality into small peaces, it might be a sign that Serverless is not the best platform for the use case. Don’t give up quickly - there are a few tricks on how to break apart parsing huge file, processing mbillions records, paging through large datasets with continuation token, etc..</p>

<h4 id="functions-should-form-applications">Functions should form applications</h4>

<p>Functions should be grouped into applications (some unit of logic). Usually you won’t be writing a single, stand alone function. I mean there are exceptions, but in most cases you ended up having a set of functions which can be merged into single logical group with shared code.</p>

<p>This group then can reside in dedicated git repository, like a “normal” application, and deployed as a single unit, again, like a “normal” application. All platforms allows grouping functions into some sort of applications.</p>

<p>Once you start threating functions as applications, then it suddenly sounds obvious that they must have code reviews, CI, tests, documentation, monitoring and release management.</p>

<h4 id="idempotency">Idempotency</h4>

<p>In best scenario the function should be idempotent (it is not always possible, especially when dealing with 3rd party APIs). Serverless runtimes have automatic retry policies in case function didn’t succeeded (unhandled exceptions, timeouts or out of memory). So if the function is idempotent, it will play nice with runtime - executing multiple times without creating side effects in your application.</p>

<p>In some cases it can helpful to use <code class="language-plaintext highlighter-rouge">requestId</code>/<code class="language-plaintext highlighter-rouge">InvocationId</code>/<code class="language-plaintext highlighter-rouge">CorrelationId</code> , which is supplied by a runtime on each call. If it is a retry operation, the identifier will be the same and it will allow you to detect whether the invocation already happened before.</p>

<blockquote>
  <p>The same correlation identifier you will find attached to log messages, which is very helpful to isolate message from one invocation to another</p>
</blockquote>

<p>References:</p>

<ul>
  <li><a href="https://docs.aws.amazon.com/lambda/latest/dg/retries-on-errors.html">AWS</a> retry policy</li>
  <li><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-error-pages">Azure</a> retry policy</li>
  <li><a href="https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html">AWS <code class="language-plaintext highlighter-rouge">requestId</code></a> for Node.js (similar to other languages runtimes)</li>
  <li><a href="https://github.com/Azure/azure-functions-host/wiki/Retrieving-information-about-the-currently-running-function">Azure <code class="language-plaintext highlighter-rouge">InvocationId</code></a></li>
</ul>

<h4 id="running-time-constraint">Running time constraint</h4>

<p>It is important to remember that there is a limit of how long the function can be running. There is a stopwatch that started once the function called, and if it reaches the limit, then your function will be terminated.</p>

<p>This, again, may raise the question whether the Serverless fits your use case - you cannot process a huge amount of data in single invocation, unless you measure the running time and can “pause and resume” processing.</p>

<blockquote>
  <p>Some platforms have an option to eliminate this limitation, but then is it still Serverless where you pay per invocation?</p>
</blockquote>

<p>For instance, when dealing with huge files, think how to break it a part with offsets. If you to process a large amount of records, then probably each invocation should deal with a single or few records each time.</p>

<h4 id="bindings-and-triggers">Bindings and triggers</h4>

<p>IMHO this is one of the main selling points of Serverless - bindings and triggers.</p>

<blockquote>
  <p><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings">Bindings</a> is pretty unique feature in Azure</p>
</blockquote>

<p>It is really allows you to concentrate on the business logic and not plumbing. Instead of hosting web server, writing queues consumer, writing poller for incoming files/records, figuring which scheduler to use, the runtime takes care for it:</p>

<p><img src="/content/images/2019/08/bindings-and-triggers.svg" alt="bindings-and-triggers" /></p>

<p>It also easy to switch between triggers - you have one logic that triggered by message in queue today, and tomorrow you easily convert or add to it HTTP endpoint.</p>

<p>While being one of the main features, this is also one the main limitations. You end up designing the solution around the available triggers, which in some cases may be just not possible. If you need to write a consumer for Kafka in AWS Lamda, or Azure Function that triggered by new message in RabitMQ, you are out of luck. There are solutions, but they usually either involves some middle tier or polling with scheduled functions, which in my opinion kills the concept of Serverless.</p>

<h4 id="function-body">Function body</h4>

<p>The body of the function itself should not do a lot. Think of it as <code class="language-plaintext highlighter-rouge">static void main()</code> - you don’t write your logic there, you parse <code class="language-plaintext highlighter-rouge">args</code>, construct your service/s and invoke them. This way you will be also able to “unit” test your service alone, not that you always should.</p>

<p>There are toolings that allow you to execute functions locally (<a href="https://serverless.com/">serverless</a>, <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local">Azure Func CLI</a> to name a few) and write a full integration tests, but I still suggest to keep function’s body clean from business logic.</p>

<p>Decoupling business logic from runtime environment is usually a good practice to follow. Not that it should be <strong>your</strong> guideline, but think how easily you can move your logic to non-Serverless platform (micro-service or monolith) or, may be even, other Serverless provider.</p>

<h4 id="exceptions-are-good">Exceptions are good</h4>

<p>If there is something unexpected happened, you should throw exceptions as soon as possible. 3rd party API returned 429 or 503? Got transient error from db connection? Just throw - there is a retry policy in place, and eventually, after a runtime will give up on retrying it can place a message in DLQ.</p>

<p>If functions are small and do exactly one thing, then there is no reason to worry about exceptions being bubbled to many levels up.</p>

<p>If you find yourself writing or using library with complex retry with exponential backoff or something similar inside your function, ask yourself again whether the Serverless fits the use case.</p>

<h4 id="parallelism">Parallelism</h4>

<p>This is also one of the main selling points of Serverless - horizontal scalability. You can control how “much of scale” you want per function. And you definitely need to be aware of it and use it, because for certain scenarios functions have insane defaults and may do you bad:</p>

<ul>
  <li>Databases has limitation on active client connections, so you won’t be able to write in parallel with infinite amount of function instances</li>
  <li>If you are going to call 3rd party API at a rate of 1000 req/sec you probably will be banned</li>
  <li>If you are going to call your own service at this rate, it can just end up in DoS</li>
  <li>Crawling websites at high rate, may take them down, or if they are behind services like Cloudflare, you will be storing reCAPTCHA challenge in your database</li>
</ul>

<p>If we follow the example from above with 3 functions, then you have a control at which rate each thing happens really easily - no limit for reading from incoming queue, 10 for calling 3rd party API and 5 for inserting records to DB. And obviously you will need to monitor queues to understand where and if a bottleneck happens.</p>

<p>Another example, if there can be only single reader of huge file, you limit the parallelism to single instance of the reader, but the data processors may have infinite scale.</p>

<h4 id="summary">Summary</h4>

<p>By following the rules above, I was able to deploy a large amount of Serverless applications and maintain it happily with other team mates. But the most important, that those rules prevented from me in some cases to use Serverless technology, as it was just not a good fit and probably would end up badly product and cost-wise.</p>

<!--kg-card-end: markdown-->]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="serverless" /><category term="aws" /><category term="azure" /><summary type="html"><![CDATA[Gartner predicted a few years ago that by now Serverless PaaS will reach its plateau of productivity. If you try to search which cloud providers have Serverless offering, you instantly get a feeling that we are there - in plateau. I mean besides the dominating clouds, such as AWS, Azure and GCP, there are also a large number of other neat providers and platforms like ZEIT, Kubeless, Fn Project, OpenFaaS, Cloudflare Workers and many many others.]]></summary></entry><entry><title type="html">Building JavaScript widget</title><link href="https://blog.jenyay.com/building-javascript-widget/" rel="alternate" type="text/html" title="Building JavaScript widget" /><published>2017-11-19T21:41:10+00:00</published><updated>2024-05-12T19:06:10+00:00</updated><id>https://blog.jenyay.com/building-javascript-widget</id><content type="html" xml:base="https://blog.jenyay.com/building-javascript-widget/"><![CDATA[<p>Widget is a sort of SDK or client of your service that other site owners embed on their websites. At the minimum they consist of JavaScript code and, if there is a UI part, HTML with CSS. Different widgets do different things, but the common for them is that you hand over some <strong>small</strong> piece of code to be embedded on foreign site.</p>

<p>For the widget to be successful there are a few really important non functional requirements:</p>

<ul>
  <li>Widget’s code should never ever mess up with the site it being hosted on. Think isolation.</li>
  <li>It should support the whole spectrum of browsers that users of the sites may use. Think IE6.</li>
  <li>It should not affect (or have a minimum impact on) performance of the website. Think small and async.</li>
  <li>You cannot rely on any library or it’s specific version presented on a site. On another hand, the library you are depending on can be already loaded on the site. Think <code class="language-plaintext highlighter-rouge">noConflict()</code>.</li>
</ul>

<h3 id="tltr">TLTR;</h3>

<p>The end result of what we build here is located <a href="https://github.com/jenyayel/js-widget">here</a>. This is some sort of template for creating JavaScript widget with HTML and CSS in which I find comfortable to develop and easy to deploy as single small JS file.</p>

<h3 id="the-embeddable-part">The embeddable part</h3>

<p>This is the block of code that the website owner will need to embed on his/her website. This code block must have a smallest possible footprint. If it will be large, it may just scare out site owner.</p>

<p>So the obvious that many other articles suggest is to have something like this:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://widget.com/script.js"</span> <span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;&lt;/script&gt;</span>
</code></pre></div></div>

<p>A few problems with this approach:</p>

<ul>
  <li>It is blocking. You can fix it with <code class="language-plaintext highlighter-rouge">async</code> attribute if you care of IE 10+ only.</li>
  <li>You don’t control the location of the script within HTML document - it is up to the site owner where he will place it.</li>
  <li>If you need some additional configurations you will need to add an additional <code class="language-plaintext highlighter-rouge">script</code> block, which makes it less solid and may lead to confusion, forgetting one of the parts (not all site owners are technical people), mixing their order, etc.:</li>
</ul>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://widget.com/script.js"</span> <span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;</span>
    <span class="nx">widget</span><span class="p">.</span><span class="nf">settings</span><span class="p">({</span><span class="na">someParam</span><span class="p">:</span> <span class="kc">true</span><span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>Basically those are reasons why Google Analytics, Facebook SDK and other vendors with high JavaScript SDKs usages ended with something similar to this:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script&gt;</span>
  <span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="nx">s</span><span class="p">,</span><span class="nx">o</span><span class="p">,</span><span class="nx">g</span><span class="p">,</span><span class="nx">r</span><span class="p">,</span><span class="nx">a</span><span class="p">,</span><span class="nx">m</span><span class="p">){</span><span class="nx">i</span><span class="p">[</span><span class="dl">'</span><span class="s1">GoogleAnalyticsObject</span><span class="dl">'</span><span class="p">]</span><span class="o">=</span><span class="nx">r</span><span class="p">;</span><span class="nx">i</span><span class="p">[</span><span class="nx">r</span><span class="p">]</span><span class="o">=</span><span class="nx">i</span><span class="p">[</span><span class="nx">r</span><span class="p">]</span><span class="o">||</span><span class="kd">function</span><span class="p">(){</span>
  <span class="p">(</span><span class="nx">i</span><span class="p">[</span><span class="nx">r</span><span class="p">].</span><span class="nx">q</span><span class="o">=</span><span class="nx">i</span><span class="p">[</span><span class="nx">r</span><span class="p">].</span><span class="nx">q</span><span class="o">||</span><span class="p">[]).</span><span class="nf">push</span><span class="p">(</span><span class="nx">arguments</span><span class="p">)},</span><span class="nx">i</span><span class="p">[</span><span class="nx">r</span><span class="p">].</span><span class="nx">l</span><span class="o">=</span><span class="mi">1</span><span class="o">*</span><span class="k">new</span> <span class="nc">Date</span><span class="p">();</span><span class="nx">a</span><span class="o">=</span><span class="nx">s</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="nx">o</span><span class="p">),</span>
  <span class="nx">m</span><span class="o">=</span><span class="nx">s</span><span class="p">.</span><span class="nf">getElementsByTagName</span><span class="p">(</span><span class="nx">o</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span><span class="nx">a</span><span class="p">.</span><span class="k">async</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="nx">a</span><span class="p">.</span><span class="nx">src</span><span class="o">=</span><span class="nx">g</span><span class="p">;</span><span class="nx">m</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nf">insertBefore</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span><span class="nx">m</span><span class="p">)</span>
  <span class="p">})(</span><span class="nb">window</span><span class="p">,</span><span class="nb">document</span><span class="p">,</span><span class="dl">'</span><span class="s1">script</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">//www.google-analytics.com/analytics.js</span><span class="dl">'</span><span class="p">,</span><span class="dl">'</span><span class="s1">ga</span><span class="dl">'</span><span class="p">);</span>
  <span class="nf">ga</span><span class="p">(</span><span class="dl">'</span><span class="s1">create</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">UA-XXXXXX-XX</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">auto</span><span class="dl">'</span><span class="p">);</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>The code above solves all 3 issues I mentioned above plus a few extra cool things. Here the same code which I un-obfusticated and added explanations:</p>

<script src="https://gist.github.com/jenyayel/ff2f78762eb4cb3d6f38d8b01c7bf9aa.js?file=ga-unobfusticated.js"></script>

<p>The script creates isolated scope via self-evaluated <code class="language-plaintext highlighter-rouge">function</code> which is important in order not to collide with others on the page. The last line is the configurations that site owner may add (e.g. UI, behavior, etc.) and the one line before this (parameters that passed to the method) are kinda “advanced” configurations for developers.</p>

<p>Now that we have a good understanding of how the implantation should look like let’s create something similar:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">function </span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="nx">d</span><span class="p">,</span><span class="nx">s</span><span class="p">,</span><span class="nx">o</span><span class="p">,</span><span class="nx">f</span><span class="p">,</span><span class="nx">js</span><span class="p">,</span><span class="nx">fjs</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">w</span><span class="p">[</span><span class="dl">'</span><span class="s1">MyWidget</span><span class="dl">'</span><span class="p">]</span><span class="o">=</span><span class="nx">o</span><span class="p">;</span><span class="nx">w</span><span class="p">[</span><span class="nx">o</span><span class="p">]</span> <span class="o">=</span> <span class="nx">w</span><span class="p">[</span><span class="nx">o</span><span class="p">]</span> <span class="o">||</span> <span class="nf">function </span><span class="p">()</span> <span class="p">{</span> <span class="p">(</span><span class="nx">w</span><span class="p">[</span><span class="nx">o</span><span class="p">].</span><span class="nx">q</span> <span class="o">=</span> <span class="nx">w</span><span class="p">[</span><span class="nx">o</span><span class="p">].</span><span class="nx">q</span> <span class="o">||</span> <span class="p">[]).</span><span class="nf">push</span><span class="p">(</span><span class="nx">arguments</span><span class="p">)</span> <span class="p">};</span>
    <span class="nx">js</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="nx">s</span><span class="p">),</span> <span class="nx">fjs</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nf">getElementsByTagName</span><span class="p">(</span><span class="nx">s</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span>
    <span class="nx">js</span><span class="p">.</span><span class="nx">id</span> <span class="o">=</span> <span class="nx">o</span><span class="p">;</span> <span class="nx">js</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">f</span><span class="p">;</span> <span class="nx">js</span><span class="p">.</span><span class="k">async</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">fjs</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nf">insertBefore</span><span class="p">(</span><span class="nx">js</span><span class="p">,</span> <span class="nx">fjs</span><span class="p">);</span>
<span class="p">}(</span><span class="nb">window</span><span class="p">,</span> <span class="nb">document</span><span class="p">,</span> <span class="dl">'</span><span class="s1">script</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">mw</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">//SOME_CDN/widget.js</span><span class="dl">'</span><span class="p">));</span>
<span class="nf">mw</span><span class="p">(</span><span class="dl">'</span><span class="s1">init</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="na">showButton</span><span class="p">:</span> <span class="kc">true</span> <span class="p">});</span>
</code></pre></div></div>

<p>You will find this script located in <a href="https://github.com/jenyayel/js-widget/blob/master/demo/index.html">demo page</a>, which simulates client’s site and we’ll use it for development purpose.</p>

<h3 id="application-structure">Application Structure</h3>

<p>Widget application is what will be loaded and executed by the embedded script on site. It may have different degree of complexity, but for any use case it should:</p>

<ul>
  <li>Have a good structure for separation of concerns and test-ability, which means proper module loading</li>
  <li>Convenient development experience via hot-module reloading</li>
</ul>

<p>I’ll use <a href="https://webpack.js.org/">WebPack</a> to address requirements above, but first let’s finalize the structure of the app:</p>

<p><img src="/content/images/2017/11/project_structure.png" alt="Project structure" /></p>

<p>It’s pretty common structure for JS application. Code goes into <code class="language-plaintext highlighter-rouge">src</code> and the entry point is <code class="language-plaintext highlighter-rouge">main.js</code>. The <code class="language-plaintext highlighter-rouge">demo</code> folder contains an emulated site’s page we talked before, it is also the page that we’ll serve by local dev server to develop widget application.</p>

<p>Let’s start with simple <code class="language-plaintext highlighter-rouge">main.js</code>:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">ping</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./services</span><span class="dl">'</span>

<span class="kd">function</span> <span class="nf">app</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">JS-Widget starting</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>

<span class="nf">app</span><span class="p">();</span>
</code></pre></div></div>

<p>Our main function is <code class="language-plaintext highlighter-rouge">app()</code> which evaluated as soon as this module loaded. Also note that I’m using here <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">ECMAScript 6 module loading</a>, which allows us to separate and isolate different parts of application.</p>

<h3 id="building-and-running">Building and running</h3>

<p>The next step is to build and able to serve the app to browser. As I mention, we’ll use WebPack and we’ll need the following packages:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install webpack webpack-dev-server copy-webpack-plugin --save-dev
</code></pre></div></div>

<p>What I want to achieve is that WebPack will take the whole application with all its modules and produce a servable single file which will be loaded in <code class="language-plaintext highlighter-rouge">demo/index.html</code> file. For this to happen I need to add <code class="language-plaintext highlighter-rouge">webpack.config.js</code> file in root with the following configuration:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">path</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">webpack</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">webpack</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">copyWebpackPlugin</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">copy-webpack-plugin</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">bundleOutputDir</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">./dist</span><span class="dl">'</span><span class="p">;</span>

<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">(</span><span class="nx">env</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[{</span>
        <span class="na">entry</span><span class="p">:</span> <span class="dl">'</span><span class="s1">./src/main.js</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">output</span><span class="p">:</span> <span class="p">{</span>
            <span class="na">filename</span><span class="p">:</span> <span class="dl">'</span><span class="s1">widget.js</span><span class="dl">'</span><span class="p">,</span>
            <span class="na">path</span><span class="p">:</span> <span class="nx">path</span><span class="p">.</span><span class="nf">resolve</span><span class="p">(</span><span class="nx">bundleOutputDir</span><span class="p">),</span>
        <span class="p">},</span>
        <span class="na">devServer</span><span class="p">:</span> <span class="p">{</span>
            <span class="na">contentBase</span><span class="p">:</span> <span class="nx">bundleOutputDir</span>
        <span class="p">},</span>
        <span class="na">plugins</span><span class="p">:</span> <span class="p">[</span><span class="k">new</span> <span class="nx">webpack</span><span class="p">.</span><span class="nc">SourceMapDevToolPlugin</span><span class="p">(),</span> <span class="k">new</span> <span class="nf">copyWebpackPlugin</span><span class="p">([{</span> <span class="na">from</span><span class="p">:</span> <span class="dl">'</span><span class="s1">demo/</span><span class="dl">'</span> <span class="p">}])]</span>
    <span class="p">}];</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Note how we instruct WebPack what is the entry of the application - <code class="language-plaintext highlighter-rouge">main.js</code>, so it can traverse it and produce a single file in <code class="language-plaintext highlighter-rouge">dist/widget.js</code>. There are also 2 plugins to allow mapping of source code for debugging, and copying the <code class="language-plaintext highlighter-rouge">index.html</code> into build destination. The last interesting thing here is <code class="language-plaintext highlighter-rouge">devServer</code> section which instructs local HTTP server to serve the <code class="language-plaintext highlighter-rouge">dist</code> folder.</p>

<p>To build let’s run:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ./node_modules/.bin/webpack --config webpack.config.js
</code></pre></div></div>

<p>and check the result in <code class="language-plaintext highlighter-rouge">dist</code> folder.</p>

<p>Now, let’s serve it:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./node_modules/.bin/webpack-dev-server --open
</code></pre></div></div>

<p>Once browser is launched, go to the browser’s console and you should find <em>JS-Widget starting</em> log entry, which means the application (widget) was loaded.</p>

<p>At this stage you will be able to develop the application (adding and modifying JS files) and the <code class="language-plaintext highlighter-rouge">webpack-dev-server</code> will auto-reloaded those modules in your browser.</p>

<h2 id="building-release">Building release</h2>

<p>First of all we need to differentiate between build types. We’ll do it by passing argument <code class="language-plaintext highlighter-rouge">--env.prod</code> to BuildPack:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./node_modules/.bin/webpack --config webpack.config.js --env.prod
</code></pre></div></div>

<p>and inside <code class="language-plaintext highlighter-rouge">webpack.config.js</code> file we’ll be able to “catch” it:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">(</span><span class="nx">env</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">isDevBuild</span> <span class="o">=</span> <span class="o">!</span><span class="p">(</span><span class="nx">env</span> <span class="o">&amp;&amp;</span> <span class="nx">env</span><span class="p">.</span><span class="nx">prod</span><span class="p">);</span>
    <span class="p">...</span>
<span class="p">};</span>
</code></pre></div></div>

<p>The second thing we’ll want to do is to minimize the output. This is done by adding <code class="language-plaintext highlighter-rouge">UglifyJsPlugin</code> plugin for non-dev build:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">(</span><span class="nx">env</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">isDevBuild</span> <span class="o">=</span> <span class="o">!</span><span class="p">(</span><span class="nx">env</span> <span class="o">&amp;&amp;</span> <span class="nx">env</span><span class="p">.</span><span class="nx">prod</span><span class="p">);</span>
        <span class="p">...</span>
            <span class="na">plugins</span><span class="p">:</span> <span class="nx">isDevBuild</span>
                <span class="p">?</span> <span class="p">[</span><span class="k">new</span> <span class="nx">webpack</span><span class="p">.</span><span class="nc">SourceMapDevToolPlugin</span><span class="p">(),</span> <span class="k">new</span> <span class="nf">copyWebpackPlugin</span><span class="p">([{</span> <span class="na">from</span><span class="p">:</span> <span class="dl">'</span><span class="s1">demo/</span><span class="dl">'</span> <span class="p">}])]</span>
                <span class="p">:</span> <span class="p">[</span><span class="k">new</span> <span class="nx">webpack</span><span class="p">.</span><span class="nx">optimize</span><span class="p">.</span><span class="nc">UglifyJsPlugin</span><span class="p">()]</span>
        <span class="p">...</span>
    <span class="p">};</span>
</code></pre></div></div>

<p>Now we can run build with release parameter and you will get combined, obfuscated and minimized JS file in <code class="language-plaintext highlighter-rouge">dist</code> folder.</p>

<p>The next phase is to be able write code in modern version of JavaScript (e.g. ECMAScript 6) and during build transpile it down to code that can be executed in, let’s say, IE6. This is where <a href="https://babeljs.io/">Babel</a> comes into the picture. We’ll need the following dependencies:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install @babel/core @babel/preset-env babel-loader@next --save-dev
</code></pre></div></div>

<p>and then, again, let’s change the <code class="language-plaintext highlighter-rouge">webpack.config.js</code>. The babel is added as <em>module</em> to WebPack, which allows to manipulate the intermediate result before it’s written to the output:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">(</span><span class="nx">env</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="p">...</span>
  <span class="na">module</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">rules</span><span class="p">:</span> <span class="p">[</span>
      <span class="p">{</span>
        <span class="na">test</span><span class="p">:</span> <span class="sr">/</span><span class="se">\.</span><span class="sr">js$/i</span><span class="p">,</span> <span class="na">exclude</span><span class="p">:</span> <span class="sr">/node_modules/</span><span class="p">,</span> <span class="na">use</span><span class="p">:</span> <span class="p">{</span>
          <span class="na">loader</span><span class="p">:</span> <span class="dl">'</span><span class="s1">babel-loader</span><span class="dl">'</span><span class="p">,</span>
          <span class="na">options</span><span class="p">:</span> <span class="p">{</span>
            <span class="na">presets</span><span class="p">:</span> <span class="p">[[</span><span class="dl">'</span><span class="s1">@babel/env</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
                <span class="dl">'</span><span class="s1">targets</span><span class="dl">'</span><span class="p">:</span> <span class="p">{</span> <span class="dl">'</span><span class="s1">browsers</span><span class="dl">'</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">ie 6</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">safari 7</span><span class="dl">'</span><span class="p">]</span> <span class="p">}</span>
            <span class="p">}]]</span>
          <span class="p">}</span>
        <span class="p">}</span>
      <span class="p">}</span>
    <span class="p">]</span>
  <span class="p">}</span>
  <span class="p">...</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Note how we target specific browsers instead of version of JavaScript, which is much more convenient.</p>

<h3 id="adding-html-and-css">Adding HTML and CSS</h3>

<p>Some widget may have UI components in them, those much easier to construct by using HTML markup and CSS. But, again, we want to have a minimal footprint in network - not to load additional files. The ideal will be to combine CSS and HTML in to the same JS file.</p>

<p>There is, however, one down side that you need to be aware of. In this solution the CSS is not isolated from the rest of the styles on page - it’s injected into the page itself under dynamically added <code class="language-plaintext highlighter-rouge">style</code> tag. The HTML is also may be affected by styles on the page, unless you will be appending it into <code class="language-plaintext highlighter-rouge">iframe</code> tags, which has it’s own downsides.</p>

<blockquote>
  <p>There is much robust solution to a CSS and HTML isolation - <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM">Shadow DOM</a>, but unfortunately the browsers support of such feature and nature of JS widget <a href="https://caniuse.com/#search=shadow%20DOM">don’t play well</a> together.</p>
</blockquote>

<p>Let’s see how we can do it. We’ll leverage again WebPack’s modules. The following packages required:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install css-loader html-loader style-loader --save-dev
</code></pre></div></div>

<p>and in <code class="language-plaintext highlighter-rouge">webpack.config.js</code> add in <em>modules</em> the following:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">(</span><span class="nx">env</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="p">...</span>
    <span class="na">module</span><span class="p">:</span> <span class="p">{</span>
        <span class="na">rules</span><span class="p">:</span> <span class="p">[</span>
            <span class="p">{</span> <span class="na">test</span><span class="p">:</span> <span class="sr">/</span><span class="se">\.</span><span class="sr">html$/i</span><span class="p">,</span> <span class="na">use</span><span class="p">:</span> <span class="dl">'</span><span class="s1">html-loader</span><span class="dl">'</span> <span class="p">},</span>
            <span class="p">{</span> <span class="na">test</span><span class="p">:</span> <span class="sr">/</span><span class="se">\.</span><span class="sr">css$/i</span><span class="p">,</span> <span class="na">use</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">style-loader</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">css-loader</span><span class="dl">'</span> <span class="o">+</span> <span class="p">(</span><span class="nx">isDevBuild</span> <span class="p">?</span> <span class="dl">''</span> <span class="p">:</span> <span class="dl">'</span><span class="s1">?minimize</span><span class="dl">'</span><span class="p">)]</span> <span class="p">},</span>
    <span class="p">...</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Note how those modules targeted by <code class="language-plaintext highlighter-rouge">css</code> and <code class="language-plaintext highlighter-rouge">html</code> extensions of files. The rest is standard ES module loader. I added <a href="https://github.com/jenyayel/js-widget/blob/master/src/views/message.html">HTML</a> with <a href="https://github.com/jenyayel/js-widget/blob/master/src/views/message.css">CSS</a> files and the <a href="https://github.com/jenyayel/js-widget/blob/master/src/views/message.js">JS module</a> just importing those files:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">template</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./message.html</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="dl">'</span><span class="s1">./message.css</span><span class="dl">'</span><span class="p">;</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">template</code> variable will contain a string representation of the HTML “template”, which needs to be converted to HTML Element and appended to page document.</p>

<h3 id="external-librarires">External librarires</h3>

<p>The widget itself has no external runtime dependencies. This guarantees a minimal footprint. It doesn’t mean you cannot use external libraries, but should use and load them responsibly - load asynchronously and avoid conflicts with site’s frameworks.</p>

<p>Another thing to consider is that may be the library you are depending on is already presented on the hosting site. jQuery for instance <a href="https://trends.builtwith.com/javascript/jQuery">still has a high usage</a>. Take a look at <a href="https://gist.github.com/jenyayel/d676554930c7a02904eb62188ad5a4d7">this example</a> on how to load jQuery without conflicting or alternately use already loaded jQuery.</p>

<p>It is probably worth mentioning that relying on <a href="https://angular.io/">Angular</a> in most cases will be an overkill. Most widgets have single or, at top, a few views, so it wiser to rely on something much compact (e.g. <a href="https://vuejs.org/">Vue.js</a>).</p>

<h3 id="summary">Summary</h3>

<p>We had built something that can be used as good start for developing JS widget that can be deployed to other websites. We didn’t compromise on development experience and used a modern tooling with modern language features, but still were able to target old browsers.</p>

<p>You can find all source code of the widget <a href="https://github.com/jenyayel/js-widget">here</a>.</p>

<h3 id="update-may-2020">Update May 2020</h3>

<p>I wrote a second part of the article, which go further in implementing the UI widget and explains a deployment scenarios. You can read it <a href="/web-ui-widget/">here</a>.</p>

<!--kg-card-end: markdown-->]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="javascript" /><category term="webpack" /><summary type="html"><![CDATA[Widget is a sort of SDK or client of your service that other site owners embed on their websites. At the minimum they consist of JavaScript code and, if there is a UI part, HTML with CSS. Different widgets do different things, but the common for them is that you hand over some small piece of code to be embedded on foreign site.]]></summary></entry><entry><title type="html">Detecting mood of coworkers in an office using Cognitive Services</title><link href="https://blog.jenyay.com/detecting-mood-of-people-in-your-office-using-microsoft-cognitive-services/" rel="alternate" type="text/html" title="Detecting mood of coworkers in an office using Cognitive Services" /><published>2017-09-03T21:19:51+00:00</published><updated>2024-05-12T19:06:10+00:00</updated><id>https://blog.jenyay.com/detecting-mood-of-people-in-your-office-using-microsoft-cognitive-services</id><content type="html" xml:base="https://blog.jenyay.com/detecting-mood-of-people-in-your-office-using-microsoft-cognitive-services/"><![CDATA[<p>With a recent developments in image and video processing it became a trivial task to add a relatively intelligent features to an application. Almost all cloud providers offer today easy to use Machine Learning APIs which allows to perform visual recognition without Computer Science doctorate.</p>

<p>In this <em>project-for-fun</em> me with co-workers decided to build a small system which will leverage <a href="https://azure.microsoft.com/en-us/services/cognitive-services/emotion/">Emotion API</a> to get some insights on how people feel during the work.</p>

<h2 id="the-setup">The setup</h2>

<p>In the office we installed RPi board with camera. The location of camera can be tricky, because we need to catch as many faces as possible during the day, and ideally different faces. The purpose of this part is to detect image with faces and once detected, the image is sent to the backend.</p>

<p>When an image arrives to the backend we’ll persist it, send it to Cognitive Service, store results and perform some additional image manipulations.</p>

<p>This pipeline allows us send a daily reports of who is the most happy, angry, etc. person and visualize aggregative data - how mood change during period of time, which are dominating moods and so on.</p>

<p><img src="/content/images/2017/07/atmosphere_arch-1.jpg" alt="architectural diagram" /></p>

<p>Obviously for us, we must try out other cool toys when building such project - serverless architecture, JS frameworks, 3D printing, IoT boards, etc.</p>

<p>Let’s dig into details.</p>

<h2 id="the-device">The device</h2>

<p>This device consists of 2 main components - Raspberry Pi and camera connected to it. It all packed into a nice box, which was <a href="https://a360.co/2r9SwNh">modeled</a> and printed by my colleague:</p>

<p><img src="/content/images/2017/07/IMG_20170612_130143--1-.jpg" alt="Atmosphere device" /></p>

<p>The camera located in the right eye of the owl, which allowed to place it near the door of central entrance to observe all people entering the office:
 <img src="/content/images/2017/07/IMG_20170612_125900--1-.jpg" alt="Door frame installation" /></p>

<p>Here are few more shots of the device internals:
 <img src="/content/images/2017/07/atmosphere-collage-1.jpg" alt="Atmosphere collage" /></p>

<h2 id="devices-smarts">Device’s smarts</h2>

<p>The device is not that smart, but is has some interesting part in it. What I wanted to prevent is to send the entire video stream outside the device. The optimal would be detect frames that <em>may</em> contain faces (AKA face detection) and send only them. This will save a huge amount of traffic to the backend. But it also means that device’s CPU should be fast enough to execute algorithm ideally 30 times per second.</p>

<p>It is currently RPi 2. It works kinda OK - there are some frames that dropped. The plan is to upgrade to RPi 3.</p>

<blockquote>
  <p>Face detection performed using OpenCV library. The unfortunate part is that there is no precompiled package of it for RaspberryPi, the fortunate part is that someone wrote <a href="https://www.pyimagesearch.com/2015/07/27/installing-opencv-3-0-for-both-python-2-7-and-python-3-on-your-raspberry-pi-2/">thorough instructions</a> for compiling from source for RPi.</p>
</blockquote>

<p>The source code which running the board is located <a href="https://github.com/atmospherehub/atmosphere-station">here</a>. There are 2 types of workers:</p>

<ol>
  <li><a href="https://github.com/atmospherehub/atmosphere-station/blob/master/lib/detector.py">Detector</a> will analyze each frame using <a href="https://docs.opencv.org/trunk/d7/d8b/tutorial_py_face_detection.html">Haar Cascades Classifier</a> and if face/s detected will push the image into in-memory queue</li>
  <li><a href="https://github.com/atmospherehub/atmosphere-station/blob/master/lib/sender.py">Sender</a> will de-queue and send the image to the backend</li>
</ol>

<p>Simple.</p>

<h2 id="backend">Backend</h2>

<p>The backend job is to execute pipeline for each received image - receive, store, enrich, transform and expose. We implemented this pipeline using <a href="https://azure.microsoft.com/en-us/services/functions/">Azure Function</a>. Each function will perform a smallest possible task and they will be connected using Queues and Topics of Azure Service Bus.</p>

<p>The building blocks of the pipeline when image received is self-explanatory and you can also find a flow diagram along with the source code <a href="https://github.com/atmospherehub/serverless/tree/master/Upload">here</a>. The core part of detecting moods located in function <a href="https://github.com/atmospherehub/serverless/blob/master/Upload/SendToEmotion.cs">SendToEmotion</a> and its essentially sending the image to <a href="https://azure.microsoft.com/en-us/services/cognitive-services/emotion/">Azure Emotions API</a>. Down to pipeline the results are persisted into SQL database so they can be later used for reporting and UI.</p>

<h2 id="exposing-results">Exposing results</h2>

<p>So we started with daily report via email that will show most happy, most angry, etc. people. There was no real value in it beside the fun part:
 <img src="/content/images/2017/08/mail-report.jpg" alt="Mail Report" /></p>

<p>The next phase was to create a dashboard which shows how moods changes during period of time and aggregate it during time of the workday:</p>

<p><img src="/content/images/2017/08/dashboard.jpg" alt="Dashboard" /></p>

<p>From this we came to conclusion:</p>

<ol>
  <li>People are usually more happy before breakfast and dinner</li>
  <li>Sad (or tired?) after dinner</li>
  <li>Angry on Sundays</li>
</ol>

<p>There are a few more screens. The web client app source code is located <a href="https://github.com/atmospherehub/atmosphere-web">here</a>.</p>

<h2 id="summary">Summary</h2>

<p>The end result is the system that aggregates people’s emotions and exposes those results via reports and dashboard.</p>

<p>We argued a lot whether there is a practical value in such system. For me personally this turned out to be a nice experience and allowed to explore some things that we are not dealing with day-to-day.</p>

<!--kg-card-end: markdown-->]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="azure" /><category term="iot" /><summary type="html"><![CDATA[With a recent developments in image and video processing it became a trivial task to add a relatively intelligent features to an application. Almost all cloud providers offer today easy to use Machine Learning APIs which allows to perform visual recognition without Computer Science doctorate.]]></summary></entry><entry><title type="html">Swagger security trimming of end points in ASP.NET Core application</title><link href="https://blog.jenyay.com/swagger-security-trimming-of-end-points-in-asp-net-core-application/" rel="alternate" type="text/html" title="Swagger security trimming of end points in ASP.NET Core application" /><published>2017-01-19T22:13:15+00:00</published><updated>2024-05-12T19:06:10+00:00</updated><id>https://blog.jenyay.com/swagger-security-trimming-of-end-points-in-asp-net-core-application</id><content type="html" xml:base="https://blog.jenyay.com/swagger-security-trimming-of-end-points-in-asp-net-core-application/"><![CDATA[<h3 id="tltr">TLTR;</h3>

<p>If you need to hide endpoints in Swagger UI based on authorization token, here is <a href="https://github.com/jenyayel/SwaggerSecurityTrimming">the repository</a> with demo for .NET Core app. The relevant parts are <a href="https://github.com/jenyayel/SwaggerSecurityTrimming/blob/master/src/V2/wwwroot/custom-swagger.js">passing HTTP header</a> and <a href="https://github.com/jenyayel/SwaggerSecurityTrimming/blob/master/src/V2/SwaggerAuthorizationFilter.cs">filter for rendering schema</a> based on permissions.</p>

<h3 id="swagger">Swagger</h3>

<p><a href="https://swagger.io/">Swagger</a> described as API framework, but for me the most important part of it is an ability to describe in source code the API - endpoint URIs and methods, models of request and response, supported response HTTP codes and so on. There are obvious pros of doing it in source code.</p>

<p>This makes super-easy and fast to integrate between different applications/parties - consumer just need to look at Swagger schema or UI to get an idea on what to expect. No, it is not <a href="https://en.wikipedia.org/wiki/SOAP">SOAP</a>, but definitely has some similarity.</p>

<h3 id="visibility-trimming">Visibility trimming</h3>

<p>While many things comes out of the box in Swagger UI, including OAuth2 flows support for <em>indicating</em> which endpoints require authorization and triggering the flow, there was still one thing I missed in a few projects in a row.</p>

<p>Let’s say there are different consumers of the API, each with different scopes or roles. Usually you will leverage standard <code class="language-plaintext highlighter-rouge">Authorize</code> attribute, which will handle the authorization part of the endpoint when the API invoked, however this doesn’t prevent from client to see and <em>inspect</em> the endpoint to which he is not authorized. Swagger ignores the attribute, and displays all endpoints, regardless the user is authorized or even authenticated.</p>

<blockquote>
  <p>At this point I must say that this behavior, probably, in most cases is desired. Even for me, in many projects regardless the permissions of the client, I don’t mind, or even willing, to show all available APIs of the application.</p>
</blockquote>

<p>So what we want to do is hide APIs that the user is not allowed to access.</p>

<h3 id="passing-authorization-token">Passing authorization token</h3>

<p>Let’s start from the fact that we need to pass authorization token from Swagger to our backend.</p>

<blockquote>
  <p>In my example I’ll be using <a href="https://jwt.io/">JWT</a> token with <a href="https://www.nuget.org/packages/Microsoft.AspNet.Authentication.JwtBearer/1.0.0-rc1-final">JwtBearer middleware</a>, but it should work with any type of authorization, as long as you relies on <code class="language-plaintext highlighter-rouge">Authorize</code> attribute.</p>
</blockquote>

<p>In Swagger UI there is a field called ‘api_key’. Depending on version it may looks different and you may find it in different places. Here it is in version I used:</p>

<p><img src="/content/images/2017/01/6.0.0-beta901-api-token.png" alt="" /></p>

<p>The out-of-the-box behavior of this thing is to append the value from this input to the HTTP header called <code class="language-plaintext highlighter-rouge">api_key</code> to every request that done when you click on ‘Try it out!’ button. Instead, we’ll take the value, prefix it with <code class="language-plaintext highlighter-rouge">Bearer</code> and put it into standard HTTP header <code class="language-plaintext highlighter-rouge">Authorization</code>. To achieve it, we need to change JS function located in index.html called <code class="language-plaintext highlighter-rouge">addApiKeyAuthorization</code>.</p>

<p>The page itself (where the function located) rendered by <code class="language-plaintext highlighter-rouge">SwaggerUi</code> middleware, thus we’ll need to override the page with static file in the same path. The important part for this trick to work, is that <code class="language-plaintext highlighter-rouge">StaticFiles</code> middleware must be registered before <code class="language-plaintext highlighter-rouge">SwaggerUi</code> middleware.</p>

<p>Once the file in under <code class="language-plaintext highlighter-rouge">wwwroot/swagger/ui/index.html</code> and the function has the following line:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">apiKeyAuth</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SwaggerClient</span><span class="p">.</span><span class="nc">ApiKeyAuthorization</span><span class="p">(</span><span class="dl">"</span><span class="s2">Authorization</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">Bearer </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">key</span><span class="p">,</span> <span class="dl">"</span><span class="s2">header</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div></div>

<p>The token will be passed in all requests, including the most important for us - when the schema file <code class="language-plaintext highlighter-rouge">swagger/v1/swagger.json</code> is retrieved by Swagger UI.</p>

<h3 id="dynamic-schema-file">Dynamic schema file</h3>

<p>In order to produce a custom <code class="language-plaintext highlighter-rouge">swagger.json</code> we’ll add a custom <code class="language-plaintext highlighter-rouge">IDocumentFilter</code>:</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">services</span><span class="p">.</span><span class="nf">AddSwaggerGen</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="n">options</span><span class="p">.</span><span class="n">DocumentFilter</span><span class="p">&lt;</span><span class="n">SwaggerAuthorizationFilter</span><span class="p">&gt;();</span>
<span class="p">});</span>
</code></pre></div></div>

<p>The <a href="https://github.com/jenyayel/SwaggerSecurityTrimming/blob/master/src/WebHost/SwaggerAuthorizationFilter.cs">filter</a> evaluated when a schema file is rendered. The main part is in <code class="language-plaintext highlighter-rouge">Apply</code> method:</p>

<ul>
  <li>Loop through each endpoint method</li>
  <li>Collect <code class="language-plaintext highlighter-rouge">Authorize</code> attributes from action method and controller class</li>
  <li>If the attribute presented, check if user authenticated or, if policy specified, evaluate current user against the policy</li>
  <li>If user doesn’t pass check, hide method or the whole endpoint</li>
</ul>

<h3 id="summary">Summary</h3>

<p>By using extensibility of Swashbuckle we were able to intercept schema rendering of Swagger UI and expose endpoints that the user is allowed to view/use based on the specified authorization token.</p>

<h3 id="update-february-2017">Update February 2017</h3>

<p>In original demo I used package <a href="https://www.nuget.org/packages/Swashbuckle/6.0.0-beta901">Swashbuckle 6.0.0-beta901</a> which uses a version of Swagger UI that didn’t had an ability to customize authentication beyound passing <code class="language-plaintext highlighter-rouge">api_key</code> in query string. This is the reason for adding a custom <code class="language-plaintext highlighter-rouge">index.html</code> to override method <code class="language-plaintext highlighter-rouge">addApiKeyAuthorization</code>.</p>

<p>This is no longer true with the version <a href="https://www.nuget.org/packages/Swashbuckle.AspNetCore/1.0.0-rc1">Swashbuckle.AspNetCore 1.0.0-rc1</a>, where the latest Swagger UI version allows to specify where to pass authorization token. This simplifies the implementation a little and I added example in the <a href="https://github.com/jenyayel/SwaggerSecurityTrimming/tree/master/src/V2">same repository</a> side by side with the original demo.</p>

<h3 id="update-may-2020">Update May 2020</h3>

<p>I added <a href="https://github.com/jenyayel/SwaggerSecurityTrimming/tree/master/src/V3">another example</a> for Swashbuckle 5+, which uses Swagger UI v. 3+ and latest OpenAPI. It does essentially the same as in previous versions.</p>

<!--kg-card-end: markdown-->]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="net-core" /><category term="swagger" /><category term="api" /><summary type="html"><![CDATA[TLTR;]]></summary></entry><entry><title type="html">Running ASP.NET Core in Heroku</title><link href="https://blog.jenyay.com/running-asp-net-core-in-heroku/" rel="alternate" type="text/html" title="Running ASP.NET Core in Heroku" /><published>2016-12-02T22:36:56+00:00</published><updated>2024-05-12T19:06:10+00:00</updated><id>https://blog.jenyay.com/running-asp-net-core-in-heroku</id><content type="html" xml:base="https://blog.jenyay.com/running-asp-net-core-in-heroku/"><![CDATA[<p>After running relatively critical application in multiple environments (staging and production) for a few months and building another one, I’m confident with saying it is possible and reasonable to run .NET Core app in Heroku.</p>

<h3 id="the-why">The Why</h3>

<p>While probably the most natural cloud environment for .net core app is Azure, there is still a good reason why would you want sometimes to host on Heroku - you get a wide PaaS offering without headache (also called <code class="language-plaintext highlighter-rouge">add-ons</code>).</p>

<p>So, let’s say your app needs PostgreSQL, Neo4j, RabbitMQ or something from <a href="https://elements.heroku.com/addons">this list</a>, IMHO it will be faster to spin up environment in Heroku. You can go and try find a vendor that will maintain one of those services for you in Azure’s data center, while in Heroku they all provisioned literally with button click and scaled by slider.</p>

<h3 id="enter-heroku">Enter Heroku</h3>

<p>Currently there are 2 options to deploy an app into Heroku’s containers (also called <a href="https://devcenter.heroku.com/articles/dynos">dynos</a>):</p>

<ul>
  <li>Using Dockerfile, which is a pretty new in Heroku. There are some naming issues due to copyright, thus it’s called <a href="https://devcenter.heroku.com/articles/container-registry-and-runtime">Container Registry and Runtime</a></li>
  <li>Using <a href="https://devcenter.heroku.com/articles/buildpacks">buildpack</a>, which is similar to <a href="https://github.com/projectkudu/kudu">Kudu</a> in Azure. The buildpack is responsible to setup a correct runtime for the application in container, build the application and provision it into container</li>
</ul>

<p>Each option has its pros and cons. After trying both, I decided to stick with buildpack.</p>

<h3 id="prepare-app">Prepare app</h3>

<p>In both cases you need to be able to pass port to which the Kestrel will bind itself. This can be done either by setting environment variable <code class="language-plaintext highlighter-rouge">ASPNETCORE_URLS</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ASPNETCORE_URLS='http://+:\8080' dotnet run
</code></pre></div></div>

<p>or by specifying via command line arguments:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet run --server.urls http://+:8080
</code></pre></div></div>

<p>For command line arguments to work, add <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Configuration.CommandLine</code> package to the application and in <code class="language-plaintext highlighter-rouge">Program.cs</code> you should have something similar to:</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">configurations</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ConfigurationBuilder</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">AddCommandLine</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">Build</span><span class="p">();</span>

    <span class="k">new</span> <span class="nf">WebHostBuilder</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">UseConfiguration</span><span class="p">(</span><span class="n">configurations</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">UseKestrel</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">UseContentRoot</span><span class="p">(</span><span class="n">Directory</span><span class="p">.</span><span class="nf">GetCurrentDirectory</span><span class="p">())</span>
        <span class="p">.</span><span class="n">UseStartup</span><span class="p">&lt;</span><span class="n">Startup</span><span class="p">&gt;()</span>
        <span class="p">.</span><span class="nf">Build</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">Run</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This will take care of passing <code class="language-plaintext highlighter-rouge">server.urls</code> argument to Kestrel.</p>

<h3 id="deploying-with-dockerfile">Deploying with Dockerfile</h3>

<p>This is the most simple and suggested by Heroku (later on this) method to deploy. All you really need is a <code class="language-plaintext highlighter-rouge">Dockerfile</code> and the place to build the image. Yes, you will need to build the image by yourself (locally, in Docker hub or with CI tool) and then push it to Heroku’s registry. They don’t build images.</p>

<p>I tried multiple files with different base images and they all worked flawlessly. You can use Microsoft’s images (e.g. <a href="https://hub.docker.com/r/microsoft/dotnet/">dotnet</a> or <a href="https://hub.docker.com/r/microsoft/aspnet/">aspnet</a>) or build custom one where you install runtime or SDK by yourself.</p>

<p>I built a small demo just to demonstrate how easy it is. The source code located <a href="https://github.com/jenyayel/aspnet-core-docker">here</a>, the image is <a href="https://hub.docker.com/r/jenyay/aspnet-core/">here</a> and app running at <a href="https://aspnet-core-dockerfile.herokuapp.com/">aspnet-core-dockerfile.herokuapp.com</a>.</p>

<p>To deploy it (assuming the app in Heroku is <code class="language-plaintext highlighter-rouge">aspnet-core-dockerfile</code>):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku plugins:install heroku-container-registry
heroku container:login
docker pull jenyay/aspnet-core
docker tag jenyay/aspnet-core registry.heroku.com/aspnet-core-dockerfile/web
docker push registry.heroku.com/aspnet-core-dockerfile/web
</code></pre></div></div>

<p>BTW, there is <a href="https://devcenter.heroku.com/articles/local-development-with-docker-compose">also support</a> for Docker Compose.</p>

<h3 id="deploying-with-buildpack">Deploying with buildpack</h3>

<p>Heroku themself were <a href="https://github.com/heroku/dotnet-buildpack">experimenting</a> with running ASP.NET on Mono (!). This repository has 5 years history with steady commits until one year ago. Half a year ago <a href="https://github.com/noliar">noliar</a> sent PR which switches from Mono runtime to .NET Core. After nothing happened with this PR, I figured out that main contributors are no longer at Heroku, so I wrote to Heroku’s support where they basically told me that I should forget about this buildpack and go with Dockerfile.</p>

<p>You can use Noliar’s <a href="https://github.com/noliar/dotnet-buildpack">fork</a> and it will work just fine. I had to <a href="https://github.com/jenyayel/dotnet-buildpack">fork</a> his fork because I wanted to get ride of NodeJS installation (my application is pure API, so there is no NPM or Bower packages) and I needed to support multiple deployable projects (web and worker) within single solution.</p>

<p>So, to deploy with buildpack you will need to:</p>

<ul>
  <li>Figure out which buildpack to use or create your own.</li>
  <li>
    <p>Define buildpack in Heroku application. This can be done either via UI by pointing to one of git repositories or from CLI</p>

    <p>heroku buildpacks:set https://github.com/jenyayel/dotnet-buildpack</p>
  </li>
  <li>
    <p>Add <code class="language-plaintext highlighter-rouge">.deployment</code> file in root of your source code repository. This file instructs buildpack which project/s needs to be published. Assuming you are deploying <code class="language-plaintext highlighter-rouge">WebAPI</code> project, then the content of the file should be:</p>

    <p>[config]
project = src/WebAPI</p>
  </li>
  <li>
    <p>The last piece is a <code class="language-plaintext highlighter-rouge">Procfile</code> which instructs Heroku how to start executables. This one also resides in root of repository and should have something similar to:</p>

    <p>web: cd $HOME/heroku_output/WebAPI &amp;&amp; dotnet ./WebAPI.dll –server.urls http://+:$PORT ${CORE_ENVIRONMENT}</p>
  </li>
</ul>

<h3 id="final-note">Final note</h3>

<p>I still decided to stick with buildpack mainly because it just takes more time to build Docker image and push into Heroku registry, than pushing source and building using buildpack.</p>

<p>It worth mentioning that <em>Container Registry and Runtime</em> is still in Beta phase and things may change/improve over time.</p>

<h3 id="update">Update</h3>

<p><strong>Dec 10 2016</strong> : <a href="https://github.com/friism">friism</a> who was one the main contributors to original .net build pack, created an a <a href="https://github.com/friism/dotnet-buildpack">new builpack</a> and submitted <a href="https://github.com/heroku/dotnet-buildpack/pull/10">PR</a>. Although I didn’t test it yet, it looks much cleaner.</p>

<p><strong>May 2017</strong> : I updated <a href="https://github.com/jenyayel/dotnet-buildpack">buildpack</a> to support both - <code class="language-plaintext highlighter-rouge">csproj</code> and <code class="language-plaintext highlighter-rouge">project.json</code> projects, compilation to use relevant SDK versions.</p>

<p><strong>October 2017</strong> The buildback was updated to support <a href="https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-net-core-2-0/">.NET Core 2.0</a></p>

<!--kg-card-end: markdown-->]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="net-core" /><category term="heroku" /><category term="docker" /><summary type="html"><![CDATA[After running relatively critical application in multiple environments (staging and production) for a few months and building another one, I’m confident with saying it is possible and reasonable to run .NET Core app in Heroku.]]></summary></entry><entry><title type="html">Install “Home Assistant” as Windows service</title><link href="https://blog.jenyay.com/install-home-assistant-as-windows-service/" rel="alternate" type="text/html" title="Install “Home Assistant” as Windows service" /><published>2016-04-17T14:49:09+00:00</published><updated>2024-05-12T19:06:10+00:00</updated><id>https://blog.jenyay.com/install-home-assistant-as-windows-service</id><content type="html" xml:base="https://blog.jenyay.com/install-home-assistant-as-windows-service/"><![CDATA[<p><a href="https://home-assistant.io/">Home Assistant</a> is automation platform for home written on Python. It allows to connect a whole bunch of devices and create rules to perform automated tasks.</p>

<p>For Mac OS and Linux there are <a href="https://home-assistant.io/getting-started/">instruction</a> on how to daemonize (autostart) the platform. So, here are the missing for Windows.</p>

<p>There numerous way to run a Python script as Windows Service, including the <a href="https://stackoverflow.com/a/32440/2307459">accepted answer</a> on StackOverflow, but IMHO a much simpler approach is by using <a href="https://nssm.cc/">NSSM</a>.</p>

<ol>
  <li>
    <p>Download and extract NSSM from <a href="https://nssm.cc/download">here</a></p>
  </li>
  <li>
    <p>Run from command line <code class="language-plaintext highlighter-rouge">\win64\nssm.exe install HomeAssistant</code> which will launch configuration UI for service</p>
  </li>
  <li>
    <p>In this example I installed “Home Assistant” under Python Virtual Environment located at <code class="language-plaintext highlighter-rouge">C:\hass-env\</code>, which places executable at <code class="language-plaintext highlighter-rouge">C:\hass-env\Scripts\hass.exe</code>. The configuration folder is located in <code class="language-plaintext highlighter-rouge">%appdata%\.homeassistant\</code>, hence will pass it location via argument <code class="language-plaintext highlighter-rouge">-c</code>:<br /><br /><img src="/content/images/2016/04/hass_service_step1.png" alt="" /></p>
  </li>
  <li>
    <p>Details screen is self explanatory:<br /><br /><img src="/content/images/2016/04/hass_service_step2.png" alt="" /></p>
  </li>
  <li>
    <p>I’m running it with <code class="language-plaintext highlighter-rouge">Local System</code> account (this is why I needed to specify configuration folder in step #3 to my <code class="language-plaintext highlighter-rouge">%appdata%</code>):<br /><br /><img src="/content/images/2016/04/hass_service_step3.png" alt="" /></p>
  </li>
  <li>
    <p>To catch log information written to console I defined I/O redirection to custom log file:<br /><br /><img src="/content/images/2016/04/hass_service_step4.png" alt="" /></p>
  </li>
  <li>
    <p>You can define file rotation in case output file growths fast as following:<br /><br /><img src="/content/images/2016/04/hass_service_step5.png" alt="" /></p>
  </li>
  <li>
    <p>Click <code class="language-plaintext highlighter-rouge">Install service</code> and you be able to find it in SCM:<br /><br /><img src="/content/images/2016/04/installed.png" alt="Installed Services" /></p>
  </li>
</ol>

<p>At this stage you should be now able to start, stop and restart the service. If error thrown during startup, the service won’t start and you can check the log file for details.</p>

<!--kg-card-end: markdown-->]]></content><author><name>Jenya Y.</name><email>me@jenyay.com</email></author><category term="iot" /><category term="home-assistant" /><category term="for-me" /><summary type="html"><![CDATA[Home Assistant is automation platform for home written on Python. It allows to connect a whole bunch of devices and create rules to perform automated tasks.]]></summary></entry></feed>