<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Médéric Burlet</title>
    <description>The latest articles on DEV Community by Médéric Burlet (@crimsonmed).</description>
    <link>https://dev.to/crimsonmed</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F187045%2F096e2d89-d8ea-4637-a577-d2fab7bbb1fd.jpg</url>
      <title>DEV Community: Médéric Burlet</title>
      <link>https://dev.to/crimsonmed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crimsonmed"/>
    <language>en</language>
    <item>
      <title>10 small AI wins that quietly give you your afternoon back</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Wed, 08 Jul 2026 03:04:11 +0000</pubDate>
      <link>https://dev.to/crimsonmed/10-small-ai-wins-that-quietly-give-you-your-afternoon-back-gec</link>
      <guid>https://dev.to/crimsonmed/10-small-ai-wins-that-quietly-give-you-your-afternoon-back-gec</guid>
      <description>&lt;p&gt;Most people save AI for the big, impressive project, the thing worth a screenshot. Then they never quite find the project, and the tool just sits there unused.&lt;/p&gt;

&lt;p&gt;Meanwhile the real value was in the ten dull tasks you already do every single day. None of them make headlines. That is exactly why they add up.&lt;/p&gt;

&lt;p&gt;None of these need any skill. You type what you want in plain words and refine from there. A few that pay off immediately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Summarise before a meeting.&lt;/strong&gt; Drop in the report, ask for the five key points. Caught up in a minute instead of skimming for ten.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rewrite for tone.&lt;/strong&gt; Message sounds too blunt, or too stiff? Ask for a warmer or shorter version. You keep control of the final wording.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meal ideas from what you already have.&lt;/strong&gt; List what is in the fridge, ask for three dinners. It is surprisingly good at turning odds and ends into a plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gap between a useful answer and generic AI slop comes down to three habits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Be specific.&lt;/strong&gt; "Suggest dinner" is weak. "Three quick vegetarian dinners using rice, eggs, and spinach" is strong.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edit the output.&lt;/strong&gt; The first draft is raw material, not the finished thing. Shaping it into your own voice is the whole job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the facts.&lt;/strong&gt; It can sound completely sure and still be wrong. For anything that matters, verify before you rely on it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And one hard rule on what never goes in: if you would not email it to a stranger, do not paste it into a chatbot. No passwords, no bank details, no confidential work files, no one else's private information.&lt;/p&gt;

&lt;p&gt;None of this is dramatic. That is the point. Everyday AI is not one giant leap, it is a hundred small ones that hand you your afternoon back.&lt;/p&gt;

&lt;p&gt;That is three of the ten. The full list, including the spreadsheet cleanup and the translate-then-verify trick most people skip, is here: &lt;a href="https://mederic.me/blog/ai-for-your-day-10-wins" rel="noopener noreferrer"&gt;https://mederic.me/blog/ai-for-your-day-10-wins&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What is the smallest, most unglamorous thing you use AI for that you would genuinely miss?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>My feed format is "62% smaller than JSON Feed." That number is a cop-out.</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Tue, 07 Jul 2026 18:24:34 +0000</pubDate>
      <link>https://dev.to/crimsonmed/my-feed-format-is-62-smaller-than-json-feed-that-number-is-a-cop-out-12h9</link>
      <guid>https://dev.to/crimsonmed/my-feed-format-is-62-smaller-than-json-feed-that-number-is-a-cop-out-12h9</guid>
      <description>&lt;p&gt;I keep quoting one number for my compact feed format: "62% smaller than JSON Feed." It is a convenient midpoint, and honestly a bit of a cop-out, because a single headline figure hides where a compact format actually earns its keep.&lt;/p&gt;

&lt;p&gt;Here is the real spread. Same serializer, single-source feed, measured at three sizes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Items&lt;/th&gt;
&lt;th&gt;JSON Feed&lt;/th&gt;
&lt;th&gt;NWF&lt;/th&gt;
&lt;th&gt;Reduction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;5.6 KB&lt;/td&gt;
&lt;td&gt;1.8 KB&lt;/td&gt;
&lt;td&gt;67%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;53.7 KB&lt;/td&gt;
&lt;td&gt;16.8 KB&lt;/td&gt;
&lt;td&gt;69%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;538.8 KB&lt;/td&gt;
&lt;td&gt;170.6 KB&lt;/td&gt;
&lt;td&gt;68%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice the ratio barely moves as the feed grows. That is the good news.&lt;/p&gt;

&lt;p&gt;The catch: those are single-source feeds, and they hit 67 to 69%. Mixed, multi-source feeds only save about 50 to 54%. The "62%" I quote everywhere is just the midpoint between those two cases.&lt;/p&gt;

&lt;p&gt;Why the gap? Interning. Authors, tags, and sources are stored once in a table and referenced by index (&lt;code&gt;a:0&lt;/code&gt; means author index 0). If one author wrote forty items, their name appears once, not forty times. A single-source feed repeats itself constantly, so the interning table pays off hugely. A multi-source merge has far less repetition to fold away, so it saves less. The compression is honest about what it is: redundancy removal, not magic.&lt;/p&gt;

&lt;p&gt;And here is the part most "I designed a format" posts skip, the part about when &lt;em&gt;not&lt;/em&gt; to use it.&lt;/p&gt;

&lt;p&gt;If you publish to clients you do not control, keep emitting JSON Feed 1.1. NWF is for machine-to-machine work: syncing feeds between servers, caching large merged outputs, storing a mesh that pulled hundreds of items together. Because the canonical model is the contract, the same feed serializes to both formats, so reaching for the compact one is never a lock-in.&lt;/p&gt;

&lt;p&gt;The full design write-up covers the line grammar (one letter per record, TAB-separated cells, LF-separated lines), the byte-for-byte round-trip guarantee, and the complete benchmark method: &lt;a href="https://mederic.me/blog/nwf-format-design" rel="noopener noreferrer"&gt;https://mederic.me/blog/nwf-format-design&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have ever shipped a compact or binary format: did you publish the honest range, or just the best-case number?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>performance</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The 30-second check that catches a confidently wrong AI</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Tue, 07 Jul 2026 08:03:17 +0000</pubDate>
      <link>https://dev.to/crimsonmed/the-30-second-check-that-catches-a-confidently-wrong-ai-4p3i</link>
      <guid>https://dev.to/crimsonmed/the-30-second-check-that-catches-a-confidently-wrong-ai-4p3i</guid>
      <description>&lt;p&gt;An AI model writes in the same calm, authoritative voice whether it is right or inventing the answer on the spot.&lt;/p&gt;

&lt;p&gt;So the confidence you feel while reading a fluent answer is not evidence. It is style. The voice tells you nothing, and a quick check is the only thing that does.&lt;/p&gt;

&lt;p&gt;Here is the 30-second version I run before trusting anything that matters. Three steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Does the cited source actually say it?&lt;/strong&gt; If the AI links or names a source, open it and find the exact claim. Surprisingly often the source is real but does not back up the point being made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Cross-check one independent source.&lt;/strong&gt; Find a second, unrelated source that agrees. Two independent sources saying the same thing is far stronger than one. If the AI gave no source at all, treat that as a yellow flag and go find one yourself before relying on the answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Trust, verify more, or drop.&lt;/strong&gt; If both agree, trust it. If they clash, dig deeper or leave the claim out.&lt;/p&gt;

&lt;p&gt;The trick that keeps this at 30 seconds: you do not audit every sentence. Pick the one or two load-bearing facts, the ones the whole answer rests on, and check only those.&lt;/p&gt;

&lt;p&gt;And aim your suspicion where models actually break: numbers, dates, names, and exact quotes. A model can be off by a single digit or a year while everything around it reads perfectly. It has no feeling of doubt to warn you with, which is exactly why you have to supply the doubt yourself.&lt;/p&gt;

&lt;p&gt;For an everyday creative question, relax. For a figure you are about to put in a report, or advice you are about to act on, run the full check every time.&lt;/p&gt;

&lt;p&gt;The full version covers which claims are high-stakes enough to always verify (legal, medical, anything you are about to act on) and how to make this a lightweight habit instead of a chore: &lt;a href="https://mederic.me/blog/fact-check-ai-answer" rel="noopener noreferrer"&gt;https://mederic.me/blog/fact-check-ai-answer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What is the last confidently-wrong AI answer that almost got past you?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Your best AI demo is a vanity metric</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Tue, 07 Jul 2026 01:17:30 +0000</pubDate>
      <link>https://dev.to/crimsonmed/your-best-ai-demo-is-a-vanity-metric-3d3m</link>
      <guid>https://dev.to/crimsonmed/your-best-ai-demo-is-a-vanity-metric-3d3m</guid>
      <description>&lt;p&gt;The most impressive AI demo you have ever given told you almost nothing about whether it would actually work.&lt;/p&gt;

&lt;p&gt;That is uncomfortable, because the demo is the thing that got the room excited and the budget approved. But a pilot is judged on a single impressive run. Production is judged on the thousandth unremarkable one.&lt;/p&gt;

&lt;p&gt;A demo is a curated event. Someone picks the input, polishes the prompt, and runs it until it shines. That tells you the ceiling of what is possible in perfect conditions, which is genuinely interesting and almost useless for predicting daily value.&lt;/p&gt;

&lt;p&gt;Daily value comes from the floor, not the ceiling. It is what happens when a tired engineer on a Friday reaches for the tool on a messy, real ticket. If that interaction is smooth enough to repeat without thinking, it compounds. If it needs the demo conditions to work, it gets abandoned the first busy week. Which is every week.&lt;/p&gt;

&lt;p&gt;So I stopped asking "how impressed was the room" and started tracking the things that actually accumulate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Throughput&lt;/strong&gt; - how much the team ships per cycle, not how fast one task went once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cycle time&lt;/strong&gt; - averaged across real tickets, including the ugly ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default usage&lt;/strong&gt; - what fraction of eligible work touches the tool without anyone being reminded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice what is missing from that list: the wow factor. "How impressed was the room" feels like progress and predicts nothing about month three. It is a vanity metric wearing a nice suit.&lt;/p&gt;

&lt;p&gt;A single spike looks bigger in the moment. The broad, steady area of many boring daily uses is what compounds, and it ends up ahead of the demo that peaked once and went flat.&lt;/p&gt;

&lt;p&gt;The full argument, including why the exact skills that win a demo are the ones that never generalize to real work, is here: &lt;a href="https://mederic.me/blog/unremarkable-workflow" rel="noopener noreferrer"&gt;https://mederic.me/blog/unremarkable-workflow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, honest question: think about the last AI tool your team actually kept using. Was it the demo that sold it, or some boring Tuesday when a teammate reached for it without being told to? Which one made it stick?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>productivity</category>
      <category>career</category>
    </item>
    <item>
      <title>I vetted 271 RSS sources so you don't have to hunt them down</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Mon, 06 Jul 2026 01:59:01 +0000</pubDate>
      <link>https://dev.to/crimsonmed/i-vetted-271-rss-sources-so-you-dont-have-to-hunt-them-down-3mja</link>
      <guid>https://dev.to/crimsonmed/i-vetted-271-rss-sources-so-you-dont-have-to-hunt-them-down-3mja</guid>
      <description>&lt;p&gt;Everyone blames RSS for dying. For a while I was convinced the problem was technical: brittle feeds, missing endpoints, formats nobody agrees on.&lt;/p&gt;

&lt;p&gt;It wasn't. The hard part was never the plumbing. It was knowing which sources are actually worth following.&lt;/p&gt;

&lt;p&gt;An empty feed reader is useless. Setting one up properly means hunting down RSS and Atom URLs one at a time, guessing which blogs still post, and finding out weeks later that half of them went quiet in 2021. That afternoon of link-hunting is the real reason people give up and go back to an algorithmic timeline that decides for them.&lt;/p&gt;

&lt;p&gt;So I did the boring part. &lt;strong&gt;271 vetted feeds, grouped into 24 themes&lt;/strong&gt;, as a ready-made pack you point a reader at instead of assembling by hand.&lt;/p&gt;

&lt;p&gt;A few of the themes and how many sources each carries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontier AI Labs (12), AI Tools &amp;amp; ML Platforms (12), AI Research &amp;amp; Academia (12)&lt;/li&gt;
&lt;li&gt;Languages &amp;amp; Frameworks (13), Developer Tools (12), Cloud &amp;amp; Infrastructure (13), Security (12)&lt;/li&gt;
&lt;li&gt;Databases &amp;amp; Data (12), Hardware &amp;amp; Chips (11)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it is not all work. There are themes for Space, Science, Gaming, Anime, Movies &amp;amp; TV, Music, Books, and Food, because a reader you actually enjoy opening is a reader you keep using.&lt;/p&gt;

&lt;p&gt;Every entry is a real, stable source, organized so a theme reads as a coherent feed instead of noise. You choose the themes; the vetting is already done. That is the middle path between an algorithm choosing for you and a blank reader making you do everything.&lt;/p&gt;

&lt;p&gt;The full theme list, the key for each one, and every source in the pack is here: &lt;a href="https://mederic.me/blog/neurowire-taps-pack" rel="noopener noreferrer"&gt;https://mederic.me/blog/neurowire-taps-pack&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Honest question for anyone still running a feed reader: how do you actually find new sources worth adding? Or did the blank-page problem win, and you quietly stopped?&lt;/p&gt;

</description>
      <category>rss</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>3 tricks that made my feed format 62% smaller than JSON Feed</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Sun, 05 Jul 2026 15:37:13 +0000</pubDate>
      <link>https://dev.to/crimsonmed/3-tricks-that-made-my-feed-format-62-smaller-than-json-feed-4jpi</link>
      <guid>https://dev.to/crimsonmed/3-tricks-that-made-my-feed-format-62-smaller-than-json-feed-4jpi</guid>
      <description>&lt;p&gt;JSON Feed is comfortable. It is also bigger than it needs to be.&lt;/p&gt;

&lt;p&gt;While building a feed engine that emits six formats from one canonical model, I wanted a native format that stayed human-readable but stopped paying for the same strings over and over. The result, NWF, comes out roughly &lt;strong&gt;62% smaller&lt;/strong&gt; than the equivalent JSON Feed, and it still round-trips losslessly back to the same model.&lt;/p&gt;

&lt;p&gt;Three tricks get it there. None of them are gzip. You can still open the file and read it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Intern repeated values.&lt;/strong&gt; Authors, tags, and sources are listed once and then referenced by index. A feed of 50 posts by one author stores that author string one time, not fifty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Relativize links.&lt;/strong&gt; Every URL is stored relative to a shared base prefix instead of repeating &lt;code&gt;https://your-domain.com/...&lt;/code&gt; on every single entry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Store dates as deltas.&lt;/strong&gt; Instead of a full ISO timestamp per item, each date is a small delta from the feed's own update time.&lt;/p&gt;

&lt;p&gt;The wire format itself is line-oriented on purpose: LF-separated lines, TAB-separated cells, a one-letter kind per line. Media type &lt;code&gt;text/x-neurowire&lt;/code&gt;, extension &lt;code&gt;.nwf&lt;/code&gt;. Compact enough for machines, still legible when you are debugging it by eye.&lt;/p&gt;

&lt;p&gt;Why bother when gzip exists? Because interning and relativizing shrink the &lt;em&gt;model&lt;/em&gt; before the transport layer ever sees it, and the file stays diffable and greppable in a way a gzipped blob never will. You get the size win and keep the ability to eyeball a feed in your terminal.&lt;/p&gt;

&lt;p&gt;The full write-up covers the rest of the engine: the "taps" that turn feed-less HTML pages into real feeds, "meshes" that merge multiple sources into one, and why one canonical model beats writing the same brittle scraper twice. It's here: &lt;a href="https://mederic.me/blog/neurowire-docs-launch" rel="noopener noreferrer"&gt;https://mederic.me/blog/neurowire-docs-launch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have ever designed a wire format, what did you strip out first: the repeated strings, or the timestamps?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>I Trained 700 Engineers on AI. The Tool Was Never the Problem.</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Sat, 04 Jul 2026 05:42:53 +0000</pubDate>
      <link>https://dev.to/crimsonmed/i-trained-700-engineers-on-ai-the-tool-was-never-the-problem-lfe</link>
      <guid>https://dev.to/crimsonmed/i-trained-700-engineers-on-ai-the-tool-was-never-the-problem-lfe</guid>
      <description>&lt;p&gt;Every company I walk into has the same plan for AI adoption: buy the tool, book a workshop, send the calendar invite. Three weeks later usage has cratered, and nobody can say why.&lt;/p&gt;

&lt;p&gt;I have run that training for more than 700 engineers across SIA, Maybank, Prudential, and Manulife. The pattern is boringly consistent, and it has almost nothing to do with the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mandate is the tell
&lt;/h2&gt;

&lt;p&gt;A mandate from leadership buys you compliance during the workshop and reversion the week after. People nod, they do the exercises, and then they quietly go back to how they worked before. Compliance looks like adoption for exactly one day.&lt;/p&gt;

&lt;p&gt;If your rollout is a tool announcement plus a generic workshop, expect a spike and a fade. That is not a motivation problem. It is a design problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually predicted whether a cohort stuck
&lt;/h2&gt;

&lt;p&gt;One thing, above everything else: whether the training used the team's real work instead of toy examples.&lt;/p&gt;

&lt;p&gt;Slides about prompting change nothing. Exercises built on the team's own codebase change behaviour, because people adopt what they have already used successfully under realistic conditions. A generic "here is how to prompt" session hands everyone material that is half relevant to their actual job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Champions beat mandates
&lt;/h2&gt;

&lt;p&gt;The other half is a person, not a policy. A respected peer who uses AI well and helps others is what sustains the change after the trainer goes home. I grow these champions deliberately in every engagement, because they are what keeps adoption compounding once the workshop energy is gone.&lt;/p&gt;

&lt;p&gt;A mandate gets you a week. A champion gets you a quarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Be honest: after your last mandated AI workshop, are you still using the thing, or did you drift back to the old way inside a month?&lt;/p&gt;

&lt;p&gt;And if you drifted, was it really the tool that failed, or was there just nobody around to keep it alive?&lt;/p&gt;

&lt;p&gt;The full post breaks down the three levers that separate a spike-and-fade rollout from durable change: role-specific tracks, real-work practice, and champions seeded inside the team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mederic.me/blog/700-engineers-on-adoption" rel="noopener noreferrer"&gt;Read the full post: What 700 trained engineers taught me about adoption&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>career</category>
      <category>discuss</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why AI pilots stall before production</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Wed, 01 Jul 2026 03:44:59 +0000</pubDate>
      <link>https://dev.to/crimsonmed/why-ai-pilots-stall-before-production-27i7</link>
      <guid>https://dev.to/crimsonmed/why-ai-pilots-stall-before-production-27i7</guid>
      <description>&lt;p&gt;Most enterprise AI pilots stall for the same reason: they were built to impress a steering committee, not to survive contact with a real delivery team. The pilot proves the model &lt;em&gt;can&lt;/em&gt; do something. Production requires that people change how they work, that output is trustworthy under pressure, and that the system fits the existing pipeline. Those are organisational and architectural problems, not model problems. A better model does not solve them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The demo trap
&lt;/h2&gt;

&lt;p&gt;A pilot is judged on a single impressive run. Production is judged on the thousandth unremarkable one. The skills that win a demo (a clever prompt, a hand-picked example) are exactly the ones that do not generalise. Treat the pilot as the finish line and you discover the gap to daily use is far wider than the gap to the demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  What production actually requires
&lt;/h2&gt;

&lt;p&gt;Three things, none of which a model upgrade provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Architecture that fits your pipeline.&lt;/strong&gt; AI has to live in the repos, review process, and ticket flow people already use. Bolted-on tools get abandoned.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardrails and evaluation.&lt;/strong&gt; Output has to be trustworthy without a human double-checking every line. That means evals, review practices, and clear failure modes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A change in how teams work.&lt;/strong&gt; Adoption is a behaviour change. Without deliberate enablement, people revert to the old way the moment they get busy, which is always.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to get past the stall
&lt;/h2&gt;

&lt;p&gt;Start where delivery actually happens, not in a sandbox. Pick a real project, embed AI into the real workflow, and measure the change in throughput, not the wow factor. Grow internal champions so the practice compounds. The teams that reach production treated adoption as the goal from day one.&lt;/p&gt;

&lt;p&gt;I wrote the full version, with the failure patterns broken down, here: &lt;strong&gt;&lt;a href="https://mederic.me/blog/why-ai-pilots-stall" rel="noopener noreferrer"&gt;Why AI pilots stall before production&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>enterprise</category>
      <category>career</category>
    </item>
    <item>
      <title>Typescript - T3 / Chakra UI Boilerplate</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Thu, 08 Jun 2023 14:14:34 +0000</pubDate>
      <link>https://dev.to/crimsonmed/typescript-t3-chakra-ui-boilerplate-28mj</link>
      <guid>https://dev.to/crimsonmed/typescript-t3-chakra-ui-boilerplate-28mj</guid>
      <description>&lt;p&gt;Recently i've been working a lot with T3 stack. &lt;/p&gt;

&lt;p&gt;I have loved using it but i've found tailwind to be too descriptive and thus wanted a version ready to use with chakra-ui.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/crimson-med"&gt;
        crimson-med
      &lt;/a&gt; / &lt;a href="https://github.com/crimson-med/t3-chakra-template"&gt;
        t3-chakra-template
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      T3 template incorporating Chakra UI
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;h1&gt;
Create T3 App&lt;/h1&gt;
&lt;p&gt;This is a &lt;a href="https://create.t3.gg/" rel="nofollow"&gt;T3 Stack&lt;/a&gt; project but that incorporates Chakra-UI and user login and password with prisma.&lt;/p&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Run the installation with: &lt;code&gt;yarn&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Make a copy of &lt;code&gt;.env.example&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt; and fill in: &lt;code&gt;NEXTAUTH_SECRET&lt;/code&gt; and &lt;code&gt;NEXTAUTH_URL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run the seeding to create users and posts: &lt;code&gt;yarn migrate/seed&lt;/code&gt; you can find the passwords in: &lt;code&gt;prisma/seed.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you want to configure Discord Login you can add the API info in: &lt;code&gt;.env&lt;/code&gt; and uncomment the discord config in &lt;code&gt;src/server/auth.ts&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
Boilerplate Examples&lt;/h2&gt;
&lt;p&gt;This boilerplate shares a few different aspects of T3 while making a few changes.&lt;/p&gt;
&lt;h3&gt;
Menu&lt;/h3&gt;
&lt;p&gt;You can find in &lt;code&gt;src/components/menu.tsx&lt;/code&gt; a basic menu with items and sub items as well as Signin and Signup.&lt;/p&gt;
&lt;p&gt;You can also specify if items are to be shown when authed.&lt;/p&gt;
&lt;h3&gt;
Signin &amp;amp; Signup&lt;/h3&gt;
&lt;p&gt;This currently has nextauth which can integrate many login system: &lt;a href="https://next-auth.js.org" rel="nofollow"&gt;NextAuth.js&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This template was also configured to allow signin / signup…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/crimson-med/t3-chakra-template"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;For those unfamiliar with T3 it uses Next, NextAuth, Prisma, tRPC and in this case Chakra-UI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nextjs.org"&gt;Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://next-auth.js.org"&gt;NextAuth.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://prisma.io"&gt;Prisma&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chakra-ui.com/"&gt;Chakra UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://trpc.io"&gt;tRPC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For now it supports simple signup / signin with username and password. &lt;/p&gt;

&lt;p&gt;A simple data seeding script creates 3 users with some random posts. &lt;/p&gt;

&lt;p&gt;You can see your own posts once logged in.&lt;/p&gt;

&lt;p&gt;All default passwords are in the seed file.&lt;/p&gt;




&lt;p&gt;Burlet Mederic&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/crimson_med"&gt;https://twitter.com/crimson_med&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Create Random team names for projects</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Tue, 22 Mar 2022 08:26:55 +0000</pubDate>
      <link>https://dev.to/pixiumdigital/create-random-team-names-for-projects-3nf9</link>
      <guid>https://dev.to/pixiumdigital/create-random-team-names-for-projects-3nf9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Here at &lt;strong&gt;Pixium Digital&lt;/strong&gt; we often need to create sets of random usernames or team names.&lt;/p&gt;

&lt;p&gt;This is either due to bench-marking with a need to simulate individuals groups or users.&lt;/p&gt;

&lt;p&gt;Or for a need to &lt;strong&gt;anonymize leader-boards&lt;/strong&gt; in various applications. This can be due to the fact that some applications have big firms as client that they want to keep anonymous hence we generate a random team or group name that can be displayed publicly without risking information leakage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/xT4uQBmMGEoGWSCCVG/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/xT4uQBmMGEoGWSCCVG/giphy.gif" alt="leaderboard" width="320" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this we have decided to build a small library that we can re-use to help us generate this content easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basics
&lt;/h2&gt;

&lt;p&gt;We first started to create a list of various information we would need. This includes adjectives, nouns, gamertags, colors, extended colors.&lt;/p&gt;

&lt;p&gt;You find the more detailed list here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/pixiumdigital/random-namer/tree/master/src/data"&gt;https://github.com/pixiumdigital/random-namer/tree/master/src/data&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;We then wanted to create the possibility to add an ID at the end of the random generated content (discord like) so we could have a result like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;myC00lUsername#3948&lt;/li&gt;
&lt;li&gt;thundering-memory#8682&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this we used a little trick of &lt;code&gt;Math.random()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Generates a random ID (discord style)
 * @returns string
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;randomId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Formats
&lt;/h2&gt;

&lt;p&gt;Most of the random lists will be in the following format &lt;code&gt;string[]&lt;/code&gt; however there will be specifications. For example teams will be composed in this format:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;adjective&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;noun&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;icy-dinosaurs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mighty-scarecrow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aquatic-squirrels&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;defiant-camp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;natural-memory&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we have the Extended Colors which are of the following format:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ExtendedColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
    &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
    &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;To use the library you simply need to do the following:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;yarn&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;pixium&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;digital&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;namer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then you can use it like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RandomNamer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RandomType&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@pixium-digital/random-namer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RandomNamer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RandomType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TEAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;toGenerate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;allUnique&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;addId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// ['voiceless-sea#4457', 'delicate-star#6563', 'even-nest#9988']&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RandomNamer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RandomType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GAMERTAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;toGenerate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// ['The Best Yoda', 'I_Cant_Play']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Link
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pixiumdigital"&gt;
        pixiumdigital
      &lt;/a&gt; / &lt;a href="https://github.com/pixiumdigital/random-namer"&gt;
        random-namer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Simple random name generator for various utilities
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;h1&gt;
Random Namer&lt;/h1&gt;
&lt;p&gt;This project aims to simply provide random usernames, team names, gamertags, adjectives, colors to use in testing data.&lt;/p&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;div class="highlight highlight-source-ts position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-s1"&gt;yarn&lt;/span&gt; &lt;span class="pl-s1"&gt;install&lt;/span&gt; @&lt;span class="pl-s1"&gt;pixium&lt;/span&gt;&lt;span class="pl-c1"&gt;-&lt;/span&gt;&lt;span class="pl-s1"&gt;digital&lt;/span&gt;&lt;span class="pl-c1"&gt;/&lt;/span&gt;&lt;span class="pl-s1"&gt;random&lt;/span&gt;&lt;span class="pl-c1"&gt;-&lt;/span&gt;&lt;span class="pl-s1"&gt;namer&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;div class="highlight highlight-source-ts position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-smi"&gt;RandomNamer&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-smi"&gt;RandomType&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"@pixium-digital/random-namer"&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;list&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;RandomNamer&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;RandomType&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;TEAM&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;toGenerate&lt;/span&gt;: &lt;span class="pl-c1"&gt;3&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;allUnique&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;addId&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-c"&gt;// ['voiceless-sea#4457', 'delicate-star#6563', 'even-nest#9988']&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;list&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;RandomNamer&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;RandomType&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;GAMERTAG&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;toGenerate&lt;/span&gt;: &lt;span class="pl-c1"&gt;2&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-c"&gt;// ['The Best Yoda', 'I_Cant_Play']&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Here is the list of random types that can be passed:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;enum&lt;/span&gt; &lt;span class="pl-smi"&gt;RandomType&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-c1"&gt;ADJECTIVE&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-c1"&gt;COLOR&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-c1"&gt;EXTENDED_COLOR&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-c1"&gt;GAMERTAG&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-c1"&gt;NOUN&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-c1"&gt;TEAM&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Here are the parameters available to pass to the function&lt;/p&gt;
&lt;div class="highlight highlight-source-ts position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;
    toGenerate: &lt;span class="pl-s1"&gt;number&lt;/span&gt; &lt;span class="pl-c"&gt;// Number of items to generate&lt;/span&gt;
    &lt;span class="pl-s1"&gt;allUnique&lt;/span&gt;?: &lt;span class="pl-s1"&gt;boolean&lt;/span&gt; &lt;span class="pl-c"&gt;// Should the generated items be unique?&lt;/span&gt;
    &lt;span class="pl-s1"&gt;addId&lt;/span&gt;?: &lt;span class="pl-s1"&gt;boolean&lt;/span&gt; &lt;span class="pl-c"&gt;//&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/pixiumdigital/random-namer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Pixium Digital&lt;/strong&gt; - Shaping your project with technology and innovation&lt;br&gt;
&lt;a href="https://pixiumdigital.com"&gt;https://pixiumdigital.com&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/pixiumdigital"&gt;https://github.com/pixiumdigital&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How we handled 350+ online connections on a video game </title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Mon, 20 Sep 2021 03:21:28 +0000</pubDate>
      <link>https://dev.to/pixiumdigital/how-we-handled-350-online-connections-on-a-video-game-8ak</link>
      <guid>https://dev.to/pixiumdigital/how-we-handled-350-online-connections-on-a-video-game-8ak</guid>
      <description>&lt;p&gt;We were working with a client on building a video game that had multiplayer integrated.&lt;/p&gt;

&lt;p&gt;The game is more of a tabletop turn based game (think monopoly, life). We had to make sure turns and actions were synchronized across the board. &lt;/p&gt;

&lt;p&gt;Furthermore we had the restraint that only one of the players is essentially the one enables to perform the actions. This means we had to account for scenarios where the client would be disconnected and we had to pass the power of decision to another user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EZnApA7U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/80W1ntjiBxAAAAAd/jim-carrey-ive-got-the-power.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EZnApA7U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/80W1ntjiBxAAAAAd/jim-carrey-ive-got-the-power.gif" alt="I got the power"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the stack
&lt;/h2&gt;

&lt;p&gt;Having had some experience with game jams and other multiplayer games we decided to go with a typescript server leveraging &lt;a href="https://socket.io/"&gt;Socket.IO&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This would let use easily create a client / server using the same typescript types for exchanging data information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7rIia-wK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/7Fa0cWtkMRAAAAAC/mail-download.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7rIia-wK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/7Fa0cWtkMRAAAAAC/mail-download.gif" alt="sending"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Session Context
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;First we wanted to setup our context. This means we could then interact with any game session or client data throughout any Socket.IO event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;SessionContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;activeSessions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GameSession&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;clientSockets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeSessions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSockets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we can see our context is consisted of &lt;code&gt;activeSessions&lt;/code&gt; and &lt;code&gt;clientSockets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;clientSockets&lt;/code&gt; is just an array of strings of the ids of each clients connection. This is used later on on handling disconnection.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;activeSessions&lt;/code&gt; are were we have a list of game session. We use here the type &lt;code&gt;Record&lt;/code&gt; as this lets us access information on a faster scale with just the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mySession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sessionContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeSessions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our class then had a few extra functions that don't need explanation such as (addActiveSession, getSessionByClientSocket, etc.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Disconnections
&lt;/h3&gt;

&lt;p&gt;It was important for us to handle disconnections as if a &lt;strong&gt;client in power&lt;/strong&gt;  gets disconnected we want to give that power to someone else.&lt;/p&gt;

&lt;p&gt;This is where the &lt;code&gt;clientSockets&lt;/code&gt; comes in as it lets us do a difference with the list of clients handled by Socket.IO. This is needed as the disconnect event does not tell us exactly who disconnected.&lt;/p&gt;

&lt;p&gt;We can then have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;reconcileDisconnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ioClients&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SocketIO&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Compare the list of the IO Server clients vs the one we stored&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;disconnectedClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ioClients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;// If we have more than one disconnected user then we have discrepancy&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disconnectedClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Loop through all the disconnected clients&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;disconnectedClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Init local variables for easy access&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tmpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;disconnectedClient&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionOfDisconnected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getSessionByClientSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;// If disconnected client was in a session&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionOfDisconnected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tmpSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeSessions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sessionOfDisconnected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GM : &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;master&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;// Remove him from the GameSession Client list&lt;/span&gt;
                &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tmpClient&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="c1"&gt;// Remove him from the global pool of connections&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpClient&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="c1"&gt;// Check if there are no more clients in the GameSession&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Delete GameSession if there are no more users&lt;/span&gt;
                    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeSessions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sessionOfDisconnected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Check if he was has power&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasPower&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;tmpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="c1"&gt;// Log a message if we switched master&lt;/span&gt;
                        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;switchMaster&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Power of the Session (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) has been changed to Client (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasPower&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newPowerClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getClientFromSocketId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasPower&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                            &lt;span class="nx"&gt;tmpSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;newGameMaster&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newPowerClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we now have a new person in power or our session deleted if the  person was the last user in the session.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oUbTfutr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/gWBNAo7iGOYAAAAd/lucifer-devil.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oUbTfutr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/gWBNAo7iGOYAAAAd/lucifer-devil.gif" alt="power"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;We have a few other functions for getting and setting information but the main point of this article was to show how to handle identity of disconnections and how to access data efficiently using context.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Pixium Digital&lt;/strong&gt; - Shaping your project with technology and innovation&lt;br&gt;
&lt;a href="https://pixiumdigital.com"&gt;https://pixiumdigital.com&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/pixiumdigital"&gt;https://github.com/pixiumdigital&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>gamedev</category>
      <category>beginners</category>
      <category>socket</category>
    </item>
    <item>
      <title>Deploying React with Express with route integrity</title>
      <dc:creator>Médéric Burlet</dc:creator>
      <pubDate>Wed, 25 Aug 2021 03:36:34 +0000</pubDate>
      <link>https://dev.to/pixiumdigital/deploying-react-with-express-with-route-integrity-2op5</link>
      <guid>https://dev.to/pixiumdigital/deploying-react-with-express-with-route-integrity-2op5</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;As you may or may not know React often uses routing through the browser &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/History"&gt;history API&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;A few of the common libraries that you might encounter would  be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React Router DOM: &lt;a href="https://www.npmjs.com/package/react-router-dom"&gt;https://www.npmjs.com/package/react-router-dom&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Wouter: &lt;a href="https://www.npmjs.com/package/wouter"&gt;https://www.npmjs.com/package/wouter&lt;/a&gt; (personal favorite)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These libraries will let you define routes and which components are being rendered.&lt;/p&gt;

&lt;p&gt;Quick Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AboutPage&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Route&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/user/:id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserPage&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Route&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this in dev mode will work fine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jA5zhK15--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/kwv_MuCidz8AAAAM/yes-will-ferrell.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jA5zhK15--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/kwv_MuCidz8AAAAM/yes-will-ferrell.gif" alt="awesome"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Issue
&lt;/h2&gt;

&lt;p&gt;If you build the react app and try to host it with express you'll notice we run in an issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buildDirectory&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server started on port 8080`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you navigate to &lt;a href="http://127.0.0.1:8080"&gt;http://127.0.0.1:8080&lt;/a&gt; you'll see your react app.&lt;/p&gt;

&lt;p&gt;However if you navigate to &lt;a href="http://127.0.0.1:8080/about"&gt;http://127.0.0.1:8080/about&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will receive an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can't GET /about
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--diAfG_iA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/4Ch9kTLVFJUAAAAC/well-this-brain-is-not-working-squidward.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--diAfG_iA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/4Ch9kTLVFJUAAAAC/well-this-brain-is-not-working-squidward.gif" alt="not working"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Solving the Issue
&lt;/h2&gt;

&lt;p&gt;Our issue comes from the fact that express will only allow the route '/' to be used.&lt;/p&gt;

&lt;p&gt;The idea is that we want to preserve the routes but still display our built &lt;code&gt;index.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For this we can add the following statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buildDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that for every route we will render the &lt;code&gt;index.html&lt;/code&gt; however since we are not redirecting we will preserve the URL scheme.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nZZgVkpy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/ul_Bdn13nnQAAAAC/missionaccomplished-emperorsnewgroove.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nZZgVkpy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://c.tenor.com/ul_Bdn13nnQAAAAC/missionaccomplished-emperorsnewgroove.gif" alt="mission accomplished"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Pixium Digital&lt;/strong&gt; - Shaping your project with technology and innovation&lt;br&gt;
&lt;a href="https://pixiumdigital.com"&gt;https://pixiumdigital.com&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/pixiumdigital"&gt;https://github.com/pixiumdigital&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
      <category>typescript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
