<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
  <channel>
    <feedpress:locale>en</feedpress:locale>
    <atom:link rel="hub" href="http://feedpress.superfeedr.com/"/>
    <image>
      <link>https://hoyci.unessa.net/</link>
      <title><![CDATA[Too Many Choices - Same Con to Hoyci]]></title>
      <url>https://static.feedpress.com/logo/hoyci-5de6e637de95e.png</url>
    </image>
    <title>Too Many Choices - Same Con to Hoyci</title>
    <link>https://hoyci.unessa.net/</link>
    <description>A blog about Web development, usability and AI.</description>
    <lastBuildDate>Thu, 20 Jan 2022 05:38:22 GMT</lastBuildDate>
    <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
    <generator>Gridsome Feed Plugin</generator>
    <atom:link href="https://rss.unessa.net/UnessanetHoyci" rel="self" type="application/rss+xml"/>
    <item>
      <title><![CDATA[The Hidden Value of Magic (and Tailwind CSS)]]></title>
      <link>https://rss.unessa.net/link/17725/13881237/magic</link>
      <guid>https://hoyci.unessa.net/2020/09/magic/</guid>
      <pubDate>Tue, 15 Sep 2020 23:31:13 GMT</pubDate>
      <content:encoded><![CDATA[<p>As I&#39;ve begun the full rewrite process of my <a href="https://slipmat.io">Slipmat.io hobby project</a>, I&#39;m astounded how much I&#39;ve been learning from all kinds of things every step of the way, by carefully analysing the old, and making lots of effort in engineering and designing the new. What follows is one of my latest learned lessons that connected some dots between 15 years of working with the Web.</p>
<p>Python is my favourite programming language, and I&#39;ve always stayed firmly with the Django camp as opposed to Flask or any other gazillion alternatives. In the early days of Django (like 15 years ago) I also had lots of reservations against Rails, mostly because I was young and stupid, but also because it had too much <em>magic</em>. The more I&#39;ve worked with JavaScript the more I&#39;ve learned about good architecture and best practises from bad examples, and my views on magic have changed somewhat.</p>
<p>JavaScript is a fascinating language. <a href="https://auth0.com/blog/javascript-whats-new-es2020/">ECMAscript 2020</a> is the ultimate lipstick on a pig. The core language is such an awful mess, yet the new syntax is pretty powerful and the modern tooling built around it is truly amazing and wonderful to work with. And as the tools have gotten so much better in a very rapid pace, the community is starting to get the libraries and coding conventions in a better shape as well.</p>
<p>Vue 3 is a great example of this. It&#39;s built totally from ground up using TypeScript, designed with an <a href="https://github.com/vuejs/rfcs">open RFC process</a> taking feedback from the whole community, and Evan You has done a lot of work shaping the end result into something that&#39;s actually designed to be used and not only something that <em>looks</em> good.</p>
<p>The work on my <a href="https://hoyci.unessa.net/2020/08/weeknotes-35/">new Vue 3 project template</a> has advanced to list screens which need various list components, preferably in a form of a powerful datatable component. I had to completely drop the project for a while to get a better understanding what I&#39;d really want here. Today I finally had an epiphany; the thing that&#39;s most wrong in the current Slipmat design are the numerous different random third-party components that even though styled to look somewhat (but not exactly) similar, they all <em>feel</em> different. And this exactly is my issue with glue-in frameworks like Flask as well. Even though the various parts can be easily used together, there&#39;s always something missing compared to tools like Django where everything is built to work together.</p>
<p>So now we get dangerously close to the infamous <a href="https://en.wikipedia.org/wiki/Not_invented_here">not invented here syndrome</a>. If gluing up various third-party solutions yields bad results, then surely we should write all components ourselves? Well, no. Firstly, always prefer an existing ui library (like Vuetify for Vue/Material Design) over building <em>anything</em> yourself. Secondly, --and this is again something I realised today-- properly architectured third-party components can be not just almost but <em>precisely</em> tweaked to fit your design. And whenever using them, you should take the time to do that design work properly. <strong>The main problem with inconsistent Web UIs is handwritten CSS.</strong> Whenever a non-designer needs to invent their own styles, the end result will end up looking something that almost matches the thing they did yesterday, <em>but only almost</em>. And this is where <a href="https://tailwindcss.com/">Tailwind CSS</a> shows again how brilliant the utility-first idea really is; there is close to zero handwritten css needed for most Tailwind projects which automatically restricts you to a relatively small amount of professionally curated choices. The end result looks automatically not-very-bad and with some tweaking it’s not hard to get absolutely spot-on. (To be fair, it’s not easy either, but unlike trying to manually come up with CSS, it’s way easier!)</p>
<p>After I watched <a href="https://www.youtube.com/watch?v=fx2lbOCAqrg">Adam Wathan build this select component</a>, I was convinced that this would be the way I should build the few components (button, toggle-switch, modal, toast, data table / list component, datepicker, tag input) I need for the Slipmat rewrite.</p>
<p>(Yes. NIH. I&#39;d <strong>love</strong> to use some third-party library here but at the moment there just aren&#39;t too much to choose from for Vue 3 and Tailwind.)</p>
<p><img src="https://hoyci.unessa.net/2020/09/magic/img/datatable_experiment.png" alt="Datatable experiment"></p>
<p>The first iterations don’t need to be anything too fancy so I’m confident that building all of these from scratch instead of trying to modify third-party alternatives won’t be an issue. I’m also fully prepared to switch to using <a href="https://github.com/tailwindlabs/tailwindui-vue">@tailwindui/vue</a> or some other library in the future if maintaining these eats too much time. Just to get a feeling of what the API would maybe feel like <a href="https://github.com/Uninen/datatable-experiment">I created an experiment project</a> and pushed it to GitHub (not GitLab because on GH I get Dependabot updates automatically).</p>
<p>So this story has been a bit of a rambling journey from back in the early days of Web frameworks to Vue 3 and Tailwind CSS. What I’m finding common between all these projects is the meticulous attention to detail regarding almost every aspect of the tool, especially to API design. <strong>Great tools aren’t born by accident, they are engineered.</strong> And after working with JavaScript for few years now I’m starting to appreciate the metaprogramming powers of Python which makes it possible to write super clean —and somewhat magical— APIs. A good amount of magic really makes a difference in developer experience when it’s done right. I still do think that having a pluralization engine that automatically fetches <a href="https://api.rubyonrails.org/classes/ActiveSupport/Inflector/Inflections.html">one Octopus and many Octopi</a> is way too much but I also do appreciate the attention to detail in Rails the more I get to see language restricted not-so-beautiful designs in JavaScript land.</p>
<p>So the lesson of the day: <strong>invest in API design</strong> and <strong>the most value from magic comes from those situations where you can&#39;t see it</strong>.</p>
<img src="https://rss.unessa.net/link/17725/13881237.gif" height="1" width="1"/>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Howto Rename Git Master Branch]]></title>
      <link>https://rss.unessa.net/link/17725/13842912/git-trunk</link>
      <guid>https://hoyci.unessa.net/2020/08/git-trunk/</guid>
      <pubDate>Sat, 29 Aug 2020 11:12:13 GMT</pubDate>
      <content:encoded><![CDATA[<p>While Git uses the term <em>master</em> <a href="https://git.github.io/rev_news/2020/07/29/edition-65/">in the sense of &quot;master record&quot;</a>, it&#39;s clear that master as a term has connotations to master-slave methaphor which is both <a href="https://tools.ietf.org/id/draft-knodel-terminology-00.html#rfc.section.1.1.1">technically and historically inaccurate</a> according to The Internet Engineering Task Force. Here&#39;s how to rename Git master branch both in your local repository and on GitLab.</p>
<h3 id="1-rename-git-master-branch">1. Rename Git Master Branch</h3>
<p>First, rename master and push the change to origin, then update local references to this new name. (I&#39;m using <code>trunk</code> here as the new name but you can use main or whatever you wish. Just change the commands accordingly.)</p>
<pre><code class="language-shellscript">git checkout master
git branch -m master trunk
git push -u origin trunk

git branch --unset-upstream
git branch -u origin/trunk
git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/trunk</code></pre>
<h3 id="2-change-gitlab-default-branch-and-delete-master">2. Change GitLab Default Branch (And Delete master)</h3>
<p>Navigate to <code>Settings &gt; Repository</code> and set the new default branch. (In GitHub you&#39;ll find the same setting under repository <code>Settings &gt; Branches</code>.)</p>
<p><img src="https://hoyci.unessa.net/2020/08/git-trunk/img/gitlab_default_branch.png" alt="Settings"></p>
<p>Lastly you may want to delete the old master branch but you need to remove protected branch status from GitLab before being able to do that. Go to <code>Protected Branches</code> on this same <code>Settings &gt; Repository</code> page and <code>Unprotect</code> the master branch if it&#39;s protected. (Don&#39;t forget to add the same protections back to the new branch!) Now we can delete the old master branch:</p>
<pre><code class="language-shellscript">git push origin --delete master</code></pre>
<h3 id="bonus-change-default-git-branch-for-new-repositories">Bonus: Change Default Git Branch For New Repositories</h3>
<p>Since Git version 2.28 you can easily set the default branch name for all new repos with a simple command:</p>
<pre><code class="language-shellscript">git config --global init.defaultBranch trunk</code></pre>
<p>Congrats for participating in making the word just a little bit better place for all of us!</p>
<img src="https://rss.unessa.net/link/17725/13842912.gif" height="1" width="1"/>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Weeknotes 35/2020]]></title>
      <link>https://rss.unessa.net/link/17725/13842270/weeknotes-35</link>
      <guid>https://hoyci.unessa.net/2020/08/weeknotes-35/</guid>
      <pubDate>Fri, 28 Aug 2020 15:15:15 GMT</pubDate>
      <content:encoded><![CDATA[<p>Many of my developer peers seem to have picked up the practise of publishing weeknotes. I&#39;ve been meaning to do this for a long time, so here goes.</p>
<h3 id="shaping-up">Shaping Up</h3>
<p>I discovered <a href="https://basecamp.com/shapeup">Shape Up</a> originally via Adam Wathan who posted absolutely brilliant <a href="https://twitter.com/adamwathan/status/1296447318074568704">Twitter thread about becoming a succesful independent maker</a>. It took me a wihe to manage to actually read it, but now that I finally did, it left me with some good ideas about shaping up (pun intended) my own work practises.</p>
<p>Shape Up is a very Basecamp-y look on modern development workflow and work practises. It narrows down on an idea of a 6-week work cycle where the team works on a pre-planned (shaped) project with external phases for planning and also for bug-fixing (what they call cooldown). Reading this felt really good as it is very similar what I&#39;ve been doing with many teams of various sizes for a long time now.</p>
<p>I&#39;ve found out that with most agile teams the idea of a 10-day sprint that <em>inludes</em> design and retro phases are just way too short. It forces the work to be planned and scheduled too much from the top down and leaves the team very little time for independent organization. If the work is instead planned (shaped up) beforehand with a smaller and more experienced team, and there is a separate bugfixing (or cooldown) period after the actual work phase (which is longer than two weeks) the probability of succesful delivery grows drastically.</p>
<p>This is very interesting topic for me and I&#39;ll propably write more about it in the future. With some new inspiration from these ideas I reorganized my near future personal work in a new way. I converted my monthly plan from two sprints into a one cycle with a proper Iteration Plan (idea <a href="https://github.com/microsoft/vscode/wiki/Iteration-Plans">stolen from VS Code</a> team) that has just one properly shaped and planned goal and clear dates for work phase. My cycle lasts for three weeks after which there is a one-week cooldown for bugfixes and planning for the next cycle. This method lets me keep monthly release cycle and hopefully allows me to actually ship something every single release. I may report back on the success of this model in the future.</p>
<h3 id="new-vue-3--typescript-project-template">New Vue 3 + TypeScript Project Template</h3>
<p><a href="https://hoyci.unessa.net/assets/img/postimg/panopticon_mobile_dashboard.png"><img src="https://hoyci.unessa.net/assets/img/postimg/panopticon_mobile_dashboard_small.png" class="left mt-2" /></a>For my end goal of <strong>shipping a totally new Vue 3 + TypeScript powered frontend for Slipmat users and artists</strong> I need a good and tested base for which to build on. To experiment with this I started a new project from scratch to remake the current admin views which have become a bit of a dumpster fire.</p>
<p>I&#39;m using <a href="https://tailwindui.com">Tailwind UI</a> components as a base which makes getting started really easy and fast. Unfortunately all the components are based on very bright color themes so I&#39;ve had to come up with my own dark color scheme as <a href="https://slipmat.io">Slipmat needs to be dark</a> by default. I spent a week with the initial design and refactoring some old API views to get some basic dummy data for developing. The end result looks pretty good as a starting point, I&#39;m sure the final product will work out great. (This is just a proof of concept after all!)</p>
<p>Vue 3 is now in RC phase and using it with TypeScript feels really solid already. The tooling (devtools in particular) is lagging a little bit behind but it&#39;s early days still. I&#39;ve got the project base pretty much nailed, it has fully automated CI/CD pipeline with <a href="https://www.cypress.io/">end to end tests with Cypress</a> and <a href="https://miragejs.com/">Mirage JS</a> with coverage monitoring that fails the build if coverage drops below 80%.</p>
<p>I&#39;ve also tried to keep everything as lean and as close to native JavaScript as possible. Most of the usual go-to libraries have had a tough screening and for example Moment.js (70k) had to go in favor of <a href="https://day.js.org/en/">Day.js</a> (2k). So far I&#39;ve managed not to load lodash either, although it might come back at some point as practicality beats purity. I might do a write up of these most used third-party libraries as well when I&#39;m starting the final production projects.</p>
<p>Here&#39;s the full list of my current dream stack that powers the new project:</p>
<ul>
<li><a href="https://v3.vuejs.org/">Vue 3</a> (w/ <a href="https://cli.vuejs.org/">vue-cli</a>)</li>
<li><a href="https://www.typescriptlang.org/">TypeScript</a></li>
<li><a href="https://tailwindcss.com/">Tailwind CSS</a></li>
<li><a href="https://www.cypress.io/">Cypress</a> for e2e-tests</li>
<li><a href="https://miragejs.com/">Mirage JS</a> for dev and test backend</li>
</ul>
<h3 id="javascript-search-engines">JavaScript Search Engines</h3>
<p>Proper search is something that I&#39;ve never got time to build for Slipmat yet but especially for admin tools it&#39;s very important. We do run Elastic on our backend stack but I wanted to investigate if I could whip up something very fast and totally in-browser so I studied few JavaScript search engines.</p>
<p>Turns out there aren&#39;t that many serious contenders. There&#39;s <a href="https://fusejs.io/">Fuse.js</a> which is great for small datasets (say less than few thousands of objects). I&#39;ve used it in the past for some projects but I wanted something a bit more serious for this. There&#39;s also <a href="https://github.com/olivernn/lunr.js/">Lunr.js</a> and <a href="https://github.com/weixsong/elasticlunr.js">Elasticlunr.js</a> both of which are loosely based on Solr. These are serious search engines with lots of options for tweaking the results and proper indexing.</p>
<p>I ended up picking <a href="https://github.com/lucaong/minisearch">MiniSearch</a> which is a tiny (6k min+zip) yet &quot;proper&quot; and modern search engine that has no external dependencies and can do all kinds of nice things like fuzzy matching, auto suggestions, field boosting and realtime index updating. It can also export and import the built index which makes the initialization very fast. I&#39;m testing the system with a 2Mb json file that has few thousand latest instances of about every model one might want to search (offline) from the admin dashboard. The biggest overhead comes from downloading this first json. Initializing the engine takes about 300ms but when you save the index it shrinks to about 1,5Mb and initializing that only takes about 50ms. As an initial proof of concept the simple pre-warmed and cached json works well enough though.</p>
<p>I&#39;m not yet sure if having a offline-capable frontend-only search is worth it when everything is already indexed in Elasticsearch but this was an interesting one-day experiment in any case. Here&#39;s the search in action:</p>
<p><a href="https://hoyci.unessa.net/2020/08/weeknotes-35/img/first_search_demo.gif"><img src="https://hoyci.unessa.net/2020/08/weeknotes-35/img/first_search_demo.gif" alt="Search Demo"></a></p>
<p>Okay so this weeks notes were a bit on the long side but hey, it&#39;s been a while. But let&#39;s try to do this again next week! In the meanwhile, find the RSS-feed and @Uninen on Twitter :)</p>
<img src="https://rss.unessa.net/link/17725/13842270.gif" height="1" width="1"/>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Howto Add TypeScript to Your Existing Vue Project]]></title>
      <link>https://rss.unessa.net/link/17725/13336315/vue-typescript</link>
      <guid>https://hoyci.unessa.net/2020/03/vue-typescript/</guid>
      <pubDate>Tue, 10 Mar 2020 13:13:13 GMT</pubDate>
      <content:encoded><![CDATA[<p>The more I work with scripting languages like JavaScript with modern tools like VS Code, the more I learn to appreciate the powers of static typing. TypeScript is a <a href="https://www.typescriptlang.org">typed superset of JavaScript</a> that compiles to plain JavaScript, and with good tools it can seriously improve your productivity.</p>
<p>Vue has a somewhat mixed TS story. On the other hand most notable packages support it well but then there are also large painpoints like Vuex that can make your life miserable. Upcoming Vue 3 is completely rewritten in TypeScript which will improve TypeScript support hugely. In attempt to future-proof a rewrite of a large existing Vue app, I decided to start gradually typing it with TypeScript. Here are some of the initial notes from my experience.</p>
<p>(Disclaimer: even though I&#39;m an experienced Vue developer, I&#39;m a complete TS-newbie so YMMV.)</p>
<h2 id="the-unbearable-lightness-of-starting-slow">The Unbearable Lightness of Starting Slow</h2>
<p>Problem with most TypeScript tutorials and simple examples is that they expect you to either start from scratch or completely convert all of your code to TypeScript from the very first step. For an existing codebase, that&#39;s obviously not going to happen. I would also personally advice against it even if there were tons of tests and all the time in the world to do it, especially if you&#39;re new to TypeScript.</p>
<p>The great secret of TypeScript is that <strong>you can start as small as you like and add typings gradually</strong>. By doing it this way you&#39;ll probably find some problems with your existing code and get the chance to refactor it properly as you move forward. Granted, you won&#39;t get the full benefits of TypeScript before you reach a certain critical point of typing completeness, but starting it small will cost you almost nothing so its very easy to get started. Life with legacy codebases is all about compromises and this path will at least give you a chance for better future.</p>
<h3 id="step-1-initial-installation">Step 1: Initial Installation</h3>
<p>If you&#39;re vue project is created with vue-cli, adding typescript looks easy: just <code>vue add typescript</code>. Problem is, the defaults may not be that good for you and you should know what they mean. Here&#39;s what I answered to the installer questions:</p>
<h4 id="use-class-style-component-syntax-❌no">Use class-style component syntax? ❌No</h4>
<p>By default this plugin suggests you to use class-style components which are an easy way to get started with Vue and TypeScript. Class based api was supposed to be the future of Vue, but the class syntax is in many ways problematic and if you plan to upgrate to Vue 3, you will want to <a href="https://vue-composition-api-rfc.netlify.com/">consider composition api instead</a>.</p>
<p>Note that many tutorials and existing TypeScript code for Vue uses class syntax. If you opt out here you have much less refactoring to do with your JavaScript and you are more future-proof with Vue 3, but you will also lose a big chunk of the examples and tutorials out there right now.</p>
<h4 id="use-babel-alongside-typescript-required-for-modern-mode-auto-detected-polyfills-transpiling-jsx-✓-yes">Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? ✓ Yes</h4>
<p>If you have an existing project where you use Babel, you&#39;ll definitely want to keep using it with TypeScript as well.</p>
<h4 id="convert-all-js-files-to-ts-❌no">Convert all .js files to .ts? ❌No</h4>
<p>This is the most problematic suggestion of them all. Sure, if you&#39;re converting a small app with five files for fun, do it. But if you&#39;re adding TypeScript to a larger project, definitely do not rename all of your JavaScript files in one go, that&#39;s just asking for trouble.</p>
<h4 id="allow-js-files-to-be-compiled-❌no">Allow .js files to be compiled? ❌No</h4>
<p>As the documentation on the whole plugin is <a href="https://cli.vuejs.org/core-plugins/typescript.html">very thin</a>, I don&#39;t exactly know what this option even means but I assume it&#39;s one more toggle to help you bruteforce TypeScript into your project. By default any JavaScript code will stay JavaScript and only .ts files and script tags with <code>lang=&quot;ts&quot;</code> will be compiled, and that&#39;s the way you&#39;ll want it to be when starting gradually.</p>
<h3 id="step-2-cleaning-up">Step 2: Cleaning Up</h3>
<p>The &quot;helpful&quot; installer will modify your existing code so you&#39;ll need to do a bit of cleanup before getting back to business. First, you&#39;ll want to delete the re-appeared <code>src/components/HelloWorld.vue</code> as I&#39;m quite sure no one is actually using that in a real project (right??). You also want to fix the havoc in your <code>src/App.vue</code> while you&#39;re at it. The <code>main.js</code> is now renamed to <code>main.ts</code>. This is a good change as it reminds you immediately that this project uses TypeScript even though most of the files might still be JavaScript.</p>
<p>The newly added <code>tsconfig.json</code> includes somewhat strict settings that may or may not work with your project. The stricter the rules, the more benefits you get from TypeScript, but on the other hand the stricter the rules, the harder it is to make your existing code valid. For me one of the first steps with an existing project was to <strong>disable strict checking</strong>. This allowed me to gradually add typings to complex files without spending hours and hours in debugging or adding the file full of ignores. Note that by loosening the checking you will lose some of the most powerful gains you could have from your editor and TS in general so evaluate yourself if you can leave it on or not.</p>
<p>(For example, with strict checking on, when editing a method inside a Vue component, the editor will know that <code>this</code> refers to a specific Vue instance. This is super powerful when it works. When strict checking is disabled, <code>this</code> inside of a component method is inferred as <code>any</code> type which will not help you at all.)</p>
<p>I would not tweak tsconfig too much more before you understand better the challenges in your specific project. Give yourself time to test and experiment before committing to any specific rule.</p>
<h3 id="step-3-start-adding-typings">Step 3: Start Adding Typings</h3>
<p>Now you are ready to start adding your first types! I&#39;d suggest to start in a file that is large or otherwise not so easy to read at a first glance -- this is where you&#39;ll get most gains.</p>
<p>This is not a tutorial on TypeScript itself, you&#39;ll find plenty of them elsewhere. The <a href="https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html">migrating from JavaScript</a> document is a good read and <a href="https://alligator.io/vuejs/using-typescript-with-vue/">Using TypeScript with Vue Single File Components</a> was very helpful to me as well. <a href="https://github.com/ffxsam/vue-typescript-cookbook">Vue + TypeScript Cookbook</a> is a brilliant source of practical advice and it also points out some of the long standing issues such as the problems with Vuex.</p>
<p>Oh yes, Vuex. Have a plan for Vuex. Almost all larger projects use Vuex and for example the <code>mapState</code> helper, so you&#39;ll immediately be in a world of trouble as <strong>Vuex does not have proper TypeScript support and no simple solution has been found by the community</strong>. This does not mean that you can&#39;t use Vuex with TypeScript or that there are no solutions. It just means that there are no good universal solutions. You need to experiment and evaluate which of the <a href="https://github.com/vuejs/vuex/issues/564">dozens of proposed workarounds</a> works best for you. And know that if it at some point stops working in your specific edge case, you&#39;re alone with your problem as there is no officially supported way. This obviously sucks big time, but there is at least some light at the end of this tunnel as Vue 3 will eventually bring proper TypeScript support to Vuex as well.</p>
<p><strong>Try not to ignore</strong> code. Alarm bells should ring if your TypeScript code starts gathering <code>// @ts-ignore</code>-lines more than actual refactoring. It&#39;s the same with linting: the point is to make your code better, not to work around your tooling. Sure, there are situations where practicality beats purity but make a mental note for yourself to keep those situations exceptions. If you find a file too hard to convert, just leave it be until you or your tools become smarter.</p>
<p>There are a couple of good rules of thumb you should keep in mind. First, <strong>all new code should be typed</strong>. This is kind of obvious but also easy to forget. Add documentation and processes in place to make sure that from now on, all new code in the project is written in TypeScript instead of JavaScript. You can help this process with CI scripts and other tools: ban adding <code>.js</code> files and if you have tools that generate new files, convert them to generate <code>.ts</code>.</p>
<p>Secondly, <strong>try not to change too much in one go</strong>. It&#39;s very easy to stumble down into the rabbit hole and use hours and hours adding typings with very little practical gains. As you learn more and as Vue world matures, you&#39;ll be getting more and more out of TypeScript. And then some day when you understand more about your project and the tools, you&#39;ll see more clearly when it is the right time to take the last step of converting all the remaining code to TypeScript. Remember, cleaning up your codebase is not a race, it&#39;s a neverending journey.</p>
<h3 id="things-will-break----its-a-good-thing">Things Will Break -- It&#39;s a Good Thing</h3>
<p>The thing with TypeScript that makes it both helpful and painful at the same time is the fact that it&#39;s much more unforgiving to mistakes that you&#39;ve used to with JavaScript. My very first steps with TS in a real world project involved several hours of debugging a file that would not compile no matter what I did. Turns out it was due to a missing import in a legacy method that was never called. You&#39;ll never find out things like this in JavaScript but they will bite you with TypeScript as soon as you turn it on, so be mentally prepared.</p>
<p>Legacy code is difficult in many ways and hunting down new bugs that previously weren&#39;t there can feel frustrating. But remember that this is <em>exactly</em> why you want to use TypeScript in the first place: to see and fix those bugs early. It&#39;s very likely that your old production code is relying on a bug you didn&#39;t even know was there and turning on TypeScript will now break that code. Learn to embrace these growing pains because fixing them will make your code better and keep your productivity high in the long run.</p>
<img src="https://rss.unessa.net/link/17725/13336315.gif" height="1" width="1"/>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Hello Comments!]]></title>
      <link>https://rss.unessa.net/link/17725/13259177/comments</link>
      <guid>https://hoyci.unessa.net/2020/02/comments/</guid>
      <pubDate>Sun, 16 Feb 2020 23:32:23 GMT</pubDate>
      <content:encoded><![CDATA[<p>For this weeks weekend project I decided to dive a bit deeper into <a href="https://firebase.google.com/">Google Firebase</a> and built a commenting system for this Gridsome-based blog from scratch. It was definitely not worth the time in the sense of adding commenting possibility to a blog but as a learning journey I&#39;d say this was a fun little project.</p>
<p>Gridsome is a JAMstack tool which means that features like commenting need to be implemented either as a third-party solution or by using a separate backend functionality be it serverless functions, a traditional REST backend or something similar. Firebase is an interesting app development platform startup that was aquired by Google in 2014. What makes Firebase intresting for this kind of applications is its realtime database and hosted pluggable authentication system. Google offers a fairly generous free tier for the services so testing it out for a personal project like this is costs you only your time.</p>
<p>I&#39;ll write more in depth about technical details later but for now, I&#39;m happy to get this thing published. The biggest lesson learned here was that as with any tehcnologies, even though the 2 minute demo seems really clean and easy, most real worl implementations need to focus on details that are hard to get right if you care about user experience and security.</p>
<p>(Obviously, this first implementation is very unpolished and not feature-complete, but it should work, that&#39;s the most important thing for now.)</p>
<img src="https://rss.unessa.net/link/17725/13259177.gif" height="1" width="1"/>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Better GraphQL Explorer for Gridsome]]></title>
      <link>https://rss.unessa.net/link/17725/13222645/graphql-explorer</link>
      <guid>https://hoyci.unessa.net/2020/02/graphql-explorer/</guid>
      <pubDate>Tue, 04 Feb 2020 22:22:22 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://gridsome.org/docs/data-layer/">Gridsome data layer</a> is built on GraphQL and the development server comes bundled with a graphical UI for studying the schema building queries. This UI, however, is not very useful if you don&#39;t already know GraphQL. I recently found out that there is a much better tool called <a href="https://github.com/OneGraph/graphiql-explorer">graphiql-explorer</a> that allows you to <strong>build GraphQL queries graphically</strong> and that it can be very easily used with Gridsome as a VS Code plugin.</p>
<p><a href="https://hoyci.unessa.net/2020/02/graphql-explorer/img/graphiql-explorer-vscode.png"><img src="https://hoyci.unessa.net/2020/02/graphql-explorer/img/graphiql-explorer-vscode.png" alt="GraphiQL Explorer inside VS Code"></a></p>
<p><small>(Note: if you happen to use some other editor, you should be able to install <code>graphiql-explorer</code> by adding it in the dev server config with <code>configureServer</code>-hook.)</small></p>
<h3 id="the-1-minute-install">The 1-minute install</h3>
<ol>
<li>Install the <code>vscode-graphiql-explorer</code>-extension.</li>
<li>In your repository root, while your development server is running, generate a GraphQL schema for the plugin with following command: <code>npx get-graphql-schema http://localhost:8080/___graphql &gt; schema.graphql</code> (the first part of the URL should be your development server URL). You might want to add <code>schema.graphql</code> to gitignore as well.</li>
<li>Profit!11</li>
</ol>
<p>You can now use the GraphiQL explorer inside your VS Code. Run <code>Explore schema with GraphiQL</code> command to see it in action.</p>
<h3 id="notes">Notes</h3>
<ul>
<li>The two other commands added by this extension don&#39;t currently work with the custom Gridsome GraphQL blocks inside -vue files. What you can do is either copy the code in an open explorer window or open it in a new file and then run the explore-command. <a href="https://github.com/zth/vscode-graphiql-explorer/issues/7">I opened a ticket</a> for fixing this, it seems that it <em>might</em> be fixed quite soon.</li>
<li>graphiql-explorer is <a href="https://www.gatsbyjs.org/blog/2019-06-03-integrating-graphiql-explorer/">bundled with Gatsby</a> and according to Gridsome developers, <a href="https://twitter.com/gridsome/status/1224064440892440576">they might switch</a> to using it in Gridsome as well. There&#39;s actually an <a href="https://github.com/gridsome/gridsome/issues/708">old ticket about this</a>, too.</li>
<li>Shout-out to <a href="https://twitter.com/eunjae_lee">@eunjae_lee</a> for leading me into this rabbit hole :)</li>
</ul>
<img src="https://rss.unessa.net/link/17725/13222645.gif" height="1" width="1"/>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Building An Open Graph Image Builder (Part 1)]]></title>
      <link>https://rss.unessa.net/link/17725/13208749/og-image-builder-part-1</link>
      <guid>https://hoyci.unessa.net/2020/01/og-image-builder-part-1/</guid>
      <pubDate>Thu, 30 Jan 2020 22:11:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>I&#39;ve been slowly updating this blog to the modern world from the ages when people wrote their XML-feeds by hand (yes, it was a thing). One of the &quot;new&quot; things Web sites nowadays have in their meta tags are <a href="https://ogp.me/">Open Graph</a> preview images (or social previews). These images are used to make preview cards in various places, for example when posting links to Twitter and other sites.</p>
<p>There are tools like <a href="https://pablo.buffer.com/">Pablo</a> for creating these images online. Recently I&#39;ve switched to creating them manually with <a href="https://www.pixelmator.com/pro/">Pixelmator</a> but I&#39;ve long been looking for a Web-based solution that could be integrated better with my other blogging workflows.</p>
<p>Two days ago I happened to stumble on to ZEIT Now&#39;s blog post <a href="https://zeit.co/blog/social-og-image-cards-as-a-service">Social Cards as a Service</a> where they dogfood their own serverless platform by building a simple image generator tool that uses Puppeteer to render the images. I immediately dove in to <a href="https://github.com/zeit/og-image/blob/master/web/index.ts">the source code</a> hoping that I could modify it to my own needs but it looked way too complicated for my taste. (In other words, I didn&#39;t understand most of it.) The UI got me thinking that building a simple framework around Tailwind would probably be super easy and would allow lots more control. So I sat down for two evenings and came up with <strong><a href="https://og-image-builder.now.sh/">Open Graph Image Builder</a></strong>.</p>
<p>This is still a work in progress and I&#39;m not sure how far I want to develop this but so far it has been a fun little project.</p>
<h3 id="the-toolchain">The Toolchain</h3>
<p>My absolutely favourite frontend tool for simple projects like this has been <a href="https://cli.vuejs.org/">Vue CLI</a>. Problem with that is that as soon as you start thinking about publishing something, you&#39;ll have gazillion things to glue together and configure before you have a production-ready site. (I should probably invest some time into a proper cookiecutter template...) This exactly is why I recently wrote <strong>Tulip</strong>, a <a href="https://github.com/Uninen/gridsome-starter-tulip">simple one page starter template for Gridsome</a> (which is just Vue with some JAMstack flavor).</p>
<p>Tulip ships with <a href="https://tailwindcss.com/">Tailwind CSS</a> preconfigured so I was immediately ready to build something interesting.</p>
<p>The third weapon of choise was <a href="https://zeit.co/">ZEIT Now</a>. I&#39;ve been following their journey for a long time because of <a href="https://simonwillison.net/tags/zeitnow/">Simon Willison</a> but never actually tried the platform. As it was their inspiration that led me to this path it was only appropriate to try out the service with this project. The <a href="https://zeit.co/download">first installation</a> and publishing workflow via the deploy button in Tulip repository was unbelievably easy, even easier than Netlify if it&#39;s even possible. (Although I did have an issue with GitLab import. It didn&#39;t work so I pushed my code in GitHub instead and after that everything has been smooth sailing.)</p>
<p>Example output:</p>
<p><img src="https://hoyci.unessa.net/2020/01/og-image-builder-part-1/img/og-builder-example-2.png" alt="Tulip starter for Gridsome preview"></p>
<h3 id="to-be-continued">To Be Continued...</h3>
<p>The project is just getting started and I want to learn the ZEIT platform a bit more to be able to write about it better. I&#39;ll also probably implement a proper backend rendering for the images so it&#39;ll be a bit more useful in practise.</p>
<p>In part 2 of this series I&#39;ll dive deeper into the code, going through some of the challenges and design decisions along the way.</p>
<p>In the mean time, check out the <a href="https://github.com/Uninen/og-image-builder">project source code</a> and <a href="https://twitter.com/uninen">follow me on Twitter</a>!</p>
<img src="https://rss.unessa.net/link/17725/13208749.gif" height="1" width="1"/>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Howto: Draft Posts With Gridsome]]></title>
      <link>https://rss.unessa.net/link/17725/13196020/draft-posts-with-gridsome</link>
      <guid>https://hoyci.unessa.net/2020/01/draft-posts-with-gridsome/</guid>
      <pubDate>Wed, 22 Jan 2020 01:32:11 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://gridsome.org">Gridsome</a> is a Vue-based static site generator inspired by <a href="https://www.gatsbyjs.org/">Gatsby</a>. As of version 0.7 there is no official way to have a publishing flow that separates draft and published posts. For me this is a big deal as I like to iterate on my writings for several days or weeks before publishing them. Luckily, there is an <a href="https://github.com/gridsome/gridsome/issues/536#issuecomment-510687476">easy way to add support</a> for draft posts yourself.</p>
<h3 id="adding-a-new-graphql-property">Adding a New GraphQL Property</h3>
<p>At the heart of a Gridsome site is a <a href="https://gridsome.org/docs/data-layer/">GraphQL data layer</a> that you can use and manipulate in development mode. Gridsome fetches any sources you define into this GraphQL storage in development mode and during the build process writes the data into static files as instructed in your configuration.</p>
<p>The naive way of importing any data into Gridsome just adds it into the storage and it then respectively gets published as you build the site. A super simple way to implement draft functionality is to simply add an attribute to your data object and then filtering by this attribute when building the site.</p>
<p>Add the following javascript in a file called <code>gridsome.server.js</code> in the root of your Gridsome project:</p>
<pre><code class="language-javascript">module.exports = function(api) {
  api.loadSource(store =&gt; {
    if (process.env.NODE_ENV === &#39;production&#39;) {
      const posts = store.getContentType(&#39;Post&#39;)

      posts.data().forEach(node =&gt; {
        if (node.published !== true) {
          posts.removeNode(node.id)
        }
      })
    }
  })
}</code></pre>
<p>(Change the <code>Post</code> ContentType to match whatever your source plugin <code>typeName</code> has been configured to in <code>gridsome.configjs</code> plugins section. The default for <code>source-filesystem</code>-plugin is <code>FileNode</code>.)</p>
<p>Now, when you run <code>gridsome build</code>, the API that loads your sources at build time filters out each post that hasn&#39;t got a <code>published</code>-attribute that evaluates to true. (Note that if you have a blog with lots of content and you don&#39;t want to add a new attribute to all of them, you might want to reverse the logic, for example to <code>if (node.draft !== true)</code>. I like to explicitly mark published posts, YMMV.)</p>
<p>For Markdown and Front Matter content you can now add <code>published: false</code> to your post meta to be able to filter out draft posts in production. (Modifying other content sources is left to the reader.)</p>
<img src="https://rss.unessa.net/link/17725/13196020.gif" height="1" width="1"/>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[My Goals for 2020]]></title>
      <link>https://rss.unessa.net/link/17725/13195841/goals-for-2020</link>
      <guid>https://hoyci.unessa.net/2020/01/goals-for-2020/</guid>
      <pubDate>Sat, 18 Jan 2020 23:23:23 GMT</pubDate>
      <content:encoded><![CDATA[<p>I don&#39;t usually write (publicly) down any new year&#39;s resolutions but as I feel like I&#39;ve been finding more and more excuses of writing less and finishing fewer hobby projects, some public peer pressure would help me to maintain some focus. So here we go; my tech-related goals for the year 2020.</p>
<h3 id="1-publish-weekly-blog-posts">1. Publish Weekly Blog Posts</h3>
<p>On this one I have to take a somewhat late start as January almost flew by already, but I&#39;m targetting to write to this blog at least ~50 new posts this year. I love writing and I do write quite a lot but I&#39;ve lost the habbit of doing it in the form of blog posts -- and I want to get that habbit back.</p>
<p>I have tons of stuff in various draft posts and even more ideas about things to write about and I&#39;m looking forward to make myself find a good publishing rhythm after a long hiatus. So stay tuned! :)</p>
<h3 id="2-release--document-more-hobby-projects">2. Release / Document More Hobby Projects</h3>
<p>One of my biggest problems is that I <em>love</em> digging into new technologies and starting something but then never actually getting anything published (nor documenting the journey). I want to learn to be better especially in the documenting part as I know that it&#39;s where I can contribute the most (compared to actual coding, for example).</p>
<h3 id="3-release-at-least-two-serious-side-projects">3. Release At Least Two Serious Side Projects</h3>
<p>I&#39;ve been working on a side project called <a href="https://slipmat.io">Slipmat.io</a> for almost four years without actually committing to getting it properly published. I&#39;ve also sat on a good idea (in my opinnion) without moving it forward for a couple of years now and I <em>really</em> want to get both of these projects in a better place.</p>
<p>While Slipmat is more of a hobby project, the second idea is something that could actually be turned into a proper SaaS business if done correctly. Both of these require a <em>lot</em> of time to complete so I really need to learn to split things up in smaller iterations and move faster if I&#39;m going to pull this off. I&#39;ll be documenting both of these journeys here, so again, stay tuned.</p>
<h3 id="4-attend-to-a-new-tech-conference">4. Attend To a New Tech Conference</h3>
<p>I&#39;ve been attending to Python-related conferences <a href="https://hoyci.unessa.net/2007/07/lightning-talk-hacking-europythonorg/">since 2007</a>. This year I want to find a new non-Python conference to find different perspectives into the world of modern software development.</p>
<h3 id="5-fix-my-tooling">5. Fix My Tooling</h3>
<p>When I was younger, I was constantly obsessing over my tooling to make my workflows faster and better. Lately I&#39;ve noticed that my hatred towards computers and technology has grown so big that I&#39;m usually just happy if my tools even <em>start</em>. The Web tooling has gotten so big and complex that it takes serious time and effort to keep everything up to date -- not to mention of trying to optimize things.</p>
<p>I want to make some time and rebuild some very basic stuff (starting with <a href="https://gitlab.com/uninen/dotfiles">dotfiles</a>) around my personal tooling, document them better and start to get back on top of things again. Continuous improvement, <a href="https://en.wikipedia.org/wiki/Kaizen">Kaizen</a>, is something that I&#39;m really passionate about so this is again a goal that is hopefully going to lead to some interesting and fullfilling paths.</p>
<p>So, there are my five fairly ambitious goals for 2020. Now, it&#39;s time for some action!</p>
<img src="https://rss.unessa.net/link/17725/13195841.gif" height="1" width="1"/>]]></content:encoded>
    </item>
    <item>
      <title><![CDATA[Django Tip: Smarter Output From Management Commands]]></title>
      <link>https://rss.unessa.net/link/17725/13048535/output-smarter</link>
      <guid>https://hoyci.unessa.net/2019/12/output-smarter/</guid>
      <pubDate>Sun, 08 Dec 2019 02:20:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Have you ever tried to add a helpful output for showing the progress of a slow management
command but all the output frustratingly appears in one go after the script has finished?
You&#39;ve tripped into something called <a href="https://www.quora.com/What-is-output-buffering-in-Python">output buffering</a> and luckily it&#39;s very easy to fix.</p>
<h3 id="use-selfstdout-instead-of-print-in-management-commands">Use <code>self.stdout</code> instead of <code>print</code> in management commands</h3>
<p>You should never use <code>print</code> inside Django management commands as they have a special
<code>self.stdout</code> method that makes testing easier. This method frustratingly takes slightly different arguments than print, but it also has <a href="https://docs.djangoproject.com/en/3.0/howto/custom-management-commands/#management-commands-output">more features</a> like <a href="https://docs.djangoproject.com/en/3.0/howto/custom-management-commands/#django.core.management.BaseCommand.style">styling</a>. Here&#39;s how you would do a simple row of dots that grows iteratively:</p>
<pre><code class="language-python">self.stdout(&quot;.&quot;, ending=&quot;&quot;, flush=True)
self.stdout.flush()</code></pre>
<p>Note the <code>flush()</code>. This is wat forces the output to be shown to the user before the script finishes. And the same with print:</p>
<pre><code class="language-python">print(&quot;.&quot;, end=&quot;&quot;, flush=True)</code></pre>
<p>Both <code>self.stdout</code> and <code>print</code> will add newline to the output by default but you can disable that by explicitly setting the ending as an empty string. And when you flush your output manually, you&#39;ll get nice and interactive console output for your management commands -- voilà!</p>
<p><small class="text-sm">(Btw. If you have ever wondered about <code>ENV PYTHONUNBUFFERED 1</code> in some of the Docker images for Python, this is why; disabling output buffering makes reading Docker logs way easier.)</small></p>
<img src="https://rss.unessa.net/link/17725/13048535.gif" height="1" width="1"/>]]></content:encoded>
    </item>
  </channel>
</rss>
