<?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: Ville M. Vainio</title>
    <description>The latest articles on DEV Community by Ville M. Vainio (@vivainio).</description>
    <link>https://dev.to/vivainio</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%2F187703%2F7fabf917-5de1-4703-aaa6-b479a86c4fc6.jpeg</url>
      <title>DEV Community: Ville M. Vainio</title>
      <link>https://dev.to/vivainio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vivainio"/>
    <language>en</language>
    <item>
      <title>Your Angular app probably doesn't need SASS</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Mon, 13 Jul 2020 18:52:09 +0000</pubDate>
      <link>https://dev.to/vivainio/your-angular-app-probably-doesn-t-need-sass-534l</link>
      <guid>https://dev.to/vivainio/your-angular-app-probably-doesn-t-need-sass-534l</guid>
      <description>&lt;p&gt;As it turns out, &lt;a href="https://github.com/angular/angular-cli/issues/17879"&gt;using SASS can slow your Angular build a lot&lt;/a&gt;. This may come as a suprise, since SASS, when run from command line (either dart-sass or the C++ based node-sass) can churn through tons of files in few seconds. When used in Angular components, however, you could be looking at one minute of just parsing SASS in medium-large application with hundreds of components. &lt;/p&gt;

&lt;p&gt;At this point you will be asking "so why are we using SASS in the first place" - and it probably boils down to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$variables&lt;/li&gt;
&lt;li&gt;Nesting&lt;/li&gt;
&lt;li&gt;Mixins&lt;/li&gt;
&lt;li&gt;No harming in doing that right?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Variables are the trivial part - you can replace them with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties"&gt;CSS Variables&lt;/a&gt; (or "CSS custom properties" if you are a cop). This can be done with a well-placed script run, but you need to be careful about calling calc() when SASS was just computing a value directly.&lt;/p&gt;

&lt;p&gt;Nesting is something you thought you wanted but actually you possibly don't. Since component styles are already scoped per-component, you can usually refer to single css class .foo without requiring it to be child of &lt;code&gt;:host&lt;/code&gt;, which is child of &lt;code&gt;.my-section&lt;/code&gt; etc. In fact, lot of nesting creates a lot of unnecessary bloat in the output .css files. Moreover, the whole &lt;code&gt;:host&lt;/code&gt; thing is only needed to style the topmost, "host" element. &lt;code&gt;::ng-deep&lt;/code&gt; (which we pretend to be deprecated) will work just fine in .css files.&lt;/p&gt;

&lt;p&gt;Mixins - odds are you are overusing them. If you have a base style called &lt;code&gt;.btn&lt;/code&gt; and you &lt;code&gt;include .btn&lt;/code&gt; in several places, consider just saying &lt;code&gt;&amp;lt;button class="btn my-buttonish-thing"&amp;gt;&lt;/code&gt; in your .html files. The "macro" capability of SASS could be considered competing and inferior to using the native browser feature of, well, supporting CSS classes that add styling to your elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eject!
&lt;/h2&gt;

&lt;p&gt;At this point, you will be looking for exits. So here's one path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a script to extract your $variables to &lt;code&gt;my-arr-variables.css&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Write a script to run node_modules/.bin/sass.cmd to all your &lt;code&gt;*.component.scss&lt;/code&gt; files. Keep the ones that didn't explode in size due to overzealous use of SASS features and leave the rest as SASS.&lt;/li&gt;
&lt;li&gt;Keep your global top level styles as .scss files, but do consider compiling them outside &lt;code&gt;ng build&lt;/code&gt; and referring them as plain .css files (i.e. not referring to them from angular.json, just add a &lt;code&gt;&amp;lt;link rel="stylesheet" href="my-global-styles.css"&amp;gt;&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>On (not?) splitting big .NET applications to assemblies</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Mon, 06 Jul 2020 16:35:26 +0000</pubDate>
      <link>https://dev.to/vivainio/on-not-splitting-big-net-applications-to-assemblies-5l4</link>
      <guid>https://dev.to/vivainio/on-not-splitting-big-net-applications-to-assemblies-5l4</guid>
      <description>&lt;p&gt;This only applies to .NET, and to large code bases fully controlled by you (preferably in a monorepo).&lt;/p&gt;

&lt;p&gt;There are good dependencies, and bad dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bad dependency
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Depends on a big framework (asp.net, wcf, ef, DI containers, etc.)&lt;/li&gt;
&lt;li&gt;Depends on several own assemblies&lt;/li&gt;
&lt;li&gt;Depends on a third party library

&lt;ul&gt;
&lt;li&gt;There are some exceptions in every product, e.g. NewtonSoft.Json, System.Reactive etc. can be "universal"&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Has significant business logic code

&lt;ul&gt;
&lt;li&gt;...and therefore can change frequently&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Good dependency:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Is mostly declarations. POCOs, constants, enums, interfaces, attributes.&lt;/li&gt;
&lt;li&gt;Can be compiled in the beginning of your build.&lt;/li&gt;
&lt;li&gt;Can be compiled when your services are running (check OutputPath!)&lt;/li&gt;
&lt;li&gt;Doesn't change often. It's "ready".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can bundle a lot of good dependencies together to same DLL without cost. If your DLL is less than 100kb, it's possible it&lt;br&gt;
can be merged with other small DLLs to simplify your dependencies and speed up the build. Instead of &lt;code&gt;Feature.Foo.dll&lt;/code&gt; and &lt;code&gt;Feature.Bar.dll&lt;/code&gt;, consider if you could just have &lt;code&gt;Feature.dll&lt;/code&gt; if those two libraries depend on same things.&lt;/p&gt;

&lt;p&gt;Contrary to naive intuition, fine grained DLL's are not efficient and usually not desirable. You are not selling them separately, or distributing to other applications. When you need to add new DLLs (e.g. because it provides integration with some new third party library or service), consider if there are other DLLs you could get rid of in your code base.&lt;/p&gt;

&lt;p&gt;You can add a reference to a good dependency without sweating it much. Most probably, you are already depending on it so you don't need to.&lt;/p&gt;

&lt;p&gt;Namespaces for internal code don't really matter. Don't overbloat your pull requests by adjusting them constantly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;... except when they matter, and you have abominations like &lt;code&gt;NetDataContractSerializer&lt;/code&gt; hiding somewhere. Stay safe!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
    </item>
    <item>
      <title>Notes from a local NuGet package development workflow</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Sun, 08 Mar 2020 10:14:44 +0000</pubDate>
      <link>https://dev.to/vivainio/notes-from-a-local-nuget-package-development-workflow-53c1</link>
      <guid>https://dev.to/vivainio/notes-from-a-local-nuget-package-development-workflow-53c1</guid>
      <description>&lt;p&gt;&lt;em&gt;Note: this is not a production-proven workflow, take it as lab notes I wrote while I still remembered how it works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When developing a NuGet package, you easily end up with situation where you depend on another package published from the same (mono)repository.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;I have FastExpressionKit targeting &lt;code&gt;netstandard2.0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;I have FastExpressionKit.BulkInsert targeting &lt;code&gt;net472&lt;/code&gt; (because &lt;code&gt;netstandard2.0&lt;/code&gt; is missing &lt;code&gt;System.ComponentModel.DataAnnotations&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;I have FastExpressionKit.Test that runs tests against both of the libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FastExpressionKit.Test needs to use &lt;code&gt;ProjectReference&lt;/code&gt; instead of &lt;code&gt;PackageReference&lt;/code&gt;, because you couldn't run the test suite against unpublished packages. You also want a fast edit/run inner development loop.&lt;/p&gt;

&lt;p&gt;I solved this dilemma by doing the following for each csproj:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dotnet pack -c Release /p:Version=1.1.0 /p:PubVer=1.1.0

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;PubVer&lt;/code&gt; is the toggle that switches on PackageReference. Excerpt from FastExpressionKit.BulkInsert.csproj:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;  &lt;span class="nt"&gt;&amp;lt;ItemGroup&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"$(PubVer) == ''"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ProjectReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"..\FastExpressionKit\FastExpressionKit.csproj"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ItemGroup&lt;/span&gt; &lt;span class="na"&gt;Condition=&lt;/span&gt;&lt;span class="s"&gt;"$(PubVer) != ''"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"FastExpressionKit"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"$(PubVer)"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When running tests, &lt;code&gt;PubVer&lt;/code&gt; is not defined and ProjectReference is activated. That wasn't so bad, especially since you can slap the &lt;code&gt;Condition&lt;/code&gt; on &lt;code&gt;ItemGroup&lt;/code&gt; instead of reference itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local feeds
&lt;/h2&gt;

&lt;p&gt;In order to create a package for FastExpressionKit.BulkInsert, it needs access to FastExpressionKit package. For a version you don't want to publish yet. Hence we publish it to local feed immediately after &lt;code&gt;dotnet pack&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dotnet nuget push -s c:\localfeed .\bin\Release\FastExpressionKit.1.2.0.nupkg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to actually use this local repository, you have to create file called NuGet.Config (case sensitive!) with content (adjust relative path accordingly):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;﻿&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;packageSources&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"local"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"..\..\localfeed"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/packageSources&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When this is in place, PackageReference will find the FastExpressionKit package from that local directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do it like this???
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;NuGet, unlike pip or npm, doesn't have built-in support for this workflow so tricks are needed&lt;/li&gt;
&lt;li&gt;Paket.local doesn't support SDK-style project files&lt;/li&gt;
&lt;li&gt;For convenience, the version of all NuGet packages in the FastExpressionKit "package family" is the same, i.e. one specified by both &lt;code&gt;PubVer&lt;/code&gt; and &lt;code&gt;Version&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;I didn't really run those commands, I have &lt;a href="https://github.com/vivainio/FastExpressionKit/blob/master/publish.py"&gt;publish.py script&lt;/a&gt; that does these steps. For the sake of historical correctness, here's the snapshot of the script:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;shutil&lt;/span&gt;

&lt;span class="n"&gt;LOCAL_FEED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r".\dev\localnuget"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;projects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"FastExpressionKit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"FastExpressionKit.BulkInsert"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.2.0.0"&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nuke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pth&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pth&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rmtree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nuget_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pth&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"dotnet nuget push -s &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;LOCAL_FEED&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pth&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;startdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;prjdir&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startdir&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;prjdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;nuke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;nuke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"obj"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"dotnet pack -c Release /p:Version=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; /p:PubVer=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pkgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bin/Release"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"*.nupkg"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;nuget_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkgs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Got a better workflow that is not a massive MsBuild XML library? Let us know in the comments!&lt;/p&gt;

</description>
      <category>dotnet</category>
    </item>
    <item>
      <title>Trivial, typesafe translations in Angular</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Wed, 17 Jul 2019 13:22:38 +0000</pubDate>
      <link>https://dev.to/vivainio/trivial-typesafe-translations-in-angular-3aod</link>
      <guid>https://dev.to/vivainio/trivial-typesafe-translations-in-angular-3aod</guid>
      <description>&lt;p&gt;The official Angular translation system (angular-i18n) is problematic in various respects (read this ticket and thread in ngx-translate project for background):&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/ngx-translate/core/issues/783" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Discussion: future of the library
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#783&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/ocombe" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars0.githubusercontent.com%2Fu%2F265378%3Fv%3D4" alt="ocombe avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/ocombe" rel="noopener noreferrer"&gt;ocombe&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/ngx-translate/core/issues/783" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 30, 2018&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Hello everyone, I'd like to discuss about the future of this library and get your opinion on my plans.&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;(Long) history&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;You can skip that part if you don't care about how this library came to life&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When I started this library 3 years ago, I wanted to learn Angular and I thought that working on an open source project would be the best way to do that. It had worked for me on AngularJS with my library ocLazyLoad that was a huge success (2600 stars) and whose core principles were finally integrated into the framework in v1.6.7.&lt;/p&gt;
&lt;p&gt;At the time I was looking for a way to translate my Angular apps and found out that there was nothing in Angular to do that (i18n wasn't even existing in the framework). I asked my good friend Pascal Precht if he was interested in porting angular-translate from AngularJS to Angular but he wasn't and told me that I should do it.&lt;/p&gt;
&lt;p&gt;My library quickly became popular for various reasons (no real alternative, I had a good reputation from my work on ocLazyLoad, my appearances in Angular Air and my talks at conferences). And I guess that the code was good enough and easy to start with.
It was also a time where the framework was still in beta, and there were no real guidelines for publishing libraries for Angular, it was so hard to do it that not a lot of people were trying and I didn't have any real competition on i18n for a long time.&lt;/p&gt;
&lt;p&gt;Some time later, the library ecosystem started to settle and Angular was stable, they decided to drop the name Angular 2/4/... in favor of just "Angular". I decided to rename this library ngx-translate and to use npm scopes in order to deliver a modular experience. I rewrote the whole library and made it possible to replace some parts (loader, parser, compiler, ...).
It was still a side project for me, but I was using it at work because we had finally started using Angular in production and needed to translate the app in multiple locales.&lt;/p&gt;
&lt;p&gt;The official i18n implementation was super complicated (and still is), it didn't support json, code translation, changing the locale without reloading the app, and you needed multiple app bundles (one per locale). My library was so popular that I wanted to work on it full time because I could see that it was a necessity for the Angular community. It solved a lot of use cases, and was simple enough to be usable in a few minutes.&lt;/p&gt;
&lt;p&gt;I decided to quit my job and see if I could make a living out my open source work. I knew that it was possible because ag-grid had done it and they were very successful. It was in December 2016, I had 2 months left at work before I was free, and I went to the conference NG-BE where Igor Minar from the core team was present. I wanted to ask him some advices on how to turn this into a profitable OSS project, but before I could tell him about my plans, he told me: &lt;em&gt;"Ah Olivier, I wanted to talk to you, you've got to stop working on your library [ngx-translate], Companies come to us and want to do i18n, but they only talk about your library, we want them to use our solution [Angular i18n] because it's more efficient".&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I was a bit speechless, I was there about to tell him that I had quit my job and wanted to work full time on my lib, and he was asking me to stop working on it. So I did what anyone with a bit of common sense would have done, I told him that Angular i18n sucked, that it failed to deliver the promise of easy-to-use-yet-powerful that they wanted Angular to be.
I probably didn't use those words, but he agreed with me that it still needed some work, but they didn't have enough resources to work on it (Victor Savkin and Jeff Cross had just left the team to create Nrwl).
I jumped on the occasion and told him that I would love to work with them to improve Angular i18n.
He told me that he would consider it, and we left it at that.&lt;/p&gt;
&lt;p&gt;A few weeks later, and recontacted me, and told me that they were ok to hire me as a contractor to work on i18n. It was like Christmas for me (actually it was around Christmas, so that might explain it) because working for Google is a once in a lifetime opportunity and a dream job. But working on open source, from home, for Angular, it was even better and I didn't even thought that it was possible for me to do that.&lt;/p&gt;
&lt;p&gt;I joined the team in February 2017 (almost a year ago), and started working on i18n. There was a lot of work to do, but I was confident that I could make a difference. It was clear to me at the time that it would take a few months to make i18n easier to use for everyone, with the features that people wanted, and that I could deprecate my library after that.&lt;/p&gt;
&lt;p&gt;It turns out that working on a framework like Angular is super complicated. The codebase is huge, not highly documented, with a lot of different packages. The development process is complicated (it doesn't even work on Windows yet), and whenever you make a change you have to be extra careful not to break anyone. We even write tests, like &lt;strong&gt;a lot of tests&lt;/strong&gt;! It was a big shift for me, because I had always worked on projects that needed to ship fast, and tests were clearly not the priority, you fixed bugs instead. But working on a library like Angular is totally different. Millions of people depend on your code, when you make a mistake you can break applications that loose thousands or hundred of thousands of dollars because of you. The responsibility is overwhelming and that's why it is much more complicated to release new features. I also wasn't the one deciding the priorities for the framework. Any change that you want to make has to work with Google applications, and it's not like you can duplicate functionalities to make it work for everyone (who said forms and http?).&lt;/p&gt;
&lt;p&gt;Anyway it was complicated to change the way i18n worked in Angular. I learned a lot and I feel like we're going in the right direction now. I understand the choices that they made for Angular i18n, it's the most efficient and stable way to translate applications. It works very well for huge companies like Google, but it just isn't what most developers need/want.&lt;/p&gt;
&lt;p&gt;During this year, I haven't really worked on ngx-translate. The issues are pilling up, I've only merged a few PRs and some of them have been waiting there for a long time without any activity because of me. There are some long term issues that I haven't taken the time to fix (code splitting / lazy loading, testing, ICU expressions, bugs with ionic...).&lt;/p&gt;
&lt;p&gt;But before we get to that, let's quickly compare my library with the native implementation.&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Angular&lt;/h3&gt;
&lt;p&gt;In Angular, you translate your templates using an extraction tool that generates xmb or xliff files, which are well defined formats that have been battle-tested. Those files are translated using professional tools, by real translators. At the end you merge the translations at build time and get a translated bundle.&lt;/p&gt;
&lt;h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Advantages:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The translation process is well defined, it is easy to detect missing translations and you can integrate that in your plans before deploying your app (extract, send to translators, merge)&lt;/li&gt;
&lt;li&gt;It scales well, you never look directly at the files since you use a software for that, you can translate in x languages, you just need to extract once and create the translation files for each locale (which your professional tool should do for you)&lt;/li&gt;
&lt;li&gt;it's super efficient because the app is pre-translated when it bootstraps, there's no extra work to apply your translations and it works well with pre-rendering because of that&lt;/li&gt;
&lt;li&gt;since you merge the translations at build time, it means that it can support directives, components and other html elements, you can move them around in the different languages, or even remove them if needed&lt;/li&gt;
&lt;li&gt;you don't need to worry about lazy loading, your bundles are translated at build time, and that includes your lazy loaded modules&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Issues:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;it takes a lot of work to setup, you need to extract, send to translators, and then you can merge&lt;/li&gt;
&lt;li&gt;you create one app bundle / locale, which means that you cannot change the locale at runtime, you need to reload a different bundle for that. And to do that you need to handle server side routing to deliver the correct locale bundle. Google doesn't feel like it's an issue because you're not supposed to change your locale frequently. And in fact most of your users will change it maybe only once, or not at all. But it still complicates the workflow a lot.&lt;/li&gt;
&lt;li&gt;no code translations, only template are translated since that's all you can do at build time for now&lt;/li&gt;
&lt;li&gt;harder to use in development because you need to stop your dev server, extract translations, merge them. And the setup is different between JIT and AOT...&lt;/li&gt;
&lt;li&gt;you cannot translate libraries, and that's a real problem for components libraries (like material, ng bootstrap, ...)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;ngx-translate&lt;/h3&gt;
&lt;p&gt;With ngx-translate you load the module and configure it, you then load the json files containing your translations. You need to manually define keys for your translations and to write them in your json files that you will probably translate yourself, or transform into other formats that you'll send to your translators. But it's ok because json is easy to manipulate and generate.&lt;/p&gt;
&lt;h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Advantages:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;you can choose how you want to handle your translations (bundled, http-loaded, pre-cached using service workers or localstorage, etc...)&lt;/li&gt;
&lt;li&gt;you can change the locale at any time&lt;/li&gt;
&lt;li&gt;it works in your templates AND in your code&lt;/li&gt;
&lt;li&gt;json (that's all I need to say)&lt;/li&gt;
&lt;li&gt;the community can work on plugins, custom loaders, tooling, etc... everything is hackable and you should be able to make it work the way you prefer&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Issues:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;it uses bindings (via a pipe or a directive) which means that it works at runtime and you can experience some kind of FOC effect (flash of content) when the translations are loaded and applied. Also it takes some memory and some processor time when change detection is triggered&lt;/li&gt;
&lt;li&gt;if you want to split translations, it doesn't work well, the setup is complicated and there are bugs in the library&lt;/li&gt;
&lt;li&gt;json is not an official translation format, and most professional translation tool don't handle that, but you can use different loaders to support other formats (like po) so that's not a super huge issue&lt;/li&gt;
&lt;li&gt;it's hard to test&lt;/li&gt;
&lt;li&gt;if it breaks, then your app will have no text!&lt;/li&gt;
&lt;li&gt;it doesn't support angular elements (components, directives, pipes) because there's no "compile" at runtime for AOT applications&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Changes in Angular&lt;/h3&gt;
&lt;p&gt;Like I said, I've been working on Angular i18n for almost a year now. I've actually worked on a lot of other things as well, and the changes in i18n were clearly not the priority for the framework. A lot of internal changes were also necessary before we could do the changes that we wanted.&lt;/p&gt;
&lt;p&gt;I've greatly improved the documentation (i18n guide), I've created demo projects with and without the cli to help people get started. I've worked on bugs, and made a few changes, but we've not released anything major for translations.&lt;/p&gt;
&lt;p&gt;Finally for v6 the big changes are coming, translating will be done at runtime. Having access to the internals of the framework means that it will be way more efficient than what ngx-translate does. You shouldn't experience the FOC effect, and it won't take any resource during change detection. You'll be able to do code translations, at last! There will only be one bundle per application for all of the locales (or multiple, if you prefer). And libraries should be translatable.&lt;/p&gt;
&lt;p&gt;What will not change:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you'll still have to extract translations using the extraction tool and merge them at build time, which means that's it's not very easy to use in development&lt;/li&gt;
&lt;li&gt;there's no json format &lt;em&gt;yet&lt;/em&gt; (we've been discussing internally about opening the API so that developers can write their own serializers if they want)&lt;/li&gt;
&lt;li&gt;it'll still be more complicated to setup and to use than ngx-translate&lt;/li&gt;
&lt;li&gt;you can translate at runtime in your code, but the templates will be translated at bootstrap, which means that you cannot change the locale without reloading the app&lt;/li&gt;
&lt;li&gt;new features will still take a long time to be implemented, because we don't have the freedom that a library like ngx-translate has&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;So what about ngx-translate future?&lt;/h3&gt;
&lt;p&gt;This has been a long post, and we're finally getting to the part where we talk about the future of ngx-translate. The way I see it there are 2 solutions:&lt;/p&gt;
&lt;p&gt;1/ we continue like it has been for the past year, only merging a few PRs, not working on new features and not improving the workflow. I keep working on making Angular i18n better and hopefully people will stop using this library because the native solution will be better. Or maybe a real alternative will emerge (like &lt;a href="https://github.com/robisim74/angular-l10n" rel="noopener noreferrer"&gt;https://github.com/robisim74/angular-l10n&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;2/ I change the way I work and decide to spend more time on the library (at least 1 day/week) to improve it: fixing lazy loading, code splitting, adding functions to help with testing, support ICU expressions, create well documented and maintained examples, finally tackle ionic and other mobile issues, ...
I focus on making sure that the library stays a viable alternative to Angular i18n by providing solutions to the "problems" that Angular i18n will not fix. I write better tooling, maybe even an editor for the translations. I rewrite the documentation, on a real website with shiny examples.&lt;/p&gt;
&lt;p&gt;To do all of that, I would need to make this library profitable somehow. I was thinking about changing the license to require companies to pay for the library (while keeping it free for open source and personal projects) in exchange for priority support (for bugs fixing, and for working on the features that they want the most).
Obviously the current version would remain free and MIT-licensed, since there's no legal way to retroactively change a license, and it would be stupid to do that anyway. But new versions would be using this new license.&lt;/p&gt;
&lt;p&gt;This library is downloaded ~350 000 times / month on npm now, if you compare that to the ~2 400 000 downloads of &lt;code&gt;@angular/core&lt;/code&gt;, it means that my library is used in 1 out of 7 Angular projects! That's crazy, and it gives me confidence that this is viable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What do you guys think&lt;/strong&gt;? Would your companies be willing to pay for a better ngx-translate? Do you see any other alternative?&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ngx-translate/core/issues/783" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Since we can't wait for Ivy to happen, we deployed our own translation system that &lt;a href="https://github.com/vivainio/ngx-pttx/blob/master/src/tx/tx.service.ts" rel="noopener noreferrer"&gt;has barely any code&lt;/a&gt; or logic (as opposed to ngx-translate that has a bunch).&lt;/p&gt;

&lt;p&gt;As preparation, grab files &lt;a href="https://github.com/vivainio/ngx-pttx" rel="noopener noreferrer"&gt;from ngx-pttx github project&lt;/a&gt; and copy them to your project (no npm package created yet).&lt;/p&gt;

&lt;h2&gt;
  
  
  The approach
&lt;/h2&gt;

&lt;p&gt;You need to have the translations available in a hierarchical JSON structure. An example (in &lt;code&gt;en-US.json&lt;/code&gt;) would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mygroup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mykey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello my english text"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your application will download this once it knows what file to get (i.e. what language is chosen). The format may be familiar from &lt;a href="https://github.com/angular-translate/angular-translate" rel="noopener noreferrer"&gt;angular-translate&lt;/a&gt; from your wild Angular 1 years.&lt;/p&gt;

&lt;p&gt;Then, you set the strings to be available globally by injecting TxService and doing setStrings():&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;txService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TxService&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetchStringsSomehow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setStrings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&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;Now you can just use txService in various components:&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mygroup.mykey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// warning: this can crash at runtime&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mygroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mykey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In templates you can use ptTx pipe:&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;span&amp;gt;&lt;/span&gt;{{ "mygroup.mykey" | ptTx }}&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;Or ptTx directive:&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;span&lt;/span&gt; &lt;span class="na"&gt;ptTx=&lt;/span&gt;&lt;span class="s"&gt;"mygroup.mykey"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you may ask - how is that type safe? Well, it isn't. &lt;/p&gt;

&lt;p&gt;Since you want type safety (to ensure your strings keep working and to get intellisense), you need to create type definitions. We do it in a build step, with &lt;a href="https://quicktype.io/" rel="noopener noreferrer"&gt;quicktype.io&lt;/a&gt; command line application. Point it to the translation json file (one, typically english, is enough for type generation):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn quicktype &lt;span class="nt"&gt;--lang&lt;/span&gt; ts &lt;span class="nt"&gt;--no-maps&lt;/span&gt; &lt;span class="nt"&gt;--just-types&lt;/span&gt; &lt;span class="nt"&gt;--out&lt;/span&gt; gen/translations_common.ts ../../some_dir_to_translations/en-US.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can use txService.make() to create a function that checks the type and gives you the string. It takes the quicktype-generated type as type argument:&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;MyUiStrings&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./gen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;getLocalizedTexts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;make&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyUiStrings&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;someText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mygroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mykey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  That's all?
&lt;/h2&gt;

&lt;p&gt;Yeah, that's all you need to do. You need to provide a few parts by yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Figure out where to fetch the json files.&lt;/li&gt;
&lt;li&gt;call setStrings() before your app is drawing components. You can use &lt;a href="https://hackernoon.com/hook-into-angular-initialization-process-add41a6b7e" rel="noopener noreferrer"&gt;APP_INITIALIZER&lt;/a&gt; provider for this.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>RxJS and Angular, I'm not feeling it</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Tue, 02 Jul 2019 08:56:45 +0000</pubDate>
      <link>https://dev.to/vivainio/rxjs-and-angular-i-m-not-feeling-it-56og</link>
      <guid>https://dev.to/vivainio/rxjs-and-angular-i-m-not-feeling-it-56og</guid>
      <description>&lt;p&gt;I read an article by  on creating custom Closure builder for Angular, and apparently the "Architect" (yes, that's the name of the system) relies heavily on RxJS for consistent API.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/steveblue" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F69169%2Fbb0f2c9b-29dc-4faf-8470-cd85b4b3a713.jpeg" alt="steveblue"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/steveblue/build-angular-like-an-architect-part-1-3ph2" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Build Angular Like An Architect (Part 1)&lt;/h2&gt;
      &lt;h3&gt;Stephen Belovarich ・ Apr 2 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#angular&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Yet again, I'm thinking how much easier people would have it if we (Angular community) were ok to use Promises where they made sense. Here's an example snippet from the article:&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="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;concatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ngc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nf"&gt;concatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;compileMain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nf"&gt;concatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;mapTo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reportStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;success&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="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what it would look like with promises (in 'async' function):&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ngc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;compileMain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reportStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(This is just async function for handling one element from the stream, so you need a Promise.all in some top level to do the loop).&lt;/p&gt;

&lt;p&gt;It's clear that the hotshots doing RxJS day in and day out can sling those concatMaps and mergeMaps in their sleep, but for an average developer - can you take a good glance at that RxJS and tell whether it's correct or not? Is the right operator being used? If you are speculating that a bug might be in that area of the code, how fast can you read and replay the flow in your head?&lt;/p&gt;

&lt;p&gt;It is pretty clear that the wider web developer community already opted for Promises and async/await, how long does Angular community plan to go their own way?&lt;/p&gt;

&lt;p&gt;(Before you ask, yes, I know Angular itself is built on RxJS - I have three pages of that in the call stack every time I hit a breakpoint).&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Saving my stuff from Medium</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Mon, 01 Jul 2019 20:04:01 +0000</pubDate>
      <link>https://dev.to/vivainio/saving-my-stuff-from-medium-3hhm</link>
      <guid>https://dev.to/vivainio/saving-my-stuff-from-medium-3hhm</guid>
      <description>&lt;p&gt;As it appears, Medium is starting to use some Dark UX Patterns to paywall content. There have been several false alarms (accidental paywalling, "build my brand" hipsterism etc.) earlier, but it seems they are now all-in on their desperate monetization attempts.&lt;/p&gt;

&lt;p&gt;Here's what I did to secure my stuff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exported the zip file of all posts from Medium Settings UI&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copied the "posts" folder from the zip (bunch of html files) to &lt;br&gt;
&lt;a href="https://github.com/vivainio/vivainio-medium-posts"&gt;my github repo&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Converted them to markdown for easy reading on github with &lt;a href="https://github.com/gautamdhameja/medium-2-md"&gt;medium-2-md&lt;/a&gt; and npx:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx medium-2-md convertLocal html/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This emitted a bunch of markdown files in a new directory. I deleted all the blog comments (nobody wants to read those!) and pushed the files to github, for easy reading. &lt;a href="https://github.com/vivainio/vivainio-medium-posts/blob/master/md/2018-01-14_MobX-with-Angular--the-Prelude-1c0dcfb43fe6.md"&gt;Here's an example blog post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the gists (i.e. code snippets) are still missing from the markdown versions - so some scripting work remains to be done before pushing them elsewhere.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://dev.to/"&gt;dev.to&lt;/a&gt; offers a way to import content from Medium through RSS  feeds. In the spirit of dark patterns, Medium's RSS feed only has a few most recent articles &lt;a href="https://medium.com/feed/@vivainio"&gt;(example here)&lt;/a&gt; so I abandoned that path. &lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating to dev.to?
&lt;/h2&gt;

&lt;p&gt;As it appears, &lt;a href="https://dev.to"&gt;dev.to&lt;/a&gt; is fast as heck. Pages practically load before you click them, so you manage to skim more posts per minute. I'll probably push all of these posts there once the preparation work is ready. &lt;/p&gt;

&lt;p&gt;The first step though was to move everything to a public static hosting site (github). Now, Medium can go tits-up tomorrow for all I care!&lt;/p&gt;

</description>
      <category>medium</category>
      <category>meta</category>
    </item>
    <item>
      <title>Clean Code</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Mon, 10 Dec 2018 17:28:24 +0000</pubDate>
      <link>https://dev.to/vivainio/clean-code-1m3f</link>
      <guid>https://dev.to/vivainio/clean-code-1m3f</guid>
      <description>&lt;p&gt;Again, there is controversy around Robert C. Martin (known as “Uncle Bob” among his following), because of Trumpster sympathy accusations (which, even if they were proven, are not unusual for a man of his age).&lt;/p&gt;

&lt;p&gt;At times like this, it’s good to study his earlier work, “Der saubere Code” (or “Clean Code”) to gain some perspective and make it evident that these accusations are without basis. It introduces a doctrine called SOLID, outlined below:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single Responsibility Principle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Evolution of code must lie in hands of singular, animating principle, embodied by an anointed Leader.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open/Closed Principle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Libraries should be Open for Use, but the decisions within the library must be Closed, stewarded by an educated board.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Liskov substitution principle (&lt;/strong&gt;Liskovsches Substitutionsprinzip)&lt;/p&gt;

&lt;p&gt;Manages relationships between Master- and subclasses. Subclasses, while independent, must always obey the rules set by Master Class, while retaining freedom to add their own functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interface segregation principle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“&lt;/strong&gt; To each their own” — different capabilities and freedoms fall naturally to different classes of users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency inversion principle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;High level, policy-setting components should be independent of lower level components. Top tier is the unmovable, unquestioned layer that provides stability, while lower tiers go about their ways with little danger of disruption to the Whole.&lt;/p&gt;

</description>
      <category>software</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>As Spoken by a Dead Enterprise Developer by the Tree</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Mon, 26 Nov 2018 20:21:02 +0000</pubDate>
      <link>https://dev.to/vivainio/as-spoken-by-a-dead-enterprise-developer-by-the-tree-1nh2</link>
      <guid>https://dev.to/vivainio/as-spoken-by-a-dead-enterprise-developer-by-the-tree-1nh2</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aOvTknUa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALjL8YlDyyXfKG0Ilzv4VeA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aOvTknUa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALjL8YlDyyXfKG0Ilzv4VeA.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Programmer said,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Like a good shepherd gently corrects the route of a wayward lamb, the shepherd of an application steers the code towards safer paths without coercing or blaming the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; You have been told that you should use backslash in Windows as a path separator. But know that backslash is an abomination in my house and should only be used as an escape character. Let Windows software that breaks without backslash break, and let us not talk about that software anymore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Man that thinks too much looks at an idea and thinks he can do better, and spends his nights belaboring for the perfect implementation without typing in the program. But his wise neighbor implements his first idea, sees how it operates and modifies it accordingly. His neighbor is blessed with riches and respect, while the man starves and is ridiculed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; You say you should depend on interfaces and not concretions. Yet you put the interface in the same dll as the implementation, like a drunkard that soils his pants also on the outside. Know that interface is of no use if it can not be used without dragging along the implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; If you inject your dependencies, you can have different life cycles and states within those dependencies. But transient dependency is almost like a static function when you look close enough.&lt;/p&gt;

&lt;p&gt;Programmer said,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; You were told to write many unit tests. Yet the man that told you, does not write unit tests in the privacy of his own house. Words are wind, and man is judged by his deeds, not his words.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.&lt;/strong&gt; Foolish young man sees a new library and knows that his elders don’t know it. So in order to acquire wives, the young man peacocks around with his knowledge above his elders, for surely he must be wiser than them. Instead, a wise man knows that the library was written by another such lovelorn young man, again to impress other people. Young man learns this from the wise man, studies computing outside JavaScript, and earns a respectable wife and a good house in his time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8.&lt;/strong&gt; Foolish old man wants to teach the youth in his village. But they won’t listen to him because he is old and busted. Do not be that old man. Instead, be the wise old man that listens to the youth, for they get around the block more and have their own stories of war and conquest to tell. And then see what you can use and what you must discard.&lt;/p&gt;

&lt;p&gt;Programmer said,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9.&lt;/strong&gt; You were said that Object Oriented is garbage and Functional Programming is too hard. But wise men know that Object Oriented programming is not garbage when done in moderation, and Functional Programming is not hard when done in moderation. And the village idiot, writing simple procedural programs in Go, laughs at both, with belly fat from rich foods and good life.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10.&lt;/strong&gt; But yet know that Haskell is doomed to obscurity, as for obscurity it was written and in obscurity it thrives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11.&lt;/strong&gt; Text is bytes written as UTF-8. It shall not have a Byte Order Marker in the beginning, for that is an aBOMination. Let no more be said about that.&lt;/p&gt;

&lt;p&gt;Programmer said,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12.&lt;/strong&gt; Many men you respect use Rust and you aspire to the same. But you should not use Rust before they fix their editor support, for the editor support is still bad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;13.&lt;/strong&gt; Wise man looks at code searching for expressiveness and clarity. But equally wise man accepts an ugly language if the tooling is built by rich masters with fanatic drive towards quality. Beautiful program will not keep you warm in winter breeze, but fast compiler just may.&lt;/p&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>Creating a Windows Forms GUI with F#</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Sat, 14 Jul 2018 20:50:43 +0000</pubDate>
      <link>https://dev.to/vivainio/creating-a-windows-forms-gui-with-f-337m</link>
      <guid>https://dev.to/vivainio/creating-a-windows-forms-gui-with-f-337m</guid>
      <description>&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%2F431ziq8tv2biajbfqhku.jpeg" 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%2F431ziq8tv2biajbfqhku.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Windows Forms is not dead — it’s now more alive than it has been for years now that Microsoft announced they will support it in &lt;a href="https://blogs.msdn.microsoft.com/dotnet/2018/05/07/net-core-3-and-support-for-windows-desktop-applications/" rel="noopener noreferrer"&gt;.NET Core 3.0&lt;/a&gt;, and that you will be able to&lt;a href="https://docs.microsoft.com/en-us/windows/uwp/xaml-platform/xaml-host-controls" rel="noopener noreferrer"&gt;embed “modern” UWP controls&lt;/a&gt; in Forms apps.&lt;/p&gt;

&lt;p&gt;Besides not being dead, it has other things going for it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s easy to use from F#, as you’ll see from this post. WPF requires more complex adaptation work (e.g. there is a &lt;a href="https://fsprojects.github.io/FsXaml/" rel="noopener noreferrer"&gt;XAML type provider&lt;/a&gt;), while Forms is pretty much straight .NET.&lt;/li&gt;
&lt;li&gt;.NET Native (i.e. the “full” UWP stack) does not work with F# at all, and possibly never will — so it’s probably not going to be relevant to your choices.&lt;/li&gt;
&lt;li&gt;Windows Forms uses the programming pattern familiar from Qt and other UI toolkits, so you can pretty much get going in a day.&lt;/li&gt;
&lt;li&gt;It’s not a particularly good fit for “rich” or customized UI’s, but you are not writing those anyway. When you have someone paying you to do a rich UI for desktop, they are paying to do it on the Web.&lt;/li&gt;
&lt;li&gt;It’s the real Native toolkit for Windows, so the applications can be very small. An application that does something can happen in 20kB (without F# of course, F# adds ca. 3MB of weight).&lt;/li&gt;
&lt;li&gt;Windows Forms, unlike WPF or UWP, has a cross platform story and can be run in Mono under Linux/Mac.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  With F# you say?
&lt;/h4&gt;

&lt;p&gt;The problem with GUI programming with F# is that UI design tools are written for C# and VB programmers. The recommended approach has usually been to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create the GUI logic in C#, using the Forms UI Designer.&lt;/li&gt;
&lt;li&gt;Use F# to make libraries and call out to them from the GUI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The obvious problem with this is that you don’t really want to use C# more than necessary, and want to keep language context switching to the minimum — not to mention that you are limited to constructs that are well supported on C# side on the boundary.&lt;/p&gt;

&lt;p&gt;Another approach, probably only appropriate for seasoned Forms developers, is to write everything in F# without using the Designer. This is outlined at least in the (excellent) “&lt;em&gt;Expert F#&lt;/em&gt;” book, if you are curious how to do it.&lt;/p&gt;

&lt;p&gt;The alternative approach I’m proposing here is to also write all the GUI logic in F#, only dropping to the C# side when you want to move things around in the Forms Designer. Your main entry point is the F# application, which then instantiates the main form (and subsequent forms). The forms register all their UI components with a “behind” class, which then binds the event handlers and implements all that hairy GUI logic in a language that is more aesthetically pleasing (that’s F#, if you are new here).&lt;/p&gt;

&lt;p&gt;I’ll take a shortcut and use a &lt;a href="https://github.com/vivainio/scaffer-templates" rel="noopener noreferrer"&gt;Scaffer template&lt;/a&gt; to create the app skeleton:&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%2F4o4ajb4iu1axpcmn0wrd.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%2F4o4ajb4iu1axpcmn0wrd.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yikes! That was a lot of stuff. Fear, not, you only ever need to care about few of them. If you click through the files, you’ll notice that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MathManDesign is a project (DLL) written in C#. That’s the one you’ll open in VS and click around the Designer.&lt;/li&gt;
&lt;li&gt;MathManMain is the “main” application (“EXE”). It contains the entry point which bootstraps Windows Forms, instantiates the MathManForm and hooks up the “behind” class. It takes a project reference to MathManDesign project, but MathManDesign does not have any kind of reference to MathManMain. Therefore, you can go wild in using F# constructs that have usability issues when exposed to C# (e.g. DU’s). This dependency “inversion” is done by &lt;a href="https://github.com/vivainio/TrivialBehinds" rel="noopener noreferrer"&gt;TrivialBehinds&lt;/a&gt;, a micro-DI-library available in nuget.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you build and launch the application, you’ll see the minimal default functionality in action:&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%2Fyfz8qr0if9agnvzvz4ot.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%2Fyfz8qr0if9agnvzvz4ot.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(to verify the behavior, I recommend clicking the button a few times and observing how the number after “Lorem ipsum“ in the label increments on each click).&lt;/p&gt;

&lt;p&gt;It looks like this in the designer (double-click on MathManForm.cs to see the Design view):&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%2Fvp8neudv3oa665fr10e8.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%2Fvp8neudv3oa665fr10e8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And press f7 to get to the code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After editing the form in the designer, you’ll add the new controls that it created in the MathManUi class. This is the &lt;strong&gt;only&lt;/strong&gt; C# code you’ll need to keep up to date (of course it needs to be added for every Form you create). You can copy-paste the control declaration from MathManForm.Designer.cs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update:&lt;/em&gt; you can replace this boilerplate by CreateComponentBehind, if you want to expose the whole MathManForm instead of of MathManUi. In that case you need to make the controls public:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, let’s take a peek at the F# code running it all:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That’s it!&lt;/p&gt;

&lt;p&gt;The first lines of main are standard Windows Forms bootstrap code. Then we instantiate the Form and start the application. The instantiation of the form instantiates the “behind” we registered in registerBehinds() function.&lt;/p&gt;

&lt;h4&gt;
  
  
  Doing it from scratch
&lt;/h4&gt;

&lt;p&gt;Warning: stop reading if you are already bored.&lt;/p&gt;

&lt;p&gt;I “cheated” a bit by using a template — because some boring work went into getting it working. For the posterity, here’s what was needed to get that F# application off the ground:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a solution&lt;/li&gt;
&lt;li&gt;Create the F# application as “Console application” and reference Windows.Forms and System.Drawing from there.&lt;/li&gt;
&lt;li&gt;Set the application type of the F# application to WinExe (otherwise you’ll get that empty terminal when running the application)&lt;/li&gt;
&lt;li&gt;Create the Design project, in VS 2017 “new project wizard” it’s “Windows Forms Control Library (.NET Framework)”.&lt;/li&gt;
&lt;li&gt;The .NET Framework to use should be .NET Framework 4.7.2, because &lt;a href="https://docs.microsoft.com/en-us/dotnet/framework/winforms/high-dpi-support-in-windows-forms" rel="noopener noreferrer"&gt;font rendering will be fuzzy on Windows 10&lt;/a&gt; on 4.6 series and older.&lt;/li&gt;
&lt;li&gt;In order to fix font rendering, I had to modify App.config (check the link above), and create a manifest in the F# application. To do that, I just did “Add manifest” on the Design project and copied it over to F# application side.&lt;/li&gt;
&lt;li&gt;Since you’ll have multiple projects, it’s good idea to migrate to Paket.&lt;/li&gt;
&lt;li&gt;Add a nuget dependency to TrivialBehinds to both projects. You can probably get similar behavior with “actual” DI libraries (get class X that supports handling data package Y), but I couldn’t be bothered to add one of those heavy injectors here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skeleton code is at &lt;a href="https://github.com/vivainio/FSharpFormsSkeleton" rel="noopener noreferrer"&gt;https://github.com/vivainio/FSharpFormsSkeleton&lt;/a&gt; — I’ll probably keep it up to date and modify the template if/when needs arise. If you are using that instead of Scaffer, you need to do some IDE legwork to rename those classes.&lt;/p&gt;

</description>
      <category>windowsforms</category>
      <category>microsoft</category>
      <category>fsharp</category>
    </item>
    <item>
      <title>14 (fourteen) habits of Okay Programmers</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Tue, 12 Jun 2018 19:03:29 +0000</pubDate>
      <link>https://dev.to/vivainio/14-fourteen-habits-of-okay-programmers-3hm7</link>
      <guid>https://dev.to/vivainio/14-fourteen-habits-of-okay-programmers-3hm7</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--00krSjTk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/900/1%2A4XemvUaTPkKwQ48PfaJAng.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--00krSjTk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/900/1%2A4XemvUaTPkKwQ48PfaJAng.jpeg" alt=""&gt;&lt;/a&gt;Mastery is Grind&lt;/p&gt;

&lt;p&gt;Setting the stage: you are a fresh mind entering the field. You don’t want to suffer from imposter syndrome or bear the dreaded mark of a “pleb”, but are confused on how to navigate the bewildering array of chaotic undercurrents in Real Programmer subculture. By practicing these simple steps you can ride that tiger all for all it’s worth.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Master the command line. You will be running lots of scripts and launch stuff from there, so why not get fluent at it?&lt;/li&gt;
&lt;li&gt;Never have spaces in file or directory names, or anywhere else for that matter. If you get caught using one, you will be assumed to be “GUI-clicker” and beyond all repair. If your code is under a directory with a space in the name (or two in some extreme scenarios, I kid you not), it’s assumed to be garbage regardless of whether it was written by John Carmack himself.&lt;/li&gt;
&lt;li&gt;Learn to think in types. If you are only doing dynamic programming languages at work, use a typed one at home. If you can’t think in types, your skills are assumed to be lacking regardless of your proven productivity or success in private life.&lt;/li&gt;
&lt;li&gt;Learn a &lt;strong&gt;typed functional programming language&lt;/strong&gt; (OCaml, F#, Scala, ReasonML, Haskell…). No matter how bad a programmer you really are, or however “unpopular” programming language (PHP, ES5, Java, …) you are forced to crank out at your day job , you are assumed to be on the top tier if you can comfortably sling one of these. Using Clojure or Elixir doesn’t count because1) these don’t have types and 2) they are perceived as “trend hopper” targets for the now-disbanded Ruby tribe. If you can be productive in Idris or other dependently typed language, you are assumed to be a Programming God despite never having closed a ticket you were supposed to work on. &lt;strong&gt;Extra caution&lt;/strong&gt; : using Haskell may be perceived as “trying too hard”.&lt;/li&gt;
&lt;li&gt;Only drink on Fridays. This ensures you have regained your mental acuity and creativity by Monday lunch time or Tuesday morning (depends on your age and stamina).&lt;/li&gt;
&lt;li&gt;Solve as many problems as you can. If you don’t encounter interesting problems in your current tasks, help other people solve their problems or create side projects where you can practice solving new interesting problems.&lt;/li&gt;
&lt;li&gt;Code as much as you feel like. 8 hour workday can only fit certain amount of coding, and you can certainly be “good enough” for your employer if you stick to that. But if you code more, you will be better. Programming is practice, practice, practice. People will routinely tell you otherwise, but parents also tend to compliment the singing of their children.&lt;/li&gt;
&lt;li&gt;If you have to draw pictures to understand something, draw them on pencil-and-paper. Git is where your work output should go. Like the sound of tree falling in the forest without anyone listening, work that didn’t end up in Git will be perceived as work that didn’t happen. &lt;strong&gt;Exception&lt;/strong&gt; : if you helped someone land something in Git, you can rationalize having sort of kind of done useful work (maybe).&lt;/li&gt;
&lt;li&gt;If you are male, try growing a beard if you can. You don’t have to wear it at all times, but at least ensure there is a verified scenario where you, in fact, were seen as having sufficient amounts of beard. If you are a woman, moderation is advised regardless of whether you can grow one or not.&lt;/li&gt;
&lt;li&gt;Do not use shell scripting languages (bash or .bat/.cmd files, or Powerhell) if you have more than 2 lines of “code”. Use Python (or Ruby if you must) instead. If someone doesn’t have Python installed, he’s not worthy of running your scripted masterpiece anyway.&lt;/li&gt;
&lt;li&gt;Have hobbies outside programming. At least read a book or play some video games sometimes for chrissake.&lt;/li&gt;
&lt;li&gt;Acquire a good arsenal of so called “thought leaders” you follow in Twitter. They should mostly consist of battle-hardened veterans aged 35 or above. The younger ones will lead you down the swamp of Node and other subcultures that are not perceived to be sufficiently programmer-y. On the other hand be wary of exceedingly old thought leaders that are perceived to be out of style (like “Uncle Bob”, or SOLID patterns in general).&lt;/li&gt;
&lt;li&gt;Follow programming news. On Reddit, &lt;a href="https://old.reddit.com/r/programming/"&gt;/r/programming&lt;/a&gt; and &lt;a href="https://old.reddit.com/r/programmingcirclejerk/"&gt;/r/programmingcirclejerk&lt;/a&gt; provide affordable value at good regularity. HackerNews (also known as the “orange website” because the maintainers &lt;a href="https://news.ycombinator.com/"&gt;can’t do CSS&lt;/a&gt;) has a small cult following, but 1) you can’t get “just programming news” from there and 2) the community (a.k.a “&lt;a href="http://n-gate.com/"&gt;webshits&lt;/a&gt;”) overall is annoying and verbose, and reading too much of their output can lead to reduction of social skills, such as they are.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“It’s nice to be important but it’s more important to be nice”&lt;/strong&gt; , to paraphrase a &lt;a href="https://en.wikipedia.org/wiki/H.P._Baxxter"&gt;German philosopher&lt;/a&gt;. If you are an Okay Programmer but arrogant or mean, you will be like that clunky old cog in a machine that just gets to stay there because yanking it out would require disassembling too much other stuff.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your mileage may vary, and this blog post should not be treated as Gospel. For one, it was written by single author (as opposed to Gospels, of which there are four at the time of writing this).&lt;/p&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>MobX with Angular, Part 2: Patterns, Perks and Gotchas</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Mon, 30 Apr 2018 20:07:13 +0000</pubDate>
      <link>https://dev.to/vivainio/mobx-with-angular-part-2-patterns-perks-and-gotchas-5a5d</link>
      <guid>https://dev.to/vivainio/mobx-with-angular-part-2-patterns-perks-and-gotchas-5a5d</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fac5cc7amilpfpbbcnyxy.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fac5cc7amilpfpbbcnyxy.jpeg" width="760" height="1111"&gt;&lt;/a&gt;State management shouldn’t be rocket science&lt;/p&gt;

&lt;p&gt;This is the second installation of the critically acclaimed “MobX with Angular” series. If you came here googling for “ngrx alternatives sweet jesus make it stop”, you are in the right place. You probably want to read &lt;a href="https://dev.to/vivainio/mobx-with-angular-the-prelude-4hkk-temp-slug-2813414"&gt;part 1&lt;/a&gt; for the basics (or any generic React-oriented MobX tutorial if you don’t particularly like my writing).&lt;/p&gt;

&lt;p&gt;On to the non-basics. We are creating a big Angular application with a largish, geographically distributed team at &lt;a href="https://www.basware.com/" rel="noopener noreferrer"&gt;Basware&lt;/a&gt;, and have established this as a pretty workable design (for the purposes of discussion I’m using the classical Blog Post feature as the example):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The single source of truth is the Store, &lt;em&gt;posts.store.ts&lt;/em&gt; (class &lt;em&gt;PostsStore&lt;/em&gt;). It contains the &lt;a class="mentioned-user" href="https://dev.to/observable"&gt;@observable&lt;/a&gt; properties, and all the @action’s that modify the state.&lt;/li&gt;
&lt;li&gt;There are many Stores. You could have &lt;em&gt;AuthorsStore&lt;/em&gt;, &lt;em&gt;SettingsStore&lt;/em&gt; etc.&lt;/li&gt;
&lt;li&gt;Components don’t access (i.e. inject) the Store directly. Instead, they use a facade called &lt;em&gt;PostsService&lt;/em&gt;, in &lt;em&gt;posts.service.ts&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Http requests are done by &lt;em&gt;PostsApiService&lt;/em&gt;, in &lt;em&gt;posts.api.ts&lt;/em&gt;. This is the only place that knows what url’s are used. This is also a good place to put a breakpoint when wondering why on earth that one request was sent three times.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The Facade
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;PostsService&lt;/em&gt; is responsible for exposing parts of the Store to the components. That is, it’s what your &lt;em&gt;post-reader.component.ts&lt;/em&gt; injects to do stuff.&lt;/p&gt;

&lt;p&gt;If there is asynchronous http work to do, &lt;em&gt;PostsService&lt;/em&gt; calls to &lt;em&gt;posts.api.ts&lt;/em&gt; service (&lt;em&gt;PostsApiService&lt;/em&gt;) that sends the request. &lt;em&gt;PostsService&lt;/em&gt; then captures the response and updates the state accordingly (usually calling an action in Store). Here’s an example flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User clicks a post. Component calls &lt;em&gt;postsService.documentChanged(id)&lt;/em&gt; which is a hint that we want the data for that document.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;PostService&lt;/em&gt; notices that we don’t have that document in store. It triggers the fetch knowing it’s needed soon.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;PostsReaderComponent&lt;/em&gt; is observing &lt;em&gt;postService.getPost(id)&lt;/em&gt;. It keeps returning &lt;em&gt;undefined&lt;/em&gt; (or &lt;em&gt;null&lt;/em&gt; if you are so inclined) for now. A busy spinner is spinning.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;PostService&lt;/em&gt; finally receives the post content. It calls the action &lt;em&gt;store.setPost(id, { content: “blah blah”})&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;The observer of &lt;em&gt;getPost(id)&lt;/em&gt; is woken up now that the data changed, and it can place the content in a component instance variable. This dismisses the spinner and reveals the glorious post content.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It’s worth mentioning that MobX itself has support for async workflows, through &lt;a href="https://mobx.js.org/best/actions.html" rel="noopener noreferrer"&gt;async actions and flow()&lt;/a&gt;. We are not using those because&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we want to stick with relatively tried-and-true async patterns familiar from AngularJS 1.x days&lt;/li&gt;
&lt;li&gt;generators don’t work great (read: hardly at all) with current crop of debuggers and source maps&lt;/li&gt;
&lt;li&gt;async is not exactly rocket science. Every action on the store is a dumb, instant “commit”.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  createTransformer()
&lt;/h4&gt;

&lt;p&gt;You noticed the &lt;em&gt;postService.getPost(id)&lt;/em&gt; above. It will probably look for the content in an observable &lt;em&gt;Map&lt;/em&gt;. You can call it in autorun body just fine, but there is actually a better and faster way.&lt;/p&gt;

&lt;p&gt;Usually, MobX recommends doing most calculations in &lt;em&gt;@computed&lt;/em&gt; properties instead of complex &lt;em&gt;autorun&lt;/em&gt; bodies when you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s faster. When a computed property is observed, it is “hot”. That is, when the data or other computed properties are modified, the computed values are pushed out and memoized. Just calling the computed property will get you the memoized value. If there are many components observing the same data in autoruns, they will be recalculated every time the data changes. With computed properties, the calculation is run only once. This means you can safely call them without worrying about performance under the hood.&lt;/li&gt;
&lt;li&gt;They are a cleaner programming pattern. When you see something is computed, you know it’s just a pure projection of underlying state. And, you know you should be observing that state in the top level autorun() somewhere. Non-computed things could be doing anything else. You’ll probably implement your state by having a whole tree of projections refining and improving the state to fit your particular consumption needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that I convinced you of their merits, here comes the Gotcha 1: &lt;strong&gt;you can’t pass arguments to computed functions&lt;/strong&gt;. They are just getters with no arguments. You could just have “&lt;em&gt;currentPostId&lt;/em&gt;” in store, and give data for that current post in the computed getters. But, this won’t work if you have multiple posts being observed at the same time (say, you have a two pane post reader showing different posts at the same time).&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://mobx.js.org/refguide/create-transformer.html" rel="noopener noreferrer"&gt;createTransformer() in mobx-utils&lt;/a&gt;steps in (if you understood none of the official description, read on). Here we create a &lt;em&gt;getPostAndAuthorData&lt;/em&gt; (in &lt;em&gt;PostsService&lt;/em&gt; class body) that reads stuff from two different transformers (projections):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The call to &lt;em&gt;getPostAndAuthorData&lt;/em&gt;() discovers the internal computation by looking it up by the &lt;em&gt;postId&lt;/em&gt;. You can only pass one primitive argument to the transformation, but I know that you, Dear Reader, will usually be using a string &lt;em&gt;documentId&lt;/em&gt; or somesuch. If you would need something more complex, eat it up and use &lt;em&gt;autorun&lt;/em&gt;() instead.&lt;/p&gt;

&lt;h4&gt;
  
  
  Component code
&lt;/h4&gt;

&lt;p&gt;In the end, you’ve got to be observing the data in autorun, otherwise it’ll all be for naught. For our application, we have made a utility to&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a list of autoruns.&lt;/li&gt;
&lt;li&gt;Dispose them in ngOnDestroy().&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It’s used like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The strings in there are names of the observables, so &lt;a href="https://chrome.google.com/webstore/detail/mobx-developer-tools/pfgnfdagidkfgccljigdamigbcnndkod?hl=en" rel="noopener noreferrer"&gt;mobx-devtools&lt;/a&gt; Chrome plugin (that also works with Angular) shows them nicely. You can grab the utilities (&lt;em&gt;startObservers&lt;/em&gt;, &lt;em&gt;addComponentDisposer&lt;/em&gt; and &lt;em&gt;stopObserving&lt;/em&gt;) from &lt;a href="https://github.com/vivainio/angularpack/blob/master/src/mobtool.ts" rel="noopener noreferrer"&gt;Github&lt;/a&gt;. The first argument to &lt;em&gt;startObservers&lt;/em&gt;() is optional; if you pass the component &lt;em&gt;ChangeDetectorRef&lt;/em&gt; there, triggering any of the listed observers will also run change detection on that component. This is usually needed for OnPush components.&lt;/p&gt;

&lt;p&gt;Why not shove everything in one autorun? The basic idea is to segregate them so that only the part that depends on a particular change is run when needed.&lt;/p&gt;

&lt;p&gt;Natural place to “start observing” is &lt;em&gt;ngOnInit&lt;/em&gt;(), since that is only run once per component, and the components input attributes have settled by the time it runs. You can delay the initialization of observables by MobX &lt;em&gt;when()&lt;/em&gt; function that retuns a promise that resolves when the observed expression returns true:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  There is no such thing as free lunch
&lt;/h4&gt;

&lt;p&gt;With all this magic and rainbows, there’s got to be a price to pay, right? Well, there is, and sooner you know the better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decorators like &lt;a class="mentioned-user" href="https://dev.to/observable"&gt;@observable&lt;/a&gt; and @computed can’t currently (as of Angular 5) be used in components because AoT compiler chokes up on them. &lt;em&gt;createTransformer&lt;/em&gt;(), on the other hand, can be used, and can be handy for some marginal refinement you want to do at the edges. MobX 4 provides an alternative syntax using &lt;em&gt;declare(),&lt;/em&gt; which won’t trigger this problem.&lt;/li&gt;
&lt;li&gt;The observable data in stores is injected with MobX specific metadata, and the attributes of objects are transformed to getters/setters. This means you need to click individual properties in the debugger to investigate them.&lt;/li&gt;
&lt;li&gt;Observable arrays look bad in the debugger. You will see hundreds of items per array, and need to click through the items to even see the length. Upcoming MobX 5 will fix this (by using ES6 proxies).&lt;/li&gt;
&lt;li&gt;Some JavaScript libraries can when fail dealing with observable data structures. E.g. lodash &lt;em&gt;_.flatMap&lt;/em&gt; (which is lodash version of &lt;em&gt;smooshMap()&lt;/em&gt;) just fails to deliver with an observable array. To be fair, that’s the only bad lodash function that I know of, so no need to throw out lodash quite yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last three problems above can be avoided by using toJS() in your computeds/transformers/autoruns — so you won’t see the guts of observable data structures at the edges. You can also log stuff to console through toJS():&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;All that being said, the debugger experience with MobX is very good. If you set a breakpoint in autorun or computed property, you see precisely what triggered the change from the call stack — and the call stack fits on the screen, as opposed to anything involving RxJS observables.&lt;/p&gt;

&lt;h4&gt;
  
  
  Should you still be using RxJS?
&lt;/h4&gt;

&lt;p&gt;A good rule of thumb is: not as much as you did.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For dumb components that don’t want to take dependency to any kind of store, pass immutable objects as inputs, and reassign the value to trigger component update (for OnPush components).&lt;/li&gt;
&lt;li&gt;Sometimes you have scenarios where component needs notification for events (as opposed to changing state as pure function of data in store — something you should do most of the time). Creating a &lt;em&gt;BehaviorSubject&lt;/em&gt; in a service provided at component level is fine for that. The alternative of passing &lt;em&gt;@Output&lt;/em&gt; events through every level can get cumbersome. Real life example: we are broadcasting events from ag-grid through a &lt;em&gt;BehaviorSubject&lt;/em&gt; for the components above.&lt;/li&gt;
&lt;li&gt;Methods in your http api services (e.g. &lt;em&gt;PostsApiService&lt;/em&gt;) usually start the &lt;em&gt;HttpClient&lt;/em&gt; observable and &lt;em&gt;map()&lt;/em&gt; it a bit to mungle the data. If the logic gets complex enough to not be readily readable using RxJS (e.g. once you go beyond trivial &lt;em&gt;map()&lt;/em&gt;), you shouldn’t be shy to run &lt;em&gt;.toPromise()&lt;/em&gt; on the observable and use async/await. Your pull request reviewers will thank you for it.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>mobx</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>MobX with Angular: the Prelude</title>
      <dc:creator>Ville M. Vainio</dc:creator>
      <pubDate>Sun, 14 Jan 2018 19:37:26 +0000</pubDate>
      <link>https://dev.to/vivainio/mobx-with-angular-the-prelude-1bp3</link>
      <guid>https://dev.to/vivainio/mobx-with-angular-the-prelude-1bp3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mvv7s9rvgqtmj3sybms.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mvv7s9rvgqtmj3sybms.jpeg" width="736" height="310"&gt;&lt;/a&gt;Conan experimenting with NGRX&lt;/p&gt;

&lt;p&gt;This is Part 1 of the in-progress article series. &lt;a href="https://medium.com/@vivainio/mobx-with-angular-part-2-patterns-perks-and-gotchas-37e2a393e0eb" rel="noopener noreferrer"&gt;Part 2&lt;/a&gt; with more advanced concepts is also available.&lt;/p&gt;

&lt;p&gt;I hit a degree of analysis paralysis on writing an “all in one” blog post about using MobX on Angular (2+) at Basware, but it ended up being a bit heavy reading. Instead of that I’m doing a series of shorter, hopefully harder-hitting posts. (&lt;em&gt;Narrator: this one ended up being neither short, nor hard-hitting&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;Aim is not to teach you MobX, but rather to generate some appetite for the productivity wins you can reach with it — and maybe help you debug some of your personal misconceptions faster (I also had some in the beginning).&lt;/p&gt;

&lt;h4&gt;
  
  
  The Store
&lt;/h4&gt;

&lt;p&gt;MobX is not really built around “Stores”. You can have your state spread over however widely you want (e.g. dozens of different Angular services or ES6 classes if you are so inclined). Simple state is always easier to track, but there is no need to cargo cult a single God-object to hold everything. The mechanics of MobX will work regardless of how you split your state.&lt;/p&gt;

&lt;h4&gt;
  
  
  Observables
&lt;/h4&gt;

&lt;p&gt;There is probably a small subset of state that actually needs to change. These are marked by &lt;a class="mentioned-user" href="https://dev.to/observable"&gt;@observable&lt;/a&gt; decorator, and they are usually primitives, arrays, objects and ES6 Maps. Note that, for better or worse, you must use ES6 Maps instead of objects to represent dictionaries (as MobX can’t detect keys being added to objects). “Changing the state” means writing to these fields (mutating, reassigning, whatever).&lt;/p&gt;

&lt;h4&gt;
  
  
  Computed properties
&lt;/h4&gt;

&lt;p&gt;@computed decorator marks an ES6 property getter that uses some of the observables defined above to calculate derivable parts of the state. If you have observable’s called “foo”, “bar” and “baz”, you can use computed properties to produce e.g. { foo, bar } object if both are defined, or null otherwise. You need that new unique object to trigger OnPush change detection, among other things. If “baz” property changed, your computed property comfortably sits as the old value, without unwanted triggers of OnPush change detection.&lt;/p&gt;

&lt;h4&gt;
  
  
  Autorun
&lt;/h4&gt;

&lt;p&gt;This is where the actual magic happens.&lt;/p&gt;

&lt;p&gt;Autorun is a function that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You probably have in your &lt;em&gt;ngOnInit&lt;/em&gt;(). Class constructor is too early (e.g. Angular ChangeDetectorRef is not available there).&lt;/li&gt;
&lt;li&gt;Is run once in the beginning. MobX records what properties (observable’s and computed’s) from MobX stores it accesses, and remembers its dependencies.&lt;/li&gt;
&lt;li&gt;Is run again when any of your dependencies change.&lt;/li&gt;
&lt;li&gt;Remains “hot” until you unsubscribe from it. autorun() returns a callable disposer that you will call in your &lt;em&gt;ngOnDestroy&lt;/em&gt; for the component.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What’s in your autorun() in a typical Angular application? You can have code that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copies values from store to your local component variables that are used from the template.&lt;/li&gt;
&lt;li&gt;Runs patchValue() on a Reactive Form within the component.&lt;/li&gt;
&lt;li&gt;Does some last minute tuneups for the data to make it easier to access from the template.&lt;/li&gt;
&lt;li&gt;Calls ChangeDetectorRef.detectChanges() to force Angular to check changes in case you are within a ChangeDetectionStrategy.OnPush component (and didn’t trigger any Input to change).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single component can have many autorun() blocks. The smaller and more granular the blocks, the more specific you can be about how often they fire.&lt;/p&gt;

&lt;p&gt;Autoruns are not limited to components though! Services can have their own autorun’s observing the state, possibly initiating HTTP requests when interesting data is available in stores, and commit interesting responses back to the stores when they return.&lt;/p&gt;

&lt;h4&gt;
  
  
  Don’t you need a new library for this?
&lt;/h4&gt;

&lt;p&gt;Not really. Core MobX works fine with Angular, with the scheme mentioned above.&lt;/p&gt;

&lt;p&gt;We have a few convenience functions to help with disposing autoruns, like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You call startObserving(this, () =&amp;gt; …) in &lt;em&gt;ngOnInit&lt;/em&gt;(), and stopObserving(this) in &lt;em&gt;ngOnDestroy&lt;/em&gt;. There will be a new blog post with some more productized helpers later on.&lt;/p&gt;

&lt;p&gt;There is also &lt;a href="https://github.com/mobxjs/mobx-angular" rel="noopener noreferrer"&gt;https://github.com/mobxjs/mobx-angular&lt;/a&gt; project that detaches a component completely from normal Angular change detection. It can work for your needs, but I posit that you may not need it, and operating directly with the (already simple) core MobX API can help when debugging problems in your own logic (e.g. “why did this not change? I better set a breakpoint in my autorun!”)&lt;/p&gt;

&lt;h4&gt;
  
  
  How about Rx Observables?
&lt;/h4&gt;

&lt;p&gt;We started out by piping stuff from MobX as Rx observables to our components, as described here: &lt;a href="https://netbasal.com/managing-state-in-angular-with-mobx-51191803e14f" rel="noopener noreferrer"&gt;https://netbasal.com/managing-state-in-angular-with-mobx-51191803e14f&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Still, I was left wondering “y tho”. If you are just using autorun(), you avoid that unnecessary wrapper, and remove need to use async pipes. You just assign new immutable references (that you got from @computed getters or autoruns) to your component variables and their change detectors kick in.&lt;/p&gt;

&lt;p&gt;MobX itself, despite its simplicity and ease of use, is a sophisticated reactive system on its own right. It just gives you the same power you get with Rx with a cheaper price tag (no need to do combineLatest(), switchMap() etc. to express a fundamentally simple computation).&lt;/p&gt;

&lt;h4&gt;
  
  
  How about NGRX?
&lt;/h4&gt;

&lt;p&gt;Bright eyed and bushy tailed, we started out with NGRX; it has a very good industry buy-in, is based on React community darling Redux, and is being pushed by a cadre of Angular community hotshots. So it’s going to be the default conservative choice, right? Right?&lt;/p&gt;

&lt;p&gt;It was a traumatizing experience for me personally. There was &lt;strong&gt;one directory with 5 files&lt;/strong&gt; to represent something that was 5 lines with MobX — basically an array.&lt;/p&gt;

&lt;p&gt;I wanted to give it a week to sink in, but I think I managed 2 days of zero productivity before calling off the experiment. Now, I have done some horrible things in my past (Symbian C++, raw GObject macro programming, 4GL’s, Perl…), but it’s 2018, I’m not getting any younger, and frontend development should be a bit fun and playful — experimenting with different state schemas and so on should be natural, energizing part of the work.&lt;/p&gt;

&lt;h4&gt;
  
  
  Call to action
&lt;/h4&gt;

&lt;p&gt;So a degree of “Question authority” is in order here. If we see MobX as the better mousetrap for Angular, we should drive that point more consistently. We should start writing developer tools that illustrate the data flow on the screen. Barring everything else, we can at least make some noise in the blogs.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>mobx</category>
      <category>javascript</category>
      <category>reactiveprogramming</category>
    </item>
  </channel>
</rss>
