<?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: Mike</title>
    <description>The latest articles on DEV Community by Mike (@mikenikles).</description>
    <link>https://dev.to/mikenikles</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F249655%2Fcaa17aa9-9b30-43f0-974b-9cd1dc06f89f.png</url>
      <title>DEV Community: Mike</title>
      <link>https://dev.to/mikenikles</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mikenikles"/>
    <language>en</language>
    <item>
      <title>SvelteKit &amp; Prisma - A match made in digital heaven</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Tue, 03 Aug 2021 04:05:42 +0000</pubDate>
      <link>https://dev.to/mikenikles/sveltekit-prisma-a-match-made-in-digital-heaven-2g0f</link>
      <guid>https://dev.to/mikenikles/sveltekit-prisma-a-match-made-in-digital-heaven-2g0f</guid>
      <description>&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most production applications need to persist &amp;amp; retrieve data. Prisma is a pretty genius way to achieve that.&lt;/li&gt;
&lt;li&gt;With SvelteKit, you get client &amp;amp; server-side data fetching - the best of both worlds.&lt;/li&gt;
&lt;li&gt;This all even works if JavaScript is disabled in the browser.&lt;/li&gt;
&lt;li&gt;Template GitHub repo: &lt;a href="https://github.com/mikenikles/sveltekit-prisma"&gt;https://github.com/mikenikles/sveltekit-prisma&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are you going to learn?
&lt;/h2&gt;

&lt;p&gt;We are going to start with a default SvelteKit application. Once initialized, we will learn how to install and configure Prisma before we will use the PrismaClient to perform create, read, update &amp;amp; delete (CRUD) actions against a local SQLite database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things you need to know
&lt;/h2&gt;

&lt;p&gt;In order to get the most out of this post, I expect you are aware of the following technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kit.svelte.dev/"&gt;SvelteKit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.prisma.io/"&gt;Prisma&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The foundation
&lt;/h2&gt;

&lt;p&gt;Let's start with the basics: A &lt;a href="https://kit.svelte.dev/"&gt;SvelteKit&lt;/a&gt; demo app.&lt;/p&gt;

&lt;p&gt;I recommend you first create a GitHub, GitLab or Bitbucket project and start a development environment with &lt;a href="https://www.gitpod.io/"&gt;Gitpod&lt;/a&gt;. Alternatively, you can follow along on your local computer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init svelte@next svelte-with-prisma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, select the following options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Which Svelte app template?" &lt;code&gt;SvelteKit demo app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;"Use TypeScript?" &lt;code&gt;Yes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;"Add ESLint for code linting?" &lt;code&gt;No&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;"Add Prettier for code formatting?" &lt;code&gt;Yes&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When complete, please follow the "Next steps" listed in the terminal to install dependencies and start the SvelteKit demo app.&lt;/p&gt;

&lt;p&gt;If you've followed along so far, you can copy &amp;amp; paste the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;svelte-with-prisma
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--open&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's how quickly you get started with SvelteKit. In your browser, you notice the "TODOS" navigation item. If you play with this list, items are persisted on svelte.dev and deleted after a while.&lt;/p&gt;

&lt;p&gt;Next, we are going to add Prisma to persist todo items in a local SQLite database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Prisma
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.prisma.io/"&gt;Prisma.io&lt;/a&gt; states "Prisma helps app developers build faster and make fewer errors with an open source ORM for PostgreSQL, MySQL and SQLite."&lt;/p&gt;

&lt;p&gt;From my personal experience, this statement is certainly true. Let's go and experience it for yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install &amp;amp; initialize Prisma
&lt;/h3&gt;

&lt;p&gt;First things first: &lt;code&gt;npm i -D prisma&lt;/code&gt; because, well... without dependencies we won't get very far 😉.&lt;/p&gt;

&lt;p&gt;Next, we are going to initialize Prisma. For that, we use &lt;a href="https://www.npmjs.com/package/npx"&gt;&lt;code&gt;npx&lt;/code&gt;&lt;/a&gt; to execute commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ This currently overwrites an existing &lt;code&gt;.gitignore&lt;/code&gt; file. Keep an eye on &lt;a href="https://github.com/prisma/prisma/issues/8496"&gt;8496&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This creates a &lt;code&gt;prisma&lt;/code&gt; directory at the root of the project. In it, you find the &lt;code&gt;schema.prisma&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;At this point, I recommend you install the &lt;code&gt;prisma.prisma&lt;/code&gt; VS Code extension. It adds syntax highlighting, formatting, auto-completion, jump-to-definition and linting for &lt;code&gt;.prisma&lt;/code&gt; files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define the &lt;code&gt;Todo&lt;/code&gt; model
&lt;/h3&gt;

&lt;p&gt;Open the &lt;code&gt;prisma/schema.prisma&lt;/code&gt; file and add the following model definition to the end of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="err"&gt;model&lt;/span&gt; &lt;span class="err"&gt;Todo&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;uid&lt;/span&gt;        &lt;span class="err"&gt;String&lt;/span&gt;  &lt;span class="err"&gt;@id&lt;/span&gt; &lt;span class="err"&gt;@default(cuid())&lt;/span&gt;
  &lt;span class="err"&gt;created_at&lt;/span&gt; &lt;span class="err"&gt;DateTime&lt;/span&gt;
  &lt;span class="err"&gt;text&lt;/span&gt;       &lt;span class="err"&gt;String&lt;/span&gt;
  &lt;span class="err"&gt;done&lt;/span&gt;       &lt;span class="err"&gt;Boolean&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Psst... How do we know what fields to define? Well, we take a peek at the &lt;code&gt;Todo&lt;/code&gt; type definition in &lt;code&gt;src/routes/todos/index.svelte&lt;/code&gt; 😉.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure a SQLite database
&lt;/h3&gt;

&lt;p&gt;Open the &lt;code&gt;.env&lt;/code&gt; file (that file was created by the &lt;code&gt;npx prisma init&lt;/code&gt; command earlier). In it, set the &lt;code&gt;DATABASE_URL&lt;/code&gt; to &lt;code&gt;"file:./dev.db"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We also have to open the &lt;code&gt;prisma/schema.prisma&lt;/code&gt; file to update the &lt;code&gt;datasource.db.provider&lt;/code&gt; to &lt;code&gt;sqlite&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check &lt;a href="https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#datasourc"&gt;the reference docs&lt;/a&gt; for more details on the above two values and what other databases are supported.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Create the database and tables
&lt;/h3&gt;

&lt;p&gt;We're making great progress! Let's now use the Prisma CLI to create our SQLite database and create a schema based on the &lt;code&gt;Todo&lt;/code&gt; model we defined earlier.&lt;/p&gt;

&lt;p&gt;It's easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma db push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give that five seconds ⏳.&lt;/p&gt;

&lt;p&gt;I recommend you read through the console output, I find it highly interesting. For one, it gives us a good deal of detail about what's going on. However, it also contains the following output which is one of the reasons I'm mind-blown by Prisma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ Generated Prisma Client (2.28.0) to ./node_modules/@prisma/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So much goodness! Basically, they use the &lt;code&gt;Todo&lt;/code&gt; model to auto-generate a bunch of TypeScript definitions and Javascript code which we are going to import in just a second. In other words, the "Prisma helps app developers build faster and make fewer errors" sentence on the Prisma website is not just some marketing speech, it is truly genius!&lt;/p&gt;

&lt;p&gt;Ok, I'm done being a fanboy about it, let's move on and thanks for your patience there with me 😅.&lt;/p&gt;

&lt;p&gt;One last thing, please add &lt;code&gt;prisma/dev.db&lt;/code&gt; to your &lt;code&gt;.gitignore&lt;/code&gt; file since we don't want to commit the dev database to version control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the &lt;code&gt;PrismaClient&lt;/code&gt; to interact with the database
&lt;/h3&gt;

&lt;p&gt;The SvelteKit demo app nicely encapsulates all API features in the &lt;code&gt;src/routes/todos/_api.ts&lt;/code&gt; file. To be more precise, the actual CRUD logic happens at &lt;a href="https://api.svelte.dev/todos"&gt;https://api.svelte.dev/todos&lt;/a&gt;. We are going to modify the &lt;code&gt;_api.ts&lt;/code&gt; file slightly to deal with CRUD right there and use the &lt;code&gt;PrismaClient&lt;/code&gt; instead of delegating to a backend API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move the &lt;code&gt;Todo&lt;/code&gt; type so we can reuse it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First and foremost, let's move the &lt;code&gt;Todo&lt;/code&gt; Typescript type. By default, it's defined and used in the &lt;code&gt;src/routes/todos/index.svelte&lt;/code&gt; file. However, with the changes we're going to make to the API, we are also going to need that type in the &lt;code&gt;src/routes/todos/_api.ts&lt;/code&gt; file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cut the &lt;code&gt;Todo&lt;/code&gt; type from &lt;code&gt;src/routes/todos/index.svelte&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Paste it below the &lt;code&gt;import&lt;/code&gt; statements in &lt;code&gt;src/routes/todos/_api.ts&lt;/code&gt;, and prefix it with &lt;code&gt;export&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use the following import in the &lt;code&gt;src/routes/todos/index.svelte&lt;/code&gt; file: &lt;code&gt;import type { Todo } from "./_api";&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Update the API to use Prisma&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;src/routes/todos/_api.ts&lt;/code&gt; file and add the following import:&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;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client&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;Remember? That's the generated code I was so excited about earlier 😀.&lt;/p&gt;

&lt;p&gt;Next, we need a new instance of the &lt;code&gt;PrismaClient&lt;/code&gt; (add this below the &lt;code&gt;import&lt;/code&gt; statements):&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;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moving right along, it's time to update the &lt;code&gt;api&lt;/code&gt; method signature to tell Typescript that the &lt;code&gt;data&lt;/code&gt; parameter is of type &lt;code&gt;Todo&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Locals&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;resource&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;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Todo&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;The following code:&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&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="nx"&gt;base&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="nx"&gt;resource&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="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;content-type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;needs to be replaced with 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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&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;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DELETE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pop&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="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PATCH&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pop&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="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;break&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;We're getting there 💪. In the &lt;code&gt;if&lt;/code&gt; statement right below the code we've just added, remove the &lt;code&gt;res.ok &amp;amp;&amp;amp;&lt;/code&gt; since we no longer have a &lt;code&gt;res&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;Lastly, change the &lt;code&gt;return&lt;/code&gt; statement to 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="k"&gt;return&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="nx"&gt;body&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let's test
&lt;/h2&gt;

&lt;p&gt;Start your SvelteKit demo app with &lt;code&gt;npm run dev&lt;/code&gt; and navigate to &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt; in your browser. If you use Gitpod, hold CTRL / CMD pressed and click on the &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt; URL in the terminal, it'll open a new browser window with the SvelteKit demo app.&lt;/p&gt;

&lt;p&gt;Click on the "TODOS" navigation link and add a few todos, rename some, mark others as done.&lt;/p&gt;

&lt;p&gt;In a new terminal, open the Prisma Studio with &lt;code&gt;npx prisma studio&lt;/code&gt;. The studio opens in a new browser tab. Click on the &lt;code&gt;Todo&lt;/code&gt; model and validate that the data matches what you see in the SvelteKit demo app.&lt;/p&gt;

&lt;p&gt;Congratulations 🎉!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus - definitely read this&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Disable JavaScript in your browser and test the todo list again. This is how the web is supposed to work - without JavaScript!&lt;/p&gt;

&lt;p&gt;We used to develop websites like that, then we spent a decade thinking it's a great idea to move everything into JavaScript and thanks to Svelte &amp;amp; SvelteKit, we now once again develop web applications that work the way the web was intended to work.&lt;/p&gt;

&lt;p&gt;JavaScript's purpose is to enhance the web experience, not break everything if JavaScript is disabled.&lt;/p&gt;

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

&lt;p&gt;With a few modifications to a default SvelteKit demo app, we managed to configure Prisma to persist todo items. There is of course a lot more you can do with Prisma, and with SvelteKit for that matter. The source code at &lt;a href="https://github.com/mikenikles/sveltekit-prisma"&gt;https://github.com/mikenikles/sveltekit-prisma&lt;/a&gt; should get you a long way towards your own web app.&lt;/p&gt;

&lt;p&gt;If you found this interesting, you may also like (wow... is this an e-commerce website 😂?!) my current project called &lt;a href="https://github.com/webstonehq/webstone"&gt;Webstone&lt;/a&gt;. Webstone is a full-stack web application boilerplate with a CLI to automate tedious tasks like adding new pages, updating the database (of course it uses Prisma 😉). It's in early development, but do hit that star button on GitHub which helps me get motivated to spend more time on the project 🙏.&lt;/p&gt;

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

</description>
      <category>svelte</category>
      <category>prisma</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I said goodbye to local development and so can you</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Wed, 30 Jun 2021 03:18:28 +0000</pubDate>
      <link>https://dev.to/mikenikles/i-said-goodbye-to-local-development-and-so-can-you-1eca</link>
      <guid>https://dev.to/mikenikles/i-said-goodbye-to-local-development-and-so-can-you-1eca</guid>
      <description>&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Individual developer efficiency is hard to measure, but directly impacts a company’s bottom line and team morale.&lt;/li&gt;
&lt;li&gt;Remote work requires developers to onboard in isolation, a process that was already challenging when teams were co-located.&lt;/li&gt;
&lt;li&gt;Onboarding instructions are often outdated, as are automated onboarding scripts because only new hires run them.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.gitpod.io" rel="noopener noreferrer"&gt;www.gitpod.io&lt;/a&gt; provides automated, one-off development environments you spin up in the cloud for each task. In seconds, repeatedly, and securely.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
What it’s like today

&lt;ul&gt;
&lt;li&gt;Open source project onboarding&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Meet Alice and Bob

&lt;ul&gt;
&lt;li&gt;Set up a new project&lt;/li&gt;
&lt;li&gt;Develop a new feature&lt;/li&gt;
&lt;li&gt;Switch context&lt;/li&gt;
&lt;li&gt;Set up a new computer&lt;/li&gt;
&lt;li&gt;Contribute to open source projects&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;What’s the catch?&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it’s like today
&lt;/h2&gt;

&lt;p&gt;Whether you recently joined a new team or contributed to an open source project for the first time, I’m quite sure you spent anywhere from an hour to a few days onboarding. If you were lucky, other contributors provided detailed, up-to-date instructions you could follow. Possibly even commands you could copy &amp;amp; paste and watch your development environment set itself up one step at a time. If this is your experience, congratulations on finding such a great and diligent team - tell them what an awesome job they did 🤩!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;More often than not though, this is not what an onboarding experience is like.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is more likely that there are no automated scripts while instructions, if there are any, are slightly outdated or incomplete - leaving you struggling to figure things out on your own. The techlead to the rescue, who then asks you to update the documentation so the next team member who joins does not run into the same issues. Except, the project evolves, and instructions fall behind again. This is no fault of anyone in particular, but simply a fact of life because once a developer sets up their local development environment, there is no need to set it up again when the code changes. Every team member applies incremental changes to their development environment without starting from scratch, leave alone following the onboarding documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This process is costly&lt;/strong&gt;, both in terms of time and team morale. The larger your team, the more time is lost on setting up development environments and keeping them maintained. At the same time, I don’t know anyone who enjoys reading outdated documentation. Feeling helpless on the first day working on a new project is certainly not a great way to get started 😕.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open source project onboarding
&lt;/h3&gt;

&lt;p&gt;In addition, there is a cost that applies to open source projects that is almost impossible to measure: &lt;strong&gt;the % of people who would like to contribute to a project, but give up because getting started is too complex or interferes with their other projects in their local environment!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To illustrate this with an example, imagine you usually work with Java 8 and want to contribute to two open source projects. Project A requires Java 7, while project B only runs with Java 11. In order for you to contribute to these projects, you need to install a Java version manager and remember to switch Java version every time you change the project you work on.&lt;br&gt;
The exact same applies to databases (no need to install MySQL, MongoDB, Postgres, etc. locally), operating system libraries, anything you currently install locally.&lt;/p&gt;

&lt;p&gt;Let’s look at a day in the life of two developers and see how cloud-based development environments simplify workflows significantly.&lt;/p&gt;
&lt;h2&gt;
  
  
  Meet Alice and Bob
&lt;/h2&gt;

&lt;p&gt;Bob is like most of us, he works on a desktop or laptop where he installs development tools, clones git repositories and installs dependencies for the projects he works on. He may or may not have had a great onboarding experience 😉. Once every so often, Bob is required to upgrade his tools and dependencies, a task he dreads because upgrading the version of an installed programming language may impact projects that are not compatible with that newer version. With every new version he installs, his cognitive load increases as he needs to remember to switch to the correct version based on the project he works on. Bob is very, very careful in the way he treats his computer because he really doesn’t want it to break… Just imagine setting everything up again from scratch 😱.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alice is not like Bob&lt;/strong&gt;, not anymore! Alice too lived a life like Bob where she carefully set up and maintained her local development environment over the lifetime of her laptop (we will talk about her experience when she gets a new laptop later). However, she has since realized there is a better way not only for herself, but for her entire team and anyone who contributes to their projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Alice no longer has any code on her computer, none whatsoever. She does that thanks to cloud-based, ephemeral development environments provided by &lt;a href="http://www.gitpod.io" rel="noopener noreferrer"&gt;www.gitpod.io&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s dive in and learn more about Bob and Alice and how you can turn yourself from being a traditional Bob to being a modern, efficient version of Alice 🥰.&lt;/p&gt;
&lt;h3&gt;
  
  
  Set up a new project
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bob&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bob starts by cloning the source code, then ensures he has the correct runtime versions installed (e.g. Java, Node, .NET) and also makes sure the project supports his operating system.&lt;br&gt;
Once that’s all good, he looks for onboarding instructions and works his way through that, potentially spending up to a few days on this task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alice&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alice creates a &lt;code&gt;.gitpod.yml&lt;/code&gt; configuration file at the root of her project, then adds &lt;a href="https://www.gitpod.io/docs/config-start-tasks" rel="noopener noreferrer"&gt;start tasks&lt;/a&gt; such as the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;She also enables Gitpod &lt;a href="https://www.gitpod.io/docs/prebuilds" rel="noopener noreferrer"&gt;Prebuilds&lt;/a&gt; - telling Gitpod to continuously create new development environments as soon as her project’s source code changes! This significantly reduces the startup time when she or anyone who works on her project needs a development environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupyfzunappt80zyvs26s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupyfzunappt80zyvs26s.png" alt="Set up a new project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Develop a new feature
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bob&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bob is very familiar with this workflow, it’s something he does many times a week, possibly even a few times per day.&lt;/p&gt;

&lt;p&gt;He starts by making sure his new feature branch is based on the latest code. He does that by first pulling the latest default branch and then creating a feature branch.&lt;/p&gt;

&lt;p&gt;Since one of his colleagues may have added a new dependency or changed a required runtime version, Bob needs to ensure he has the latest versions. You know, otherwise he starts the dev server only to be presented with an error message telling him a dependency is missing. You know what I’m talking about 😉.&lt;/p&gt;

&lt;p&gt;Then, Bob is ready to shift into feature development mode. Well... after he started the database and dev servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alice&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;She’s keen to get started right away. Once she looks at the issue on GitHub, GitLab or Bitbucket, she simply clicks the “Gitpod” button*. This opens a new workspace with a feature branch already created, all dependencies installed and the database and dev servers started!&lt;/p&gt;

&lt;p&gt;* She gets that by installing the &lt;a href="https://www.gitpod.io/docs/browser-extension" rel="noopener noreferrer"&gt;Gitpod browser extension&lt;/a&gt;. Alternatively, she could prefix the issue URL with &lt;code&gt;gitpod.io/#&amp;lt;issue-url&amp;gt;&lt;/code&gt; to open a new development environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flifbczeaznb3ey1kcdhj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flifbczeaznb3ey1kcdhj.png" alt="Develop a new feature"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Switch context
&lt;/h3&gt;

&lt;p&gt;Imagine this: You’re working on a feature when your team member contacts you, letting you know she needs your review for a production hotfix pull request. Here’s how Bob and Alice handle this situation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bob&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hm... 🤔 Bob is a bit hesitant. He has a bunch of code changes that are not ready to be committed, he also removed a dependency that is no longer needed thanks to his feature - yay! The timing to review a pull request is less than ideal.&lt;/p&gt;

&lt;p&gt;He stashes his changes, pulls the PR branch and switches to it. Since he removed a dependency in his feature branch, he needs to install that again because the production hotfix PR still requires it.&lt;/p&gt;

&lt;p&gt;Time to start the dev server and review the hotfix. Looks good, LGTM 👍.&lt;/p&gt;

&lt;p&gt;To get back to his feature branch and continue development, he first switches back to his branch. Next, Bob needs his stashed files back, then drops that dependency his feature no longer requires and eventually starts the servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alice&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alice’s workflow is no different than when she develops a new feature. She opens a new browser tab, navigates to the pull request and opens a new development environment based on that PR. Within seconds, the environment starts and the database and dev servers already run - ready for Alice’s review.&lt;/p&gt;

&lt;p&gt;She can even leave review comments right within VS Code and have them synced with GitHub.&lt;/p&gt;

&lt;p&gt;When she’s done with the review, Alice closes the browser tab. This brings her back to her previous development environment where she continues to work on her feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqaynpg1sywub1oybbbb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqaynpg1sywub1oybbbb.png" alt="Switch context"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up a new computer
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bob&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Oh boy... where to start?! Ah right, from scratch 😰!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alice&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alice, well Alice is excited to get a new computer and is up and running as soon as she installs her favourite browser 🚀. Way to go, Alice!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flit40c6u8obqt8dgxzd7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flit40c6u8obqt8dgxzd7.png" alt="Set up a new dev environment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Contribute to open source projects
&lt;/h3&gt;

&lt;p&gt;Remember the example with the three open source projects earlier that use different versions of Java? In Alice’s case, she does not have Java installed locally at all. She starts any open source project in an ephemeral development environment and uses whatever version of Java is configured for that project. She can even contribute to two projects in parallel - if she really wanted to 😛.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s the catch?
&lt;/h2&gt;

&lt;p&gt;Well, for the time being you need an internet connection to work like Alice. The good news, it doesn’t have to be high bandwidth since the data exchange between Gitpod and your browser is minimal. A decent latency is all you need for a smooth experience.&lt;/p&gt;

&lt;p&gt;If you read this and think “Well, what about X?” please get in touch, I’d love to work with you and set up Gitpod for your project.&lt;/p&gt;

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

&lt;p&gt;Alice &amp;amp; Bob, two not-so-fictional characters living their life as software developers. I used to be a Bob for close to two decades before I found &lt;a href="http://www.gitpod.io" rel="noopener noreferrer"&gt;www.gitpod.io&lt;/a&gt; which gives me everything Alice has! Want to get a sneak peek? Click the following button to start your first development environment in the cloud (it will open the source file of this blog post):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitpod.io/#https://github.com/gitpod-io/website/blob/main/src/routes/blog/i-said-goodbye-to-local-development-and-so-can-you.md" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgitpod.io%2Fbutton%2Fopen-in-gitpod.svg%3Fv%3Dkumquat" alt="Open in Gitpod"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d love to hear your thoughts and feedback, please get in touch 🙏.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>cloud</category>
      <category>gitpod</category>
      <category>remote</category>
    </item>
    <item>
      <title>Why I Left Google and Joined Gitpod</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Mon, 15 Mar 2021 12:01:59 +0000</pubDate>
      <link>https://dev.to/mikenikles/why-i-left-google-and-joined-gitpod-4489</link>
      <guid>https://dev.to/mikenikles/why-i-left-google-and-joined-gitpod-4489</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;tl;dr:&lt;/em&gt;&lt;/strong&gt; After almost three years of working with global enterprises on their digital transformation at Google, I joined Gitpod (&lt;a href="https://www.gitpod.io"&gt;www.gitpod.io&lt;/a&gt;) to help build the Developer &amp;amp; Community Success team. Gitpod caught my attention in 2019. It is clear to me that ephemeral, cloud-based development environments are going to be the default way of working and I want to be part of the team that shapes the future for millions of developers around the world!&lt;/p&gt;

&lt;h1&gt;
  
  
  My time at Google
&lt;/h1&gt;

&lt;p&gt;I joined Google Cloud in 2018 after many years of working in the startup world. The main goal for my time there was to learn more about sales since this was one area I hadn't had much experience.&lt;br&gt;
The first day, the first week, who am I kidding... the first two years were overwhelming. I learned new things every single day, attended courses on personal growth, mentorship, DEI (diversity, equity &amp;amp; inclusion), team building, productivity, interviewing, you name it. It felt like a university where I also got paid to partner with global businesses and work on real world challenges, mainly focused on the travel &amp;amp; e-commerce industries. I led internal global communities, presented at conferences and participated in strategic meetings both internally and with customers to deliver cloud migration or application modernization projects.&lt;/p&gt;

&lt;p&gt;After two years, I started to work with a very large customer and repetition kicked in, recurring meetings dominated my calendar and my daily tasks were no longer aligned with my personal goals in life. This led me to spend more and more of my spare time pursuing my dreams, taking away time I would have much rather spent with my family.&lt;/p&gt;

&lt;h1&gt;
  
  
  2020
&lt;/h1&gt;

&lt;p&gt;Without commute and no business travel in 2020, I had a very productive year to focus on my personal interests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Book #1: &lt;a href="https://gum.co/cloud-native-web-development"&gt;Cloud Native Web Development&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Book #2: &lt;a href="https://gum.co/a-smart-guide-for-your-career-as-a-software-engineer"&gt;A Smart Guide for Your Career as a Software Engineer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SaaS #1: &lt;a href="https://www.your-analytics.org"&gt;your-analytics.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Gitpod article #1: &lt;a href="https://www.infoq.com/articles/cloud-based-development"&gt;Cloud Based Development - from Dream to Reality&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Gitpod article #2: &lt;a href="https://www.mikenikles.com/blog/why-i-use-a-cloud-based-development-environment-and-how-you-can-too"&gt;Why I use a cloud-based development environment and how you can too&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Book #1, both articles, the SaaS product, and &lt;a href="https://www.mikenikles.com"&gt;my personal website&lt;/a&gt; all relate to Gitpod (&lt;a href="https://www.gitpod.io"&gt;www.gitpod.io&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;These projects motivated me and were without a doubt a lot of fun. Most importantly, they aligned with my personal goals. I knew I needed to align my day job with something I cared about and believed in. I knew my time at Google was coming to an end.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Who in their right mind would give up a job at a global, well-paid company that repeatedly ranks as the best employer?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Read on to learn why I am that person.&lt;/p&gt;

&lt;h1&gt;
  
  
  Gitpod - The way we are all going to develop software
&lt;/h1&gt;

&lt;p&gt;It was in mid January when &lt;a href="https://www.gitpod.io"&gt;Gitpod&lt;/a&gt; reached out to me, based on my InfoQ article I linked to above and my personal advocacy for their product. It had been well over a year since I started to use Gitpod and talk about it publicly. After an initial conversation and some back and forth, we agreed there was a good fit and working together would benefit both Gitpod and myself.&lt;/p&gt;

&lt;p&gt;Throughout my career, I developed software but also enjoyed mentoring, writing and sharing my work at meetups, conferences or in articles. At Gitpod, I get to focus on all that - a true win/win. On top of that, we have an opportunity to improve the developer experience for millions of developers around the world - many of them don't know yet how much more efficient they could be 🚀!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why join Gitpod?
&lt;/h2&gt;

&lt;p&gt;I remember my excitement when jQuery, Bootstrap and React were in their very early days. I had a gut feeling these frontend frameworks would take the world by storm - and they sure did. &lt;br&gt;
About two years ago, I experienced the same with &lt;a href="https://www.svelte.dev"&gt;Svelte&lt;/a&gt; and &lt;a href="https://tailwindcss.com"&gt;Tailwind CSS&lt;/a&gt;. They are still in their early days, but make no mistake they only just got started.&lt;/p&gt;

&lt;p&gt;When I learned about Gitpod in 2019, my gut feeling was back, even stronger than when I heard of the technologies mentioned above.&lt;/p&gt;

&lt;p&gt;So let me leave this here for historians to find 😀:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Automated, ephemeral development environments in the cloud are the way we are all going to develop software in the not too distant future.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.quora.com/What-does-Googles-web-IDE-look-like"&gt;Google&lt;/a&gt;, &lt;a href="https://eng.uber.com/tech-stack-part-one-foundation"&gt;Uber&lt;/a&gt;, and more recently &lt;a href="https://twitter.com/jmwind/status/1331364214582222854"&gt;Shopify&lt;/a&gt; all already work like that, &lt;strong&gt;when will you start&lt;/strong&gt;?&lt;/p&gt;

&lt;h2&gt;
  
  
  So, what is Gitpod?
&lt;/h2&gt;

&lt;p&gt;Please read my article &lt;a href="https://www.infoq.com/articles/cloud-based-development"&gt;Cloud Based Development - from Dream to Reality&lt;/a&gt; to understand why Gitpod exists and what challenges it solves.&lt;/p&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gitpod provides always ready-to-code development environments.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a developer, think about all the time you spend setting up a new project or working your way through onboarding documentation. What about switching context when a team member asks you to review their code? Remember the last time you troubleshooted a colleague's issue that "worked on my machine"? How about a message from the team lead telling everyone to migrate to a newer version of Node.js or Java? Let's not even talk about downloading and installing dependencies or database seed scripts that no longer work because the schema changed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gitpod eliminates all that.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With Gitpod, you work in an ephemeral development environment for each feature, bug fix or code review. Even better, it all happens in a browser and requires minimal compute power on your laptop. Any and all changes to the development environment setup are reviewed, tested and versioned like all your other code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hey, don't take my word for it. Do me favour please 🙏🏻&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your browser and navigate to your GitHub, GitLab or Bitbucket project.&lt;/li&gt;
&lt;li&gt;Prefix the URL with &lt;code&gt;gitpod.io/#&lt;/code&gt; end hit Enter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. That's all it takes to spin up a new environment.&lt;/p&gt;

&lt;p&gt;Hold on though, it gets better! We haven't even talked about &lt;a href="https://www.gitpod.io/docs/prebuilds"&gt;prebuilt workspaces&lt;/a&gt;, &lt;a href="https://www.gitpod.io/docs/config-docker"&gt;custom environment images&lt;/a&gt;, or &lt;a href="https://www.gitpod.io/docs/self-hosted/latest/self-hosted"&gt;self-hosting Gitpod&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out these &lt;a href="https://www.gitpod.io/screencasts"&gt;short screencasts&lt;/a&gt; to learn more:&lt;/p&gt;



&lt;h1&gt;
  
  
  In conclusion
&lt;/h1&gt;

&lt;p&gt;Sometimes in life you have to make decisions that seem contrary to what most people would do - I'm talking about leaving Google. This is one such moment in my life, not the first and likely not the last. It is the right decision at this point in time.&lt;/p&gt;

&lt;p&gt;I talked to many people about this decision and once I presented Gitpod, the feedback was unanimous: "Wow, I can't believe how simple that is. Join them, this is exactly what you're good at!"&lt;/p&gt;

&lt;p&gt;I have no doubt the future of how we develop software is going to be based in the cloud. The amount of time we waste globally across all local development environments is simply not sustainable going forward. Developer experience is going to become a competitive advantage not only for hiring the best talent, but also to compete by improving productivity and reducing time to market.&lt;/p&gt;

&lt;p&gt;Please reach out to me via Twitter &lt;a href="https://twitter.com/mikenikles"&gt;@mikenikles&lt;/a&gt; or find me in the Gitpod community at &lt;a href="https://community.gitpod.io"&gt;https://community.gitpod.io&lt;/a&gt;. I would love to dive deeper into Gitpod and work with you to enable the next generation of software development environment for your project &amp;amp; team.&lt;/p&gt;

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

</description>
      <category>googlecloud</category>
      <category>gitpod</category>
      <category>developer</category>
      <category>experience</category>
    </item>
    <item>
      <title>A Svelte component to format numbers</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Sat, 09 Jan 2021 17:09:31 +0000</pubDate>
      <link>https://dev.to/mikenikles/a-svelte-component-to-format-numbers-477g</link>
      <guid>https://dev.to/mikenikles/a-svelte-component-to-format-numbers-477g</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@nhillier?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Nick Hiller&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/notebook?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's develop a &lt;a href="https://svelte.dev"&gt;Svelte&lt;/a&gt; component that formats numbers in a human readable way.&lt;/p&gt;

&lt;p&gt;Instead of 63476432, the component displays 64M. Here are a few more examples:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;6&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;6&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;63&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;63&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;634&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;634&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;6347&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;6.3K&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;63476&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;63K&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;634764&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;635K&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;6347643&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;6.3M&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;63476432&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;63M&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It supports different locales as well. Converting &lt;code&gt;63476432&lt;/code&gt; looks as follows&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;ko-KR&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;6348만&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;zh-TW&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;6348萬&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;de-CH&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;63 Mio.&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;ar-SA&lt;/td&gt;
    &lt;td&gt;=&amp;gt;&lt;/td&gt;
    &lt;td&gt;&lt;span&gt;٦٣ مليون&lt;/span&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How it's done
&lt;/h2&gt;

&lt;p&gt;We leverage the &lt;code&gt;Number.prototype.toLocaleString()&lt;/code&gt; method (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString"&gt;docs&lt;/a&gt;). Thanks to that, the Svelte component becomes very basic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formattedNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;notation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compact&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;compactDisplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;short&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-variant-numeric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tabular-nums&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{formattedNumber}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important to make sure &lt;code&gt;number&lt;/code&gt; is of type &lt;code&gt;Number&lt;/code&gt;. If you pass a string, the &lt;code&gt;toLocaleString&lt;/code&gt; method will not work as intended.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typescript
&lt;/h3&gt;

&lt;p&gt;I highly recommend you enable Typescript for your Svelte project (&lt;a href="https://svelte.dev/blog/svelte-and-typescript"&gt;instructions&lt;/a&gt;) and refactor the &lt;code&gt;FormattedNumber&lt;/code&gt; component as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formattedNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;notation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compact&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;compactDisplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;short&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-variant-numeric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tabular-nums&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{formattedNumber}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voilà, now the Typescript compiler makes sure you pass a &lt;code&gt;Number&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>svelte</category>
    </item>
    <item>
      <title>2021 - My Objectives &amp; Key Results</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Sat, 02 Jan 2021 17:21:46 +0000</pubDate>
      <link>https://dev.to/mikenikles/2021-my-objectives-key-results-4db7</link>
      <guid>https://dev.to/mikenikles/2021-my-objectives-key-results-4db7</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@j0rt?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;🇻🇪 Jose G. Ortega Castro 🇲🇽&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/notebook?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt;: &lt;em&gt;My personal 2021 OKRs are &lt;a href="https://www.notion.so/mikenikles/OKRs-73a4619b8b8f487ca18c6c3d5ee7570f"&gt;publicly available&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I briefly touched on Objectives &amp;amp; Key Results (OKRs) in my &lt;a href="https://www.mikenikles.com/blog/2020-year-in-review"&gt;2020 - Year in Review&lt;/a&gt; blog post. Below, I will dive deeper into what I have planned for 2021.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is OKR?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/OKR"&gt;Wikipedia article for OKR&lt;/a&gt; defines it as &lt;strong&gt;a goal-setting framework for defining and tracking objectives and their outcomes&lt;/strong&gt;. It is often used in businesses to set goals (objectives) and measurable steps to achieve these goals (key results).&lt;br&gt;
At the company level, an objective may be to have 500 new customers by the end of the year. Throughout the company departments, sub-objectives and key results are defined that all work towards that company objective. The marketing team may have a key result of "Hold two webinars per month to introduce new product features" whereas the development team may have a key result of "Achieve a &lt;a href="https://developers.google.com/web/tools/lighthouse"&gt;Lighthouse&lt;/a&gt; score of 90 across all metrics."&lt;br&gt;
A high Lighthouse score leads to a better user experience and hence, a higher conversion rate whereas the marketing team shares what's new with the world - both result in getting a step closer to 500 new customers.&lt;/p&gt;

&lt;p&gt;Your objectives must be clearly defined and your 3 - 5 key results must be measurable as seen in the two examples above. To contrast, here are two bad key results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Marketing team: "Introduce new features"&lt;/li&gt;
&lt;li&gt;Development team: "Improve Lighthouse score"
These are bad key results because you cannot measure their progress or success. "Introduce how many features? How often?" and "Improve the Lighthouse score by how much?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can assign a progress percentage to your key results, you likely have a good key result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why create personal OKRs?
&lt;/h2&gt;

&lt;p&gt;I used personal OKRs for the first time in 2020 and despite everything that happened in the world, I had one of the most productive and successful years in my life. Check my &lt;a href="https://www.mikenikles.com/blog/2020-year-in-review"&gt;2020 - Year in Review&lt;/a&gt; blog post for full details.&lt;/p&gt;

&lt;p&gt;Without goals and concrete, small steps towards these goals, living life is like driving a ship in the ocean without navigational assistance. You move (read: you get older), but you don't really know which way you go or whether you actually make progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to expect in 2021
&lt;/h2&gt;

&lt;p&gt;Towards the end of each quarter, I will plan the key results for the upcoming quarter. Check back frequently at the link below to see what quarterly OKRs I define and whether I achieved the current quarter's OKRs. See me succeed or fail 😀.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why share my OKRs publicly?
&lt;/h2&gt;

&lt;p&gt;First of all, you can find my OKRs &lt;a href="https://www.notion.so/mikenikles/OKRs-73a4619b8b8f487ca18c6c3d5ee7570f"&gt;available here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I see three benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encourage others&lt;/li&gt;
&lt;li&gt;Personal accountability&lt;/li&gt;
&lt;li&gt;See me fail in public - maybe&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Encourage others
&lt;/h3&gt;

&lt;p&gt;The main reason to share this publicly is to encourage you to think about OKRs for your life. I had great success at work for many years and exceeded my personal expectations of 2020 thanks to OKRs.&lt;/p&gt;

&lt;p&gt;I allow comments on the pages so if you have questions, you can leave comments right on the Notion pages. I'll answer whatever comes up there.&lt;/p&gt;

&lt;p&gt;I also allow duplication of these pages. Click the "Duplicate" button at the top right to create a copy in your own Notion account. All you need to do is update the databases to match your own objectives and key results. If you do that, please drop me a note on Twitter or in the comments below to let me know. I'd love to see how many people I encouraged 🙏.&lt;/p&gt;

&lt;h3&gt;
  
  
  Personal accountability
&lt;/h3&gt;

&lt;p&gt;I am generally pretty good at following through with a plan I set in motion so this is not really a reason to publish publicly. However, for people who are good at procrastinating, sharing OKRs publicly is a great way to feel a bit of social pressure to make sure you work on your goals.&lt;/p&gt;

&lt;h3&gt;
  
  
  See me fail in public - maybe
&lt;/h3&gt;

&lt;p&gt;I think where it gets interesting is if I don't achieve my objectives and run a retrospective to determine what went wrong. This is where sharing it all publicly will add a lot of value to people who follow me.&lt;br&gt;
You know, it is like when someone writes code on stage in real-time and every single attendee pays close attention and waits for an error to show up on the screen 😂. By the way, based on personal experience, this is the best way to get everyone's undivided attention!&lt;/p&gt;

&lt;p&gt;Always learn, always grow!&lt;/p&gt;

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

</description>
    </item>
    <item>
      <title>A smart guide for your career as a software engineer - My new book</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Thu, 31 Dec 2020 20:53:59 +0000</pubDate>
      <link>https://dev.to/mikenikles/a-smart-guide-for-your-career-as-a-software-engineer-my-new-book-oln</link>
      <guid>https://dev.to/mikenikles/a-smart-guide-for-your-career-as-a-software-engineer-my-new-book-oln</guid>
      <description>&lt;p&gt;You can buy the book at &lt;a href="https://gum.co/a-smart-guide-for-your-career-as-a-software-engineer" rel="noopener noreferrer"&gt;https://gum.co/a-smart-guide-for-your-career-as-a-software-engineer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F40uwz4k2q6fcpuzfqo3d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F40uwz4k2q6fcpuzfqo3d.jpg" alt="Book cover"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you want to earn a six figure income, work from anywhere, live a lifestyle of your choosing and be a part of the people who develop the next generation software applications? Are you a software engineer already, but want to change jobs or advance in your current role to get promoted?&lt;/p&gt;

&lt;p&gt;If that is you, congratulations! The bad news is that there are thousands of other people just like you with more starting that journey every day. Each one of them is a potential competitor when you look for your next job. They may even be your co-worker and friend who also want to get promoted!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Smart Guide for Your Career as a Software Engineer&lt;/strong&gt; is exactly the book you want to read. You learn what it takes to stand out among the crowd, how to impress the interviewers and most importantly, how to be an employee that gets promoted because you add value and come across as professional, well organized and energized.&lt;/p&gt;

&lt;p&gt;Throughout my career, I have had many job interviews as a candidate, interviewed well over a hundred candidates and saw even more resumes. I was fortunate to meet incredible human beings who have become good friends, but I also participated in interviews where I didn't quite understand what was happening 😆.&lt;/p&gt;

&lt;p&gt;❌ I've experienced things as bad as candidates yelling, walking out or telling us they were wasting their time talking to me and my team.&lt;/p&gt;

&lt;p&gt;✅ On the other end of the spectrum, I've witnessed candidates who showed up well prepared, confident, and people who said "I don't know" a number of times and still got hired.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to expect
&lt;/h2&gt;

&lt;p&gt;The book is structured around the following topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why become a software engineer?&lt;/li&gt;
&lt;li&gt;How to become a software engineer?&lt;/li&gt;
&lt;li&gt;Job search&lt;/li&gt;
&lt;li&gt;Resume / Curriculum Vitae (CV)&lt;/li&gt;
&lt;li&gt;Interviews&lt;/li&gt;
&lt;li&gt;Offer negotiations&lt;/li&gt;
&lt;li&gt;First day&lt;/li&gt;
&lt;li&gt;First 100 days&lt;/li&gt;
&lt;li&gt;Promotions&lt;/li&gt;
&lt;li&gt;Teamwork&lt;/li&gt;
&lt;li&gt;Leaving the company&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read it cover to cover or jump to the topic that most applies to your current situation. Armed with the knowledge, advice, tips &amp;amp; tricks and templates in this book, your chances of getting that next job or being promoted rather than your co-worker are significantly higher than without reading this book.&lt;/p&gt;

&lt;p&gt;All throughout the book, you find ✅ and ❌ to visually highlight things I recommend you do versus things you better avoid. &lt;strong&gt;There are over 80 tips &amp;amp; tricks in the book!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I am Mike Nikles; I have led hundreds of job interviews and reviewed thousands of resumes over the last twenty years in my career as a software engineer. I also sat at the other side of the interview table plenty of times as &lt;a href="https://www.linkedin.com/in/mikenikles" rel="noopener noreferrer"&gt;my LinkedIn profile&lt;/a&gt; proofs.&lt;/p&gt;

&lt;p&gt;I currently work at Google. Prior to that, I had my own business and worked at companies anywhere from two to hundreds of employees. I helped with critical first hires, tripled engineering teams and mentored others to become efficient hiring managers.&lt;/p&gt;

&lt;p&gt;You can learn more about me on Twitter &lt;a href="https://twitter.com/mikenikles" rel="noopener noreferrer"&gt;@mikenikles&lt;/a&gt; or on my personal website &lt;a href="https://www.mikenikles.com" rel="noopener noreferrer"&gt;www.mikenikles.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Templates
&lt;/h2&gt;

&lt;p&gt;Optionally, I provide templates in Google Doc / Sheet and Notion.so format for the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Job search tracking&lt;/li&gt;
&lt;li&gt;1:1 meeting notes template&lt;/li&gt;
&lt;li&gt;Personal development plan template&lt;/li&gt;
&lt;li&gt;"People I Met" spreadsheet&lt;/li&gt;
&lt;li&gt;Promotion tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the book, I describe what each template does and how you can develop your own. The templates are available if you want to save time and use what I have been battle-testing personally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why write a book about career advice?
&lt;/h2&gt;

&lt;p&gt;I dive into a bit more detail in the book itself, but I have always mentored others and started to notice patterns in what mentees asked me about. After I published my first book, &lt;a href="https://www.mikenikles.com/cloud-native-web-development" rel="noopener noreferrer"&gt;Cloud Native Web Development&lt;/a&gt; in summer of 2020, I realized I can reach a lot more people through that medium compared to 1:1 mentoring (in hindsight, things always seem obvious haha).&lt;/p&gt;

&lt;p&gt;There is an ever-growing number of people who look at starting their career as a software engineer. With GitHub, free online courses, YouTube, and many other available resources, you no longer need a university degree to be a software engineer. What you do need is passion and a desire to learn. It is a tough path, but well worth every step you take on it.&lt;/p&gt;

&lt;p&gt;I wrote this book to help you fast-track your career and make sure you stand out among the many other candidates who apply for the same role. In a remote-first world, this becomes increasingly important!&lt;/p&gt;

&lt;h2&gt;
  
  
  Purchasing Power Parity
&lt;/h2&gt;

&lt;p&gt;For my previous book, a number of people contacted me and said they would love to read it, but couldn't afford it. I provided these individuals with coupon codes based on what they said they could afford and without exception, they were thrilled and so was I 💪. I would absolutely love to provide my content for free and I will continue to do that with blog posts, helping out in online forums, answer questions in chat rooms and with videos starting in 2021, but writing a book takes effort and comes with a cost to myself which is why I charge a minimal price for it. For the next 30 days, the book is $20, which means you pay $1 for each year of experience I have, seems like a good deal to me 😉.&lt;/p&gt;

&lt;p&gt;I'm excited to announce a purchasing power parity policy (wow… that's a lot of Ps 😛). I cannot automate it, but if you think the price is too expensive, please contact me and we can figure something out that works for you. The best place to reach me is with a direct message on Twitter &lt;a href="https://twitter.com/mikenikles" rel="noopener noreferrer"&gt;@mikenikles&lt;/a&gt;. If you decide to do that, please message me with a price you can afford.&lt;/p&gt;

&lt;h2&gt;
  
  
  Help spread the word and earn 30%
&lt;/h2&gt;

&lt;p&gt;The main goal of this book is to help as many people as possible with their career as a software engineer. I can only reach so many people through my network, so here is my offer to you: Help me spread the word and earn 30% of your sales!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does it work?&lt;/strong&gt; I need you to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Gumroad.com account (so you can get paid)&lt;/li&gt;
&lt;li&gt;Contact me via Twitter &lt;a class="mentioned-user" href="https://dev.to/mikenikles"&gt;@mikenikles&lt;/a&gt; and let me know you are interested in helping me spread the word about the book&lt;/li&gt;
&lt;li&gt;Provide me with your Gumroad email address and I will create a unique link for you to share with your network. Every time someone buys a book through your link, you earn 30% of the sale.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Personally, 2020 was one of the best years of my career and I'm excited to wrap it up with the publication of this book. There is so much experience and knowledge I have acquired over the years, why keep it for myself? Onwards to 2021!&lt;/p&gt;

&lt;p&gt;If you want to hear more from me, sign up for the newsletter below or follow me on Twitter &lt;a class="mentioned-user" href="https://dev.to/mikenikles"&gt;@mikenikles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Always learn, always grow!&lt;/p&gt;

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

</description>
      <category>books</category>
      <category>career</category>
    </item>
    <item>
      <title>2020 - Year in Review</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Thu, 24 Dec 2020 19:14:26 +0000</pubDate>
      <link>https://dev.to/mikenikles/2020-year-in-review-29h5</link>
      <guid>https://dev.to/mikenikles/2020-year-in-review-29h5</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@kellysikkema?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Kelly Sikkema&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/notebook?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's a wrap for 2020, the most unpredictable year in a long time. There has been, and continues to be, tragedy and suffering for many people globally. So much of that could likely be avoided with a bit of common sense and wearing a mask… 😷&lt;/p&gt;

&lt;h2&gt;
  
  
  Year in review
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Work from home
&lt;/h3&gt;

&lt;p&gt;Some time in early March, I started to work from home. To be completely honest, I was glad it (finally) happened. I worked remotely for a few years as a freelancer earlier in my life and remember that time as the most productive time ever.&lt;/p&gt;

&lt;p&gt;For someone who works in the software industry, I have never liked open office spaces, not to mention the 9 to 5 work hours and the fact I needed to be present. These are leftovers from the industrial age. There is so much to be said about the inefficiency I have experienced in offices, let's just be glad we are past all that.&lt;/p&gt;

&lt;p&gt;What I am most thankful for is that people who can work from home finally get a chance to spend more time with their families. Missing dinners, birthdays or the first step of your child because you are abroad or working late to make someone else's dream come true is ridiculous.&lt;/p&gt;

&lt;p&gt;In my case, working from home resulted in a lot less wasted time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No more commute (~1h 15m per day)&lt;/li&gt;
&lt;li&gt;No more domestic &amp;amp; international travel (~4 to 6 days per month)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had two options as to what I could do with that extra time. Play video games, watch Netflix, scroll through Facebook or be smart. I opted for being smart and using the time wisely, which I reflected in my &lt;a href="https://en.wikipedia.org/wiki/OKR"&gt;OKRs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Objectives &amp;amp; Key Results (OKRs)
&lt;/h3&gt;

&lt;p&gt;In my first week at home earlier in 2020, I knew I had to get my WFH routine set up. The first step was to create objectives and key results for the rest of the year. I highly suggest you look into that as you wouldn't try to cross an ocean in a boat without GPS or a compass, so why live life without any clear direction?&lt;/p&gt;

&lt;p&gt;My top objectives I set for the year were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Publish a technical book about modern web development (&lt;a href="https://www.mikenikles.com/cloud-native-web-development"&gt;Cloud Native Web Development&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;✅ Develop a SaaS product to experiment with new technologies (&lt;a href="https://www.your-analytics.org"&gt;Your Analytics&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Svelte - a technology bet that paid out
&lt;/h3&gt;

&lt;p&gt;Over two years ago, I learned about &lt;a href="https://svelte.dev"&gt;www.svelte.dev&lt;/a&gt;. I spent some time to understand how it worked and it was clear to me that Rich Harris was onto something. I dropped React and started to use Svelte (&lt;a href="https://www.mikenikles.com/blog/why-i-moved-from-react-to-svelte-and-why-others-will-follow"&gt;Why I moved from React to Svelte and why others will follow&lt;/a&gt;). I received quite a bit of push back from people when I started to recommend Svelte back then, just the same way I received push back when I recommended React before people talked about it.&lt;/p&gt;

&lt;p&gt;Svelte's daily downloads &lt;a href="https://npm-stat.com/charts.html?package=svelte&amp;amp;from=2020-01-01&amp;amp;to=2020-12-31"&gt;increased by 10x this year&lt;/a&gt;, from ~2k to ~20k. Companies such as Disney and IKEA and &lt;a href="https://twitter.com/SvelteSociety/status/1260209026563858432"&gt;many others&lt;/a&gt; now use Svelte and the trend is clear.&lt;/p&gt;

&lt;p&gt;This was a bet I made two years ago and in 2020, it showed it was worth it. Expect to hear a lot more about Svelte in 2021.&lt;/p&gt;

&lt;h3&gt;
  
  
  Focus on more than one income source
&lt;/h3&gt;

&lt;p&gt;"Don't put all your eggs in one basket" is a common saying to mitigate loss. We all follow that in one way or another. Whether it is eating healthy (you wouldn't just eat pasta every day) or investing in various industries to better weather market difficulties.&lt;/p&gt;

&lt;p&gt;How many of us though rely on one single income source? "Study hard, get a good job" is what you likely heard from your parents. They told you that because it worked for them. However, with the availability of the internet and its global reach, I no longer believe a single income source to be a smart decision.&lt;/p&gt;

&lt;p&gt;My OKRs in 2020 reflect that and with my first book, I created my first additional income source besides my full-time job. As you will see in my next blog post, my 2021 OKRs are very much focused on creating further income sources. Look at yourself, find what you enjoy and what you are passionate about, then start creating. Create more and consume less!&lt;/p&gt;

&lt;h2&gt;
  
  
  What worked
&lt;/h2&gt;

&lt;p&gt;First and foremost, I published a book and made significant progress with my SaaS product, which is used by eight teams at the time of this writing. The best part: It's completely free until I get a chance to integrate with Stripe :-). If you have less than 10k pageviews per month, it will forever be free or you can self-host it for free too.&lt;/p&gt;

&lt;p&gt;Secondly, for the time of 2020 when my wife and I lived in the UK, we had a great daily exercise routine. The lack of the daily commute and generally being more active needed to be compensated for. Make sure you move!&lt;/p&gt;

&lt;p&gt;I also deleted my Facebook account and decided to focus my social media time on Twitter. More on that in my next blog post where I talk about 2021. Along the same lines, I trimmed my RSS feed, unsubscribed from all sorts of email lists, cut toxic people from my network and became a lot more protective of my time by learning to say "no".&lt;/p&gt;

&lt;h2&gt;
  
  
  What didn't work
&lt;/h2&gt;

&lt;p&gt;After relocating back to Canada, our exercise routine went down the drain for a while, something that needs to be picked up again.&lt;/p&gt;

&lt;p&gt;I stopped taking my half an hour nap at lunchtime. That was something I did for the first few months when I started to work from home and it was great. This is high on the list of things I want to revive. Even if you don't fall asleep as easily as I do, I suggest you try lying down for thirty minutes to rest.&lt;/p&gt;

&lt;p&gt;I do not yet live at the place I want to live, but this is something I will continue to work towards in the coming year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways for 2021
&lt;/h2&gt;

&lt;p&gt;In my next blog post, I will go into a lot more details on what I have planned in 2021. I will also publicly share my OKRs and hope to inspire some of you.&lt;/p&gt;

&lt;p&gt;Overall, for all that happened, 2020 was a pretty good year for me personally. The lifestyle I live now is a lot more aligned with my personal values. Not 100% yet and I will make further adjustments in 2021 to move closer to exactly how I want to live my life. More to come!&lt;/p&gt;

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

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Why I turned my homepage into a timeline</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Sun, 06 Dec 2020 21:32:28 +0000</pubDate>
      <link>https://dev.to/mikenikles/why-i-turned-my-homepage-into-a-timeline-h9</link>
      <guid>https://dev.to/mikenikles/why-i-turned-my-homepage-into-a-timeline-h9</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@fprado?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Félix Prado&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/line?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What has happened so far?
&lt;/h2&gt;

&lt;p&gt;On December 21, 2019 I migrated my blog from Medium to my own infrastructure (&lt;a href="https://dev.to/mikenikles/migrating-from-medium-to-my-own-blog-1nj8"&gt;this blog post has more details&lt;/a&gt;). The main reason was to own my content rather than leaving it on servers owned by a company. It also gives me more flexibility should the need arise to provide my content in other formats, e.g. RSS feed.&lt;br&gt;
In summer of 2020, I launched &lt;a href="https://dev.to/blog/my-personal-website-v2-0"&gt;v2 of my website&lt;/a&gt; in preparation for the publication of my first book, &lt;a href="https://dev.to/cloud-native-web-development"&gt;Cloud Native Web Development&lt;/a&gt;. The main goal of v2 was to significantly simplify the architecture.&lt;/p&gt;

&lt;p&gt;As of v2, the homepage displayed a list of blog post previews.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frskoce9bdanth9g159s9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frskoce9bdanth9g159s9.png" alt="v2 homepage with blog post thumbnails"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That was great up until just about now, read December 2020.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why choose a timeline as my homepage?
&lt;/h2&gt;

&lt;p&gt;The latest evolution of the homepage looks as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fegnxcndi49oigsf2nnfb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fegnxcndi49oigsf2nnfb.png" alt="Timeline homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lightweight version of the timeline is used on mobile:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnowka2m0wvaom4wc08h0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnowka2m0wvaom4wc08h0.png" alt="Mobile intro"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Filwiuu13j1rwytr9h5j0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Filwiuu13j1rwytr9h5j0.png" alt="Mobile timeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://twitter.com/mikenikles/status/1334305377500925953" rel="noopener noreferrer"&gt;this Twitter thread&lt;/a&gt; for progress updates and how the homepage came together.&lt;/p&gt;

&lt;p&gt;The reason to show a timeline is twofold and inspired by &lt;a href="https://www.florin-pop.com/timeline" rel="noopener noreferrer"&gt;Florin Pop's timeline on his website&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Simplicity&lt;/li&gt;
&lt;li&gt;It's about more than blog posts&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Simplicity
&lt;/h3&gt;

&lt;p&gt;A bit over 1,000 visitors per month read a single blog post where I explain why I moved from React to Svelte, according to &lt;a href="https://your-analytics.org/mikenikles.com?preset=30days" rel="noopener noreferrer"&gt;my public website analytics&lt;/a&gt;.&lt;br&gt;
The second most visited page is the homepage with roughly 800 visitors per month. While the previous version was colorful and had nice images and blog post summaries, I received feedback from people saying they look at the titles and if anything sounds interesting, they click and read the blog post.&lt;/p&gt;

&lt;p&gt;The new timeline view reflects that and only displays a blog post's title, with a call to action to read the post.&lt;/p&gt;

&lt;p&gt;A nice side effect with the new view is a much more performant homepage given there is only a single image to load.&lt;/p&gt;

&lt;h3&gt;
  
  
  It's about more than blog posts
&lt;/h3&gt;

&lt;p&gt;Throughout my career, I have mentored others, answered questions in online communities and worked on side projects.&lt;br&gt;
With the timeline view, I have a place to showcase this work and help others find me online and see what I'm up to.&lt;/p&gt;

&lt;p&gt;The filter &amp;amp; search features help narrow down what is displayed in the timeline. Starting in 2021, I am going to revive my &lt;a href="https://www.youtube.com/channel/UCgEvLz_YbByFqn8f32wh9lA" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt;, so expect there to be new entries on the timeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical implementation
&lt;/h2&gt;

&lt;p&gt;The majority of the work happened in &lt;a href="https://github.com/mikenikles/www-mikenikles-com/pull/252" rel="noopener noreferrer"&gt;PR 252&lt;/a&gt;. There are about 10 lines of custom CSS code, the rest is styled with &lt;a href="https://tailwindcss.com" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt; and of course still based on &lt;a href="https://svelte.dev" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; &amp;amp; &lt;a href="https://sapper.svelte.dev" rel="noopener noreferrer"&gt;Sapper&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>You ask, I share my opinion - Free ebook</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Mon, 17 Aug 2020 22:17:45 +0000</pubDate>
      <link>https://dev.to/mikenikles/you-ask-i-share-my-opinion-free-ebook-ejg</link>
      <guid>https://dev.to/mikenikles/you-ask-i-share-my-opinion-free-ebook-ejg</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@robschreckhise"&gt;https://unsplash.com/@robschreckhise&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since I released my Cloud Native Web Development book, many readers messaged me saying they enjoy my personal view of various topics.&lt;/p&gt;

&lt;p&gt;Would you read a free ebook written by me where I discuss my view of the tech world? You ask, I answer.&lt;/p&gt;

&lt;p&gt;Any tech topic is fair game. Learn how to code, job hunting, hiring process, interviews, promotions, big vs small biz, testing, pair programming, job levels, spaces vs tabs. Whatever you can think of, I'm sure I have an opinion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who am I?&lt;/strong&gt;&lt;br&gt;
I have twenty years of web dev experience and am the author of Cloud Native Web Development (&lt;a href="http://mikenikles.com/cloud-native-web-development"&gt;http://mikenikles.com/cloud-native-web-development&lt;/a&gt;). I was an individual contributor, software architect, co-founder, CTO and now work at Google Cloud helping enterprise customers modernize their applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does it work?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Simple, ask your question in the comments.&lt;/li&gt;
&lt;li&gt;I will collect all of them, together with the responses I get on Twitter. I will then answer each question and combine all answers in a free ebook.&lt;/li&gt;
&lt;li&gt;You download the book and start reading and learning.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ask me anything! &lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>discuss</category>
      <category>ama</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Svelte now supports TypeScript</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Tue, 21 Jul 2020 17:08:51 +0000</pubDate>
      <link>https://dev.to/mikenikles/svelte-now-supports-typescript-imo</link>
      <guid>https://dev.to/mikenikles/svelte-now-supports-typescript-imo</guid>
      <description>&lt;p&gt;That's it, Svelte now supports TypeScript :-)!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svelte.dev/blog/svelte-and-typescript"&gt;https://svelte.dev/blog/svelte-and-typescript&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>news</category>
      <category>svelte</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How I wrote 214 pages for a web development book with 19 pull requests in 3 months</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Fri, 03 Jul 2020 20:11:11 +0000</pubDate>
      <link>https://dev.to/mikenikles/how-i-wrote-214-pages-for-a-web-development-book-with-19-pull-requests-in-3-months-1b4o</link>
      <guid>https://dev.to/mikenikles/how-i-wrote-214-pages-for-a-web-development-book-with-19-pull-requests-in-3-months-1b4o</guid>
      <description>&lt;p&gt;Photo credit: &lt;a href="https://unsplash.com/@florianklauer?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Florian Klauer&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the book
&lt;/h2&gt;

&lt;p&gt;The best place to learn about the book is on its &lt;a href="https://www.mikenikles.com/cloud-native-web-development"&gt;landing page&lt;/a&gt;. It contains&lt;br&gt;
details of the content, a list of each chapter, reviews and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MIkCZebM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/0m47dte3j60x2aim4w6a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MIkCZebM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/0m47dte3j60x2aim4w6a.jpg" alt="Cloud Native Web Development cover" width="800" height="1035"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In short: Cloud Native Web Development is a hands-on guidebook that walks readers through the entire end-to-end&lt;br&gt;
process of developing, testing, deploying and monitoring a cloud-native web application.&lt;br&gt;
&lt;strong&gt;Everything you need to know, packed into a single book.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each hands-on chapter comes with a corresponding pull request on GitHub. All readers are part of a private GitHub&lt;br&gt;
organization where they can collaborate together, ask questions and exchange their experiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing and self-publishing the book - my journey
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2000 until early 2020
&lt;/h3&gt;

&lt;p&gt;A book like Cloud Native Web Development cannot be written over night. It's twenty years of work experience,&lt;br&gt;
numerous failures, a handful of successes and a personal desire to continously grow and expand my knowledge.&lt;/p&gt;

&lt;p&gt;For the past few years, I repeatedly thought I would like to write a book about everything it takes to run a web application in production. There are tutorials, video courses and guides available online for any topic you can imagine. Need to compare React and Svelte? You'll find&lt;br&gt;
&lt;a href="https://www.mikenikles.com/blog/why-i-moved-from-react-to-svelte-and-why-others-will-follow"&gt;plenty of tutorials&lt;/a&gt;. Want to learn SRE (site reliability engineering) best practices? &lt;a href="https://landing.google.com/sre/books/"&gt;Check here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, unless you know what to look for, you won't succeed because there are so many pieces to the puzzle, it's challenging to know where to start.&lt;/p&gt;

&lt;h3&gt;
  
  
  February 2020
&lt;/h3&gt;

&lt;p&gt;With COVID-19 spreading across the globe and governments putting countries into lockdown, it became immediately&lt;br&gt;
apparent that this is not like a previous pandemic. I had two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;worry, feel anxious, be unsure what to do&lt;/li&gt;
&lt;li&gt;look at it as an opportunity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was privileged enough not to worry, not to feel anxious. So I went for the second option and decided to make&lt;br&gt;
the best of the situation.&lt;/p&gt;

&lt;p&gt;It was now or never to write a book. Luckily, my wife supported me all the way, otherwise this would have never&lt;br&gt;
been possible. In fact, she encouraged me to spend as much of my spare time on the book because she knew how much it would mean to me to publish that book I had been talking about for years.&lt;/p&gt;

&lt;p&gt;The outline of the book had been in my mind for a while already. The tech stack I wanted to use was pretty clear&lt;br&gt;
to me as well. I wanted to use technologies that I believe in, technologies I use in my projects and technologies&lt;br&gt;
I believe are about to become very popular.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-publish vs. using a publisher&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a tricky one. Late in 2019, I was contacted by two publishers who asked me to develop a &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; online course. When I learned that my take-home pay would be between 12% and 18%, I declined. Now, writing a book was never about earning a lot or quitting my day job. It was about sharing my knowledge and helping others learn from my experience. Having said that and knowing my personality, I knew I would make this as perfect as it gets and invest a lot of time. So why did I reject the publishers? Quite simple, while the financial reward is not the first priority, I believe my knowledge and two decades of experience is worth something worth paying for. It's still a lot cheaper than four years at university where you are taught things you likely won't need in real life.&lt;/p&gt;

&lt;p&gt;In addition, a publisher provides you with technical reviews. Without sounding arrogant, my book is about my experience,&lt;br&gt;
my view of what's best and my best practices. There are very few people who know my experience better than myself.&lt;br&gt;
It turned out I had amazing technical reviwers among my co-workers and friends, and even a PhD student from Austria&lt;br&gt;
who, by chance, found my website and contacted me. He became the first to fully review line by line and provided input as valuable as a tech reviewer at a publishing company could have done.&lt;/p&gt;

&lt;p&gt;A publisher would have given me a wider reach, but on the other hand, my blog gets 80 to 100 unique visitors per day&lt;br&gt;
from across the world, that's good enough for me to get started.&lt;/p&gt;

&lt;h3&gt;
  
  
  March, April and May 2020
&lt;/h3&gt;

&lt;p&gt;From a "behind the scenes" point of view, these months were not exciting. Lots of writing, both the book and the corresponding source code.&lt;/p&gt;

&lt;p&gt;I started with an empty Google Doc, wrote down the top-level chapters and started with the "About the author" chapter. It&lt;br&gt;
was the only chapter I was pretty sure I knew what to write :-). It also helped to turn the white screen into something that looked like a tiny essay. Anything other than a blank page is better at that stage of the process!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development of the source code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The idea was to give access to the source code to all readers. I wanted to make sure the commit history, the PRs and everything related to the code was perfect. So how did I manage 105 commits without any mistakes or commit messages&lt;br&gt;
such as "Whoops... try again."?&lt;/p&gt;

&lt;p&gt;I had two repositories! A "playground" where I experimented, made sure everything worked and tested things for individual chapters. In parallel to the experimentation, I wrote the book's hands-on part. When I was satisfied with the code, I switched to the "clean" repository, the one readers have access to now. I followed the instructions I wrote in the book. This made sure I was the first person to actually follow along my instructions in the book.&lt;br&gt;
It also meant I wrote the entire book's source code twice - once with lots of experimentation and once in a clean way.&lt;br&gt;
As I'm writing this, I was curious to see how many commits the "playground" repo has and to my surprise... it has 119!&lt;br&gt;
That's only 14 more than the final repo... I could have sworn it would be a lot messier!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;June 2020&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The book's content was completely written some time in early June. At that point, I shared the book with a few more&lt;br&gt;
technical reviewers. Prior to that, I had a few close friends and "Thomas, the Austrian" who provided feedback.&lt;br&gt;
The tech reviews went very well and I felt comfortable publishing the book.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;June 26, 2020&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two days before the self-imposed publication deadline, my wife suggested we develop a landing page for the book.&lt;br&gt;
"Sure!" She also did some research on book covers and designed the one you see now. Based on that, we developed&lt;br&gt;
the website in the same colors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;June 27, 2020&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I adjusted headings, aligned them to new pages and updated the table of contents. My wife reviewed it and made&lt;br&gt;
sure everything was properly aligned. My wife got up, looked at me and said, "We need to change the icons in the book." One day to go... I was surely nervous, but learned over the years that it's best to trust her. I'm glad I did as the icons now look a million times better than the black &amp;amp; white ones I used previously!&lt;/p&gt;

&lt;p&gt;June 27 was a Saturday and we stayed up until 2:30am or so on Sunday morning. When we finally went to bed, we felt&lt;br&gt;
we were ready.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;June 28, 2020&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few last-minute updates to the table of contents due to changes to page numbers and I downloaded the PDF and&lt;br&gt;
published it on &lt;a href="https://gum.co/cloud-native-web-development"&gt;Gumroad&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons I learned up to this point
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I think the best thing I did was starting with a very clear idea in my mind of what I want to write about. I knew&lt;br&gt;
exactly who the target audience would be, I pretty much had all chapters in mind and also knew I wanted there to be&lt;br&gt;
source code and a private community of everyone who buys the book.&lt;/p&gt;

&lt;p&gt;Patience &amp;amp; dedication: From the very beginning, I set myself a strict deadline of June 28, 2020 (my birthday).&lt;br&gt;
This project was a big time investment and I knew there is no excuse to delay anything if I wanted to hit that deadline.&lt;br&gt;
The rule I set myself was very clear: Spend as much of my spare time on writing, every day. Looking back at my time&lt;br&gt;
tracking, I wrote at least a little bit every single day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing a 200+ book, with 19 pull requests is a lot of work and I spent a few hundred hours on it. If I write another book, I will give myself more time. It is more likely though that I would write a shorter book ;-).&lt;/p&gt;

&lt;p&gt;Perfectionism is your biggest enemy to get stuff done. Sure, I'm very proud of the final outcome and how each chapter maps to a pull request and sometimes even individual sub-chapters that map to commit messages. My readers absolutely love and appreciate this, but it put a lot of pressure on me throughout the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first week since publication
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V7HQk-0j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/728u1o7vwmg6j09etlvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V7HQk-0j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/728u1o7vwmg6j09etlvq.png" alt="Gumroad sales in week 1" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;37 books sold with no advertising other than posting on my Twitter account (500 followers) and LinkedIn.&lt;br&gt;
Given the incredible feedback I received from reviewers, I am confident I will reach a wider audience once the 37 readers wrap up the book and hopefully provide some feedback on Twitter to help promote the book.&lt;/p&gt;

&lt;p&gt;Estimates from reviewers vary between 30 to 50 hours to finish the book, depending on their level of experience&lt;br&gt;
in web development. I'm keen to keep an eye on what happens over the next few weeks and months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Writing Cloud Native Web Development was an incredibly fun project. I learned a lot about writing, publishing,&lt;br&gt;
EPUB (it's basically HTML!), marketing, and what it means to be dilligent and stick to a strict schedule.&lt;/p&gt;

&lt;p&gt;Would I do it again? Possibly, but not in 2020 :-).&lt;/p&gt;

&lt;p&gt;Please head over to the &lt;a href="https://www.mikenikles.com/cloud-native-web-development"&gt;book's page&lt;/a&gt; and get yourself a copy!&lt;/p&gt;

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

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>books</category>
      <category>svelte</category>
    </item>
    <item>
      <title>A complete rebuild of www.mikenikles.com</title>
      <dc:creator>Mike</dc:creator>
      <pubDate>Sat, 27 Jun 2020 08:16:36 +0000</pubDate>
      <link>https://dev.to/mikenikles/a-complete-rebuild-of-www-mikenikles-com-5g8f</link>
      <guid>https://dev.to/mikenikles/a-complete-rebuild-of-www-mikenikles-com-5g8f</guid>
      <description>&lt;p&gt;Photo credit: &lt;a href="https://unsplash.com/@thoughtcatalog?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Thought Catalog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's been an interesting few evenings to rebuild &lt;a href="http://www.mikenikles.com:"&gt;www.mikenikles.com:&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7aDGO_j_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/g2n6emim2sa20gar7gxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7aDGO_j_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/g2n6emim2sa20gar7gxl.png" alt="Code changes" width="150" height="35"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's first talk about v1.0
&lt;/h2&gt;

&lt;p&gt;The previous version was a proof of concept. I wanted to run&lt;br&gt;
&lt;a href="https://ghost.org/"&gt;Ghost.org&lt;/a&gt; on Cloud Run (&lt;a href="https://cloud.run"&gt;https://cloud.run&lt;/a&gt;), with &lt;a href="https://sapper.svelte.dev"&gt;Sapper&lt;/a&gt;&lt;br&gt;
as a static site generator for the frontend, so that the Ghost database did not have to be accessed at runtime.&lt;/p&gt;

&lt;p&gt;The architecture looked like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5mkpL4xd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/oaqy3r2jyl7k2bm6uuls.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5mkpL4xd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/oaqy3r2jyl7k2bm6uuls.jpg" alt="v1.0 architecture" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  What were the challenges?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Publication process&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To publish a new blog post, I had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start the Cloud SQL databaes used by Ghost.

&lt;ul&gt;
&lt;li&gt;It's worth noting I have could left that turned on, but the point was not to have a database at runtime ;-)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Log in to the Ghost instance.&lt;/li&gt;
&lt;li&gt;Write the post and upload assets.

&lt;ul&gt;
&lt;li&gt;Asking for reviews was tricky. I would have to give reviewers access to Ghost and they would see
the blog post displayed in Ghost, not the way it will look once deployed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Publish the post.&lt;/li&gt;
&lt;li&gt;Wait for the static website to be generated and deployed to Firebase Hosting.&lt;/li&gt;
&lt;li&gt;Shut down the Cloud SQL instance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As I mentioned well before I developed v1.0, this was over-engineered and overly complex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operating costs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The operating costs were about CAD $40 per month:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZYi6VqI8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/44quq1a02xwisl203u0c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZYi6VqI8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/44quq1a02xwisl203u0c.jpg" alt="v1.0 GCP costs" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Throughout the first half of 2020, the blog had ~2,000 unique visitors per month with ~5,200 page views.&lt;br&gt;
I wanted to find a more cost effective way to provide my content to others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Analytics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I used Google Analytics and Firebase Performance tracking. While the insights are interesting, I rarely looked at more than number of visitors, the country they are from and which blog posts they read. The various scripts I needed to get this to work also came at a performance cost I want to avoid in v2.0.&lt;/p&gt;
&lt;h2&gt;
  
  
  The goals for v2.0
&lt;/h2&gt;

&lt;p&gt;Before starting the project, I defined the following goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open&lt;/li&gt;
&lt;li&gt;Best practices&lt;/li&gt;
&lt;li&gt;Automation&lt;/li&gt;
&lt;li&gt;Low operating costs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Open
&lt;/h3&gt;

&lt;p&gt;I want all aspects of my website to be open. The &lt;a href="https://github.com/mikenikles/www-mikenikles-com"&gt;source code&lt;/a&gt;&lt;br&gt;
including project management, pull requests, issues, etc.&lt;/p&gt;

&lt;p&gt;Each blog post will be released as a pull request. Anyone can access drafts and provide feedback. This also gives me the flexibility to potentially allow for community contributions such as translations etc.&lt;/p&gt;

&lt;p&gt;In addition, I will make the website's analytics available publicly as part of a project later in 2020. Stay tuned for that by following me on Twitter &lt;a href="https://www.twitter.com/mikenikles"&gt;@mikenikles&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Best practices
&lt;/h3&gt;

&lt;p&gt;As it has always been the case, my personal website is a place for me to experiment with new technologies.&lt;br&gt;
If I get asked "How would you ...?" in relation to web development, I want my answer to be "Have a look at&lt;br&gt;
&lt;a href="http://www.mikenikles.com"&gt;www.mikenikles.com&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;A perfect Lighthouse score, fully accessible, top SEO ratings, works without JavaScript, etc.&lt;/p&gt;
&lt;h3&gt;
  
  
  Automation
&lt;/h3&gt;

&lt;p&gt;For anyone who's worked with me they know that automation is near and dear to me. "Don't document what you can automate!"&lt;br&gt;
The focus is on using NPM scripts where necessary and connect it all via GitHub Actions.&lt;/p&gt;

&lt;p&gt;Each PR provides a preview URL and once merged, a production deployment happens within seconds.&lt;/p&gt;

&lt;p&gt;To create a new blog post and all necessary directories, I use &lt;code&gt;npm run generate&lt;/code&gt; and answer a few questions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Operating costs
&lt;/h3&gt;

&lt;p&gt;As close to $0 as possible and no database since it's all static content - simple.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's new in v2.0?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;It's &lt;strong&gt;a lot&lt;/strong&gt; simpler:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nS-3Hnp---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/haf0eo2hk5m6wazowphr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nS-3Hnp---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/haf0eo2hk5m6wazowphr.png" alt="Architecture 2.0" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Diagram source: &lt;a href="https://excalidraw.com/#json=5406435517136896,jY4N1Wo4Vgqn45E9uxUqPA"&gt;https://excalidraw.com/#json=5406435517136896,jY4N1Wo4Vgqn45E9uxUqPA&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All we've got is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://gitpod.io/"&gt;Gitpod.io&lt;/a&gt; for my cloud-based development environment.

&lt;ul&gt;
&lt;li&gt;Get 30% off your Gitpod subscription with my &lt;strong&gt;coupon code&lt;/strong&gt; &lt;code&gt;mikenikles&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mikenikles/www-mikenikles-com"&gt;GitHub&lt;/a&gt; for the blog posts, source code and workflow automation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt; for hosting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The publication process now looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the blog post and add assets.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git push&lt;/code&gt; it to GitHub and open a pull request.&lt;/li&gt;
&lt;li&gt;Share the draft URL with reviewers; iterate on the post.&lt;/li&gt;
&lt;li&gt;Merge the PR.

&lt;ul&gt;
&lt;li&gt;Deployment to production then happens automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Interactive blog posts written in &lt;code&gt;mdsvex&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is arguably a bit of a nice-to-have. It is so nice though that I have to point it out!&lt;/p&gt;

&lt;p&gt;I write this blog post in &lt;a href="https://mdsvex.com/"&gt;&lt;code&gt;mdsvex&lt;/code&gt;&lt;/a&gt; which is basically Markdown with &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; mixed in wherever I want.&lt;/p&gt;

&lt;p&gt;An example taken from &lt;a href="https://svelte.dev/examples:"&gt;https://svelte.dev/examples:&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Clock /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The above clock only renders on my blog at &lt;a href="https://www.mikenikles.com/blog/my-personal-website-v2-0"&gt;https://www.mikenikles.com/blog/my-personal-website-v2-0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the blog post file, the following is what I write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Clock&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;./clock.svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

...
Another example, taken from https://svelte.dev/examples:

&lt;span class="nt"&gt;&amp;lt;Clock&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm looking forward to taking advantage of that as I get back into more frequent blogging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Draft preview URLs
&lt;/h3&gt;

&lt;p&gt;Have a look at the &lt;a href="https://github.com/mikenikles/www-mikenikles-com/pulls?q=is%3Apr+is%3Aclosed+label%3A%22blog+post%22"&gt;recently closed blog post pull requests&lt;/a&gt;, open one and find the preview URLs to see how the post looked when it was in draft.&lt;/p&gt;

&lt;p&gt;With the blog post's content available in the pull request, reviewers can comment on individual lines and I can pick up the conversation right there in the correct context. No more back &amp;amp; forth via emails or copy &amp;amp; paste from shared Google Docs.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Personal website &amp;amp; blog
&lt;/h3&gt;

&lt;p&gt;I track the v2+ project &lt;a href="https://github.com/mikenikles/www-mikenikles-com/projects/2"&gt;on GitHub&lt;/a&gt;. The focus is going to be on small enhancements and experiments as I see fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Book: Cloud Native Web Development
&lt;/h3&gt;

&lt;p&gt;On June 28, 2020, I (will release) released my book &lt;a href="https://www.gum.co/cloud-native-web-development"&gt;Cloud Native Web Development&lt;/a&gt;.&lt;br&gt;
It's two decades of web development experience packed into 200+ pages and 19 pull requests. It's a hands-on guidebook from zero to production and anything in between!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use coupon code &lt;code&gt;DEV&lt;/code&gt; for a 25% discount!&lt;/strong&gt;&lt;/p&gt;

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

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>svelte</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
