go-jamming/mocks/samplerss.xml

17710 lines
1.6 MiB
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Brain Baking</title>
<link>https://brainbaking.com/</link>
<description>Recent content on Brain Baking</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<managingEditor>Wouter Groeneveld</managingEditor>
<webMaster>Wouter Groeneveld</webMaster>
<lastBuildDate>Tue, 16 Mar 2021 17:07:14 +0000</lastBuildDate>
<atom:link href="https://brainbaking.com/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>@celia @kev I have read both you and Kev&#39;s post on...</title>
<link>https://brainbaking.com/notes/2021/03/16h17m07s14/</link>
<comments>https://brainbaking.com/notes/2021/03/16h17m07s14/#commento</comments>
<pubDate>Tue, 16 Mar 2021 17:07:14 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/16h17m07s14/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A5GVjIHI6MH82H6iLQ" href="https://fosstodon.org/@celia" rel="ugc">@<span>celia</span></a></span> <span class="h-card"><a class="u-url mention" data-user="A54b8g0RBaIgjzczMu" href="https://fosstodon.org/@kev" rel="ugc">@<span>kev</span></a></span> I have read both you and Kev&rsquo;s post on this and agree on some points indeed! But I&rsquo;m not yet ready to give up webmentions. As an academic, the idea of citing/mentioning each other is very alluring 🤓. Plus, I needed an excuse to fiddle some more with JS&hellip; <br><br>As much as I loved using Wordpress before, I can&rsquo;t imagine going back to writing stuff in there instead of in markdown. Gotta keep the workflow short, though. Hope it helps you focus on what matters - content!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 16 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@robert @kev @celia I run an instance-of-one Plero...</title>
<link>https://brainbaking.com/notes/2021/03/16h12m38s27/</link>
<comments>https://brainbaking.com/notes/2021/03/16h12m38s27/#commento</comments>
<pubDate>Tue, 16 Mar 2021 12:38:27 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/16h12m38s27/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A5B4KIqbB6t20egJhQ" href="https://social.winter.ink/@robert" rel="ugc">@<span>robert</span></a></span> <span class="h-card"><a class="u-url mention" data-user="A54b8g0RBaIgjzczMu" href="https://fosstodon.org/@kev" rel="ugc">@<span>kev</span></a></span> <span class="h-card"><a class="u-url mention" data-user="A5GVjIHI6MH82H6iLQ" href="https://fosstodon.org/@celia" rel="ugc">@<span>celia</span></a></span> I run an instance-of-one Pleroma server and ps tells me it&rsquo;s using 8% of the 2GB RAM (postgres takes up even less). Also happy with the clean Soapbox UI. If you&rsquo;re already hiring a VPS, I see no reason to pay for <a href="http://masto.host" rel="ugc">masto.host</a>.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 16 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>So, we rewrote our CS courses in Markdown. I&#39;m loo...</title>
<link>https://brainbaking.com/notes/2021/03/15h14m43s49/</link>
<comments>https://brainbaking.com/notes/2021/03/15h14m43s49/#commento</comments>
<pubDate>Mon, 15 Mar 2021 14:43:49 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/15h14m43s49/</guid>
<description>
<![CDATA[
<p>So, we rewrote our CS courses in Markdown. I&rsquo;m looking for ways to make things more <strong>interactive</strong> for students, e.g. by embedding <a href="http://replit.com" rel="ugc">replit.com</a> snippets. However, I dont&rsquo;t want to create 34235 repls for every snippet, and a single backed repository is not supported. Any ideas? Jupyter notebooks are out of the question, and sadly, so is <a href="http://codepen.io" rel="ugc">codepen.io</a> or jsfiddle: I need Java and C compile support. It should be something <em>simple</em> - snippets are mostly single-page, small things. E.g. <a href="https://kuleuven-diepenbeek.github.io/osc-course/ch1-c/intro/" rel="ugc"><a href="https://kuleuven-diepenbeek.github.io/osc-course/ch1-c/intro/">https://kuleuven-diepenbeek.github.io/osc-course/ch1-c/intro/</a></a></p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 15 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>Enjoyed an afternoon of oldskool Diablo II on the ...</title>
<link>https://brainbaking.com/notes/2021/03/14h17m41s53/</link>
<comments>https://brainbaking.com/notes/2021/03/14h17m41s53/#commento</comments>
<pubDate>Sun, 14 Mar 2021 17:41:53 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/14h17m41s53/</guid>
<description>
<![CDATA[
<p>Enjoyed an afternoon of oldskool Diablo II on the Europebattle servers. We did a few Mephisto runs, managed to hit Hell, and I re-converetd my druid into a windy one. Good times!</p>
<div class="flex">
<div>
<a class="lbox" href="https://chat.brainbaking.com/media/6f8b72ca-9bfb-460b-9609-c4298a8cab2b/EuropeBattle%202021-03-14%2016-20-36-87.jpg">
<img loading="lazy" src="https://chat.brainbaking.com/media/6f8b72ca-9bfb-460b-9609-c4298a8cab2b/EuropeBattle%202021-03-14%2016-20-36-87.jpg" alt="Enclosed Toot image">
</a>
</div>
<div>
<a class="lbox" href="https://chat.brainbaking.com/media/3dbcb044-2acc-4ace-a4f6-37ce94c3f2b1/EuropeBattle%202021-03-14%2015-35-01-56.jpg">
<img loading="lazy" src="https://chat.brainbaking.com/media/3dbcb044-2acc-4ace-a4f6-37ce94c3f2b1/EuropeBattle%202021-03-14%2015-35-01-56.jpg" alt="Enclosed Toot image">
</a>
</div>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 14 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@rsolva whoops overlooked the word &#39;native&#39;.Well, ...</title>
<link>https://brainbaking.com/notes/2021/03/13h12m44s29/</link>
<comments>https://brainbaking.com/notes/2021/03/13h12m44s29/#commento</comments>
<pubDate>Sat, 13 Mar 2021 12:44:29 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/13h12m44s29/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A58ShiR61N9xSQZPDk" href="https://mastodon.social/@rsolva" rel="ugc">@<span>rsolva</span></a></span> whoops overlooked the word &lsquo;native&rsquo;.Well, all I can say is: it works!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 13 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@rsolva that&#39;s a lie indeed 😁 see https://brainba...</title>
<link>https://brainbaking.com/notes/2021/03/13h09m58s25/</link>
<comments>https://brainbaking.com/notes/2021/03/13h09m58s25/#commento</comments>
<pubDate>Sat, 13 Mar 2021 09:58:25 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/13h09m58s25/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A58ShiR61N9xSQZPDk" href="https://mastodon.social/@rsolva" rel="ugc">@<span>rsolva</span></a></span> that&rsquo;s a lie indeed 😁 see <a href="https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/" rel="ugc"><a href="https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/">https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/</a></a> I use davx5 and it works flawlessly</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 13 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@rsolva @aral @laura Great incentive Ruben, I chim...</title>
<link>https://brainbaking.com/notes/2021/03/12h19m17s26/</link>
<comments>https://brainbaking.com/notes/2021/03/12h19m17s26/#commento</comments>
<pubDate>Fri, 12 Mar 2021 19:17:26 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/12h19m17s26/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A58ShiR61N9xSQZPDk" href="https://mastodon.social/@rsolva" rel="ugc">@<span>rsolva</span></a></span> <span class="h-card"><a class="u-url mention" data-user="A58ShkZg4RDE5cbHsG" href="https://mastodon.ar.al/@aral" rel="ugc">@<span>aral</span></a></span> <span class="h-card"><a class="u-url mention" data-user="A54UboCD7EY4rO4wgi" href="https://mastodon.laurakalbag.com/@laura" rel="ugc">@<span>laura</span></a></span> Great incentive Ruben, I chimed in and also became a backer! Loving what you guys do. Hopefully the latest video will be online shortly, I missed the live stream.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 12 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>Great, I can ditch lazysizes.js! Didn&#39;t know about...</title>
<link>https://brainbaking.com/notes/2021/03/12h18m06s14/</link>
<comments>https://brainbaking.com/notes/2021/03/12h18m06s14/#commento</comments>
<pubDate>Fri, 12 Mar 2021 18:06:14 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/12h18m06s14/</guid>
<description>
<![CDATA[
<p>Great, I can ditch lazysizes.js! Didn&rsquo;t know about this before: <a href="https://web.dev/browser-level-image-lazy-loading/" rel="ugc"><a href="https://web.dev/browser-level-image-lazy-loading/">https://web.dev/browser-level-image-lazy-loading/</a></a> and browser support is &ldquo;good enough&rdquo;: <a href="https://caniuse.com/loading-lazy-attr" rel="ugc"><a href="https://caniuse.com/loading-lazy-attr">https://caniuse.com/loading-lazy-attr</a></a></p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 12 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>Always have a Diaster Recovery Plan</title>
<link>https://brainbaking.com/post/2021/03/always-have-a-disaster-recovery-plan/</link>
<comments>https://brainbaking.com/post/2021/03/always-have-a-disaster-recovery-plan/#commento</comments>
<pubDate>Thu, 11 Mar 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/03/always-have-a-disaster-recovery-plan/</guid>
<category domain="https://brainbaking.com/tags/vps">vps</category>
<description>
<![CDATA[
<p>A relatively quiet Wednesday morning. I wrote a few JS files, fiddled a bit more with my attempts to get <a href="/post/2021/03/the-indieweb-mixed-bag/">Webmentions working</a>. Timeouts appeared. Huh? Check <em>brainbaking.com</em>. No response. Huh? Try to login into my VPS administration panel. More timeouts. Huh-wuh?</p>
<p><figure>
<a href="../ovh-fire.jpg" class="lbox">
<img loading="lazy" src="../ovh-fire.jpg" title="Uh-oh. This can&#39;t be good...">
</a>
<figcaption>Uh-oh. This can&#39;t be good...</figcaption>
</figure>
</p>
<p>SBG2, one of <a href="https://www.ovh.com/">OVHcloud&rsquo;s</a> data centers in Strasbourg, <a href="https://twitter.com/olesovhcom/status/1369770805064855552">was completely destroyed</a> by a fire last night. Luckily, everyone got out in time. Well, except for all VPS servers&hellip; Mine is hosted in the adjacent SBG1, and 1/3th of that center is also gone.</p>
<p>The first thing my wife posted on Instagram? <em>&ldquo;Dear sir/madam. <a href="https://www.youtube.com/watch?v=xqQ6Z-HmAqY">Fire - exclamation mark!</a> Fire - exclamation mark!&quot;</em> - who&rsquo;s the nerd now?</p>
<p>We were recommended to <em>&ldquo;activate your disaster recovery plan&rdquo;</em>. Cool. I didn&rsquo;t have any, except for a few shoddy bash scripts I wrote about <a href="/post/2020/04/vps/">last year</a>. That poor man&rsquo;s backup plan clearly was <em>not</em> sufficient&hellip; I hastily reserved another VPS in Gravelines, just below
Dunkirk. DNS IP settings borked, no failover plan, no automatic backups&hellip; Getting static websites back up and running in no-time is not a problem. However, my wife&rsquo;s Wordpress instance was much more painful.</p>
<p>And of course, I forgot to backup the CalDAV and Mastodon databases, and a portion of my wife&rsquo;s Moodle instance&hellip;</p>
<p>So yeah. Wednesday sucked. Time to put Ansible/Docker on the priority queue&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 11 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@eli_oat a serious fire destroyed the data center ...</title>
<link>https://brainbaking.com/notes/2021/03/10h16m24s22/</link>
<comments>https://brainbaking.com/notes/2021/03/10h16m24s22/#commento</comments>
<pubDate>Wed, 10 Mar 2021 16:24:22 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/10h16m24s22/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A54Sl2iQIm74acQBwu" href="https://dog.estate/@eli_oat" rel="ugc">@<span>eli_oat</span></a></span> a serious fire destroyed the data center of my VPS last night: <a href="https://twitter.com/olesovhcom/status/1369478732247932929" rel="ugc"><a href="https://twitter.com/olesovhcom/status/1369478732247932929">https://twitter.com/olesovhcom/status/1369478732247932929</a></a> - guess what I did NOT backup: my Mastodon instance. What a disaster. No idea if things get pushed back to this new instance. Just wanting to see if your instance recognizes this username, cause it's a fresh install?</p>
<p>invalid domain: <a href="https://youtube.com/cool">cool!</a></p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 10 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>I&amp;#39;ve been fiddling with IndieWeb stuff the last week and all in all, I think it&amp;#39;s a mixed...</title>
<link>https://brainbaking.com/notes/2021/03/09h15m17s30/</link>
<comments>https://brainbaking.com/notes/2021/03/09h15m17s30/#commento</comments>
<pubDate>Tue, 09 Mar 2021 15:17:30 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/09h15m17s30/</guid>
<description>
<![CDATA[
<p>I've been fiddling with IndieWeb stuff the last week and all in all, I think it's a mixed bag: <a href="https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/" rel="ugc"><a href="https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/">https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/</a></a><br><span class="h-card"><a class="u-url mention" data-user="A52GhcQ6Ux4hx6tIe0" href="https://fosstodon.org/@kev" rel="ugc">@<span>kev</span></a></span> after I published it, I found out your &quot;removing support for indieweb&quot; post. Seems like we agree that it's overly complicated, sadly enough! Loving the guestbook alternative. What to do, what to do&hellip; 😅</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 9 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>https://forth-standard.org/ - yet another programming language I need to take a look at? That lis...</title>
<link>https://brainbaking.com/notes/2021/03/09h08m09s04/</link>
<comments>https://brainbaking.com/notes/2021/03/09h08m09s04/#commento</comments>
<pubDate>Tue, 09 Mar 2021 08:09:04 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/09h08m09s04/</guid>
<description>
<![CDATA[
<p><a href="https://forth-standard.org/" rel="ugc"><a href="https://forth-standard.org/">https://forth-standard.org/</a></a> - yet another programming language I need to take a look at? That list is becoming ridiculously long&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 9 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>The IndieWeb Mixed Bag</title>
<link>https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/</link>
<comments>https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/#commento</comments>
<pubDate>Tue, 09 Mar 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/</guid>
<category domain="https://brainbaking.com/tags/privacy">privacy</category>
<category domain="https://brainbaking.com/tags/accessibility">accessibility</category>
<description>
<![CDATA[
<p>It&rsquo;s that time again: I started fiddling with my blog code - for the <em>nth</em> time. Kev Quirk calls it <a href="https://kevq.uk/the-wonderful-world-of-wordpress-wizardry-for-working-with-websites/">pissing around with the code</a>. That was meant negatively, and one of the reasons for him to switch back from Jekyll to Wordpress. I, however, like <em>pissing around</em> because I like <em>pissing</em> - or coding, just for the sake of it. After all, <em>Brain Baking</em> is a big side project that helps me learn and discover new things, blogging technology included.</p>
<h2 id="so-what-changed">So, what changed?</h2>
<p>I discovered the <a href="https://indieweb.org/">IndieWeb</a>, perhaps an integral part of what Aral Balkan likes to call the <a href="https://ar.al/2020/08/07/what-is-the-small-web/">Small Web</a>. Many IndieWeb W3C standards have been around for almost twenty years! I have no idea why I only came across it a few weeks ago. Since then, I&rsquo;ve been trying to refactor parts of my site to support the IndieWeb standards, and I&rsquo;m starting to see why.</p>
<p>It&rsquo;s a <em>big hassle</em>.</p>
<p>There&rsquo;s this thing with <code>h-card</code>, <code>e-content</code> and <code>u-url</code> meta-classes that have to be added in order for your HTML content to be machine-parsable. Verification can be done with any <a href="https://aimee-gm.github.io/microformats-parser/">microformats2-parser</a> or the nice website <a href="https://indiewebify.me">indiewebify.me</a>. That meant messing around with the templates - again - as of course many components were not properly placed within each other. Author information should be on the root page of your domain, syndication links should have proper meta classes, etc etc.</p>
<h2 id="but-why">But why?</h2>
<p>Now we&rsquo;re getting somewhere! One compelling component of the IndieWeb movement is <strong>Webmentions</strong>. A webmention is a logical evolution from <code>pingback</code> links from the hopefully long lost XML era that nobody ever implements unless they happen to run a Wordpress website. With Webmentions, you notify others when you&rsquo;ve written an article and linked theirs - or written a comment on theirs.</p>
<p>The concept is a webmention is that instead of commenting on someone else&rsquo;s domain, you <em>own your data</em>. Want to write a comment or remark? Post it on <em>your own</em> site and send a webmention instead. This idea is also called <a href="https://indieweb.org/POSSE">POSSE</a>: <em>Publish On your Site, Syndicate Elsewhere</em>. As opposed to PESOS: <em>Publish Elsewhere, Syndicate to your Own Site</em>. A very intriguing concept that got my full attention.</p>
<p>Until I started thinking about the ramifications of POSSE. It would be cool if the <a href="/notes/2021/03/04h08m47s31/">Switch supported POSSE</a> instead of having me post screenshots to a private Twitter account. It would be great if we had access to the ecosystem of the target <em>silo</em> (a centralized social platform) when simply interacting with our own site. <a href="https://www.jvt.me/mf2/2021/02/hvjtd/">Jamie Tanna</a> uses <a href="https://indigenous.realize.be/">Indigenous</a> to publish content to his site. Oh, you&rsquo;ll need to implement a few microservices (micropub/sub) in order to get that working&hellip; And you&rsquo;ll also lose context. So, again: why?</p>
<p>I like the idea of webmentions, because as an academic, I also like the idea of correctly citing each others work. In theory, writing something like this should automatically post webmention notifications to the people I mentioned in this article. A link to this article should appear on their page. Note that I&rsquo;m using the word <em>should</em> here. A few major problems prevent me from smiling instead of sighing:</p>
<ul>
<li>The responsibility for sending webmentions is the web blog owner. Many blogs do not send them out and only receive them because <a href="https://webmention.io/">webmention.io</a> makes it semi-easy to implement. Yes, many efforts like <a href="https://webmention.app/">webmention.app</a> exist to automate this, but none work effectively, and they all still require you to run the scripts.</li>
<li>Being dependent on something like webmention.io defeats the purpose of a <em>Small Web</em>: now I&rsquo;m still using a big central silo to receive my stuff!</li>
<li>As for POSSE: that&rsquo;s simply ridiculous when thinking about something like Goodreads. I might also be interested in what others are reading, and not every context gets synced to my site with the IndieWeb tools.</li>
</ul>
<h2 id="so-dont-do-it">So don&rsquo;t do it!</h2>
<p>I wrote about my <a href="/post/2020/06/tracking-and-privacy-on-websites/">Facebook PESOS attempt</a> before. I&rsquo;d love to POSSE, but some questions that are posted there simply don&rsquo;t make it back, and as a community maintainer, I simply sometimes need to be there, even if I really, really hate that.</p>
<p><strong>Blog comments</strong>, another big debate. My evolution from Disqus to Commento to nothing to Mastodon to Webmentions says it all<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>: it&rsquo;s a hassle. People like <a href="https://darthmall.net/weblog/webmentions/">Evan Sheehan</a> add a small form to each page where webmentions can be requested - although they should be sent automatically. But what about &ldquo;normal&rdquo;, non-tech savvy people? What if they want to comment? Oh, they can just use <a href="https://commentpara.de/">commentpara.de</a>. Well, that doesn&rsquo;t work, and I&rsquo;ve tried it - and it&rsquo;s another external liability.</p>
<p>All these headaches made people not just leave the IndieWeb standards behind: they are actually leaving static website generators behind and reverting to Wordpress! Read about <a href="https://rusingh.com/2021/03/05/waving-thankful-goodbye-to-static-websites-and-more/">Ru Singh</a> and <a href="https://chriswiegman.com/2020/08/hello-wordpress-my-old-friend/">Chris Wiegman</a>&rsquo;s reasons. It&rsquo;s mostly the convoluted workflow, and the hassle to get all the tools of their Jamstack-site just right.</p>
<p><figure>
<a href="../blogchart.jpg" class="lbox">
<img loading="lazy" src="../blogchart.jpg" title="Courtesy of rakhim.org. I&#39;m somewhere on the lower right...">
</a>
<figcaption>Courtesy of rakhim.org. I&#39;m somewhere on the lower right...</figcaption>
</figure>
</p>
<p><a href="https://jamstack.org/what-is-jamstack/">What&rsquo;s a jamstack</a> 🥞? I&rsquo;ve been jamstack-ing more than four years and only just found out that there&rsquo;s an acronym/cool word for the counterpart of a LAMP-stack: a <em>Javascript + Microservices-stack</em>. Because if you&rsquo;re interested in receiving webmentions, you still need an end-point&hellip;</p>
<p>Sleeves up, code out:</p>
<ul>
<li>microservice endpoint: check, <a href="https://github.com/wgroeneveld/serve-my-jams">https://github.com/wgroeneveld/serve-my-jams</a></li>
<li>javascript tools: check, <a href="https://github.com/wgroeneveld/jam-my-stack">https://github.com/wgroeneveld/jam-my-stack</a></li>
</ul>
<p>Okay, so now, I can answer the <em>why</em>. Not because it will be heavily used, or the IndieWeb stuff feels like the future. The low adoption rate says it all&hellip; No, simply because I was bored and wanted to learn about modern JS frameworks. I had an excuse to code again. Yay!</p>
<p>Still, once I more or less finished a first revision of my own toolset (sending is up next), I felt a bit empty inside. What&rsquo;s the point? Who will <em>webmention</em> me anyway? Those few other tech-related cooler bloggers? If you pay attention to the webmentions on other sites, you&rsquo;ll notice that <code>95%</code> of them are Twitter feeds, probably converted into webmentions by services like <a href="https://brid.gy/">brid.gy</a>. My point is that as far as <strong>usability</strong> goes, the IndieWeb standard completely falls apart. Sure, decentralization is the future. That&rsquo;s why I try to host and own my own data such as my <a href="https://chat.brainbaking.com/">Mastodon Instance</a> - and that&rsquo;s the philosophy of the IndieWeb.</p>
<p>But I can&rsquo;t ask my wife to stop posting on Instagram because she&rsquo;s giving her data away? I can&rsquo;t ask her to post it on her own Wordpress-site, after installing a bunch of <a href="https://kevq.uk/removing-support-for-the-indieweb/">barely working</a> POSSES-related plug-ins? And I can&rsquo;t ask visitors of my own site to &ldquo;webmention me!&rdquo; if they don&rsquo;t have a site?</p>
<p>Feel free to prove me wrong, though. Why don&rsquo;t you webmention this article?</p>
<h2 id="who-owns-what-data">Who owns what data?</h2>
<p>One of the key properties of POSSE-ing is that you include a url-shortened reference to the original article, like so: <code>(short.co 34yf1)</code>. Having to put up with visible junk metadata on Twitter is also a big concern for me. The theory behind it is good and logical, but without the silos supporting it, the implementation is just awful. Furthermore, without a reference, you won&rsquo;t know if it&rsquo;s POSSE or PESOS. Aren&rsquo;t you still giving your data away either way? On <a href="https://help.micro.blog/2018/twitter-differences/">Micro.blog</a>&rsquo;s help page, they explain the difference between Micro.blog and Twitter like so:</p>
<blockquote>
<p>But when you use Twitter, your content stays at Twitter. At Micro.blog, you can write short posts that appear in the Micro.blog timeline, as well as on your own blog that you control.</p>
</blockquote>
<p>But almost everyone who uses webmention uses it to syndicate replies from others to their site, after POSSE-ing their microblog contents to Twitter. Just for the record: I use PESOS on my <a href="/notes">fleeting notes</a>, because it&rsquo;s coming from my own Mastodon/Pleroma instance anyway.</p>
<p>So, in essence, you&rsquo;re still sending out data to big &ldquo;evil&rdquo; third party silos - possibly including media. That means from thereon, a snapshot of that data does <em>NOT</em> belong to you anymore. You just gave it away! I <a href="/notes/2021/02/27h17m51s39/">can&rsquo;t wrap my head</a> around that. Again, I think the <em>Own Your Data</em> philosophy is great, and I fully support it. Otherwise, I wouldn&rsquo;t have taken the trouble to <a href="/post/2021/03/getting-rid-of-tracking-using-lineageos/">install LineageOS</a>.</p>
<p>Maybe, a part of the blog technology fatigue is because of our own fanaticism&hellip;</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>Managing comments is a hassle, as Kev and others agree. I got rid of these systems last year. If you like to chime in on the discussion, just toot or e-mail me. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 9 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>I just learned about https://www.inklestudios.com/ink/ a scripting language used in story-heavy a...</title>
<link>https://brainbaking.com/notes/2021/03/06h12m41s48/</link>
<comments>https://brainbaking.com/notes/2021/03/06h12m41s48/#commento</comments>
<pubDate>Sat, 06 Mar 2021 12:41:48 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/06h12m41s48/</guid>
<description>
<![CDATA[
<p>I just learned about <a href="https://www.inklestudios.com/ink/" rel="ugc"><a href="https://www.inklestudios.com/ink/">https://www.inklestudios.com/ink/</a></a> a scripting language used in story-heavy adventurelite games such as Heaven's Vault. It reminds me of a mention of <a href="http://www.squirrel-lang.org/" rel="ugc"><a href="http://www.squirrel-lang.org/">http://www.squirrel-lang.org/</a></a> by Ron Gilbert while developing Thimbleweed Park: <a href="https://blog.thimbleweedpark.com/scripting_test.html" rel="ugc"><a href="https://blog.thimbleweedpark.com/scripting_test.html">https://blog.thimbleweedpark.com/scripting_test.html</a></a></p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 6 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>I spent some time with Yarn/Jest/ES2019, it felt good to be programming again. I am developing a ...</title>
<link>https://brainbaking.com/notes/2021/03/05h08m51s41/</link>
<comments>https://brainbaking.com/notes/2021/03/05h08m51s41/#commento</comments>
<pubDate>Fri, 05 Mar 2021 08:51:41 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/05h08m51s41/</guid>
<description>
<![CDATA[
<p>I spent some time with Yarn/Jest/ES2019, it felt good to be programming again. I am developing a serious JavaScript FOMO since switching from the software engineering industry to academia, and I'm not quite sure if I like that&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 5 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@rubenerd out of curiosity: are both synced in any way? If not, are you sure the migraine isnt fr...</title>
<link>https://brainbaking.com/notes/2021/03/04h14m52s55/</link>
<comments>https://brainbaking.com/notes/2021/03/04h14m52s55/#commento</comments>
<pubDate>Thu, 04 Mar 2021 14:52:55 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/04h14m52s55/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A4fIbZoZ0HNJPHV4Vs" href="https://bsd.network/@rubenerd" rel="ugc">@<span>rubenerd</span></a></span> out of curiosity: are both synced in any way? If not, are you sure the migraine isnt from checking both walls? 😇</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 4 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>Dog-walk thought: how cool would it be if the Nintendo Switch would support publishing screenshot...</title>
<link>https://brainbaking.com/notes/2021/03/04h08m47s31/</link>
<comments>https://brainbaking.com/notes/2021/03/04h08m47s31/#commento</comments>
<pubDate>Thu, 04 Mar 2021 08:47:31 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/04h08m47s31/</guid>
<description>
<![CDATA[
<p>Dog-walk thought: how cool would it be if the Nintendo Switch would support publishing screenshots through <a href="https://indieweb.org/Micropub" rel="ugc"><a href="https://indieweb.org/Micropub">https://indieweb.org/Micropub</a></a> ? Instead, I'm left to fiddling with Birdsite to manually <a href="https://indieweb.org/PESOS" rel="ugc"><a href="https://indieweb.org/PESOS">https://indieweb.org/PESOS</a></a> these things, after which I can finally use them in <a href="http://jefklakscodex.com/" rel="ugc">jefklakscodex.com/</a> &hellip; As long as big companies only support silo infrastructures, we're left with PESOS instead of POSSE.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 4 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>Heads up RSS feed readers of brainbaking.com! Federated half-baked thoughts (https://brainbaking....</title>
<link>https://brainbaking.com/notes/2021/03/03h16m00s44/</link>
<comments>https://brainbaking.com/notes/2021/03/03h16m00s44/#commento</comments>
<pubDate>Wed, 03 Mar 2021 16:00:44 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/03h16m00s44/</guid>
<description>
<![CDATA[
<p>Heads up RSS feed readers of <a href="http://brainbaking.com" rel="ugc">brainbaking.com</a>! Federated half-baked thoughts (<a href="https://brainbaking.com/notes/" rel="ugc"><a href="https://brainbaking.com/notes/">https://brainbaking.com/notes/</a></a>) are now integrated in /index.xml 🤓. Don't like that? Subscribe to /post/index.xml instead! Next up: webmentions, PESOS-ing of Goodreads reviews. I'm not sure if die-hard POSSE is worth it&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 3 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@StampedingLonghorn I tried to chase him away, but you know how that turned out... 😼 There&amp;#39;s ...</title>
<link>https://brainbaking.com/notes/2021/03/02h17m18s46/</link>
<comments>https://brainbaking.com/notes/2021/03/02h17m18s46/#commento</comments>
<pubDate>Tue, 02 Mar 2021 17:18:46 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/02h17m18s46/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A4nwg4LYyh4WgrJOXg" href="https://social.linux.pizza/@StampedingLonghorn" rel="ugc">@<span>StampedingLonghorn</span></a></span> I tried to chase him away, but you know how that turned out&hellip; 😼 There's even cat hair inside the cases&hellip; (to be clear: also unintentional)</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 2 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@StampedingLonghorn @256 Don&amp;#39;t forget the cleverly hidden Roland MT-32, a majestic piece of p...</title>
<link>https://brainbaking.com/notes/2021/03/02h17m13s27/</link>
<comments>https://brainbaking.com/notes/2021/03/02h17m13s27/#commento</comments>
<pubDate>Tue, 02 Mar 2021 17:13:27 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/02h17m13s27/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A4nwg4LYyh4WgrJOXg" href="https://social.linux.pizza/@StampedingLonghorn" rel="ugc">@<span>StampedingLonghorn</span></a></span> <span class="h-card"><a class="u-url mention" data-user="A4kSMHDHqoHahjCthg" href="https://mastodon.social/@256" rel="ugc">@<span>256</span></a></span> Don't forget the cleverly hidden Roland MT-32, a majestic piece of pre-MIDI standardized era synthesizer. What else would you use to run Sierra Online games, and monkey1? I really need one for my 486&hellip; <a href="https://brainbaking.com/post/2021/02/my-retro-desktop-setup/" rel="ugc"><a href="https://brainbaking.com/post/2021/02/my-retro-desktop-setup/">https://brainbaking.com/post/2021/02/my-retro-desktop-setup/</a></a></p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 2 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@aussocialadmin Great! I didn&amp;#39;t even know https://joinmobilizon.org/ existed, thanks for shar...</title>
<link>https://brainbaking.com/notes/2021/03/02h13m18s54/</link>
<comments>https://brainbaking.com/notes/2021/03/02h13m18s54/#commento</comments>
<pubDate>Tue, 02 Mar 2021 13:18:54 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/02h13m18s54/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A4nTeVFn4QjKtHVqpU" href="https://aus.social/@aussocialadmin" rel="ugc">@<span>aussocialadmin</span></a></span> Great! I didn't even know <a href="https://joinmobilizon.org/" rel="ugc"><a href="https://joinmobilizon.org/">https://joinmobilizon.org/</a></a> existed, thanks for sharing! So many superb alternatives. If only the userbase would follow&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 2 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>I pulled the Google plug and installed LineageOS: https://brainbaking.com/post/2021/03/getting-ri...</title>
<link>https://brainbaking.com/notes/2021/03/01h20m03s35/</link>
<comments>https://brainbaking.com/notes/2021/03/01h20m03s35/#commento</comments>
<pubDate>Mon, 01 Mar 2021 20:03:35 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/03/01h20m03s35/</guid>
<description>
<![CDATA[
<p>I pulled the Google plug and installed LineageOS: <a href="https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/" rel="ugc"><a href="https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/">https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/</a></a> Very impressed so far! Also rely on my own CalDAV server to replace GCalendar. Any others here running <a class="hashtag" data-tag="lineageos" href="https://chat.brainbaking.com/tag/lineageos" rel="tag ugc">#lineageos</a> for privacy reasons?</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>Getting rid of trackers using LineageOS</title>
<link>https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/</link>
<comments>https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/#commento</comments>
<pubDate>Mon, 01 Mar 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/</guid>
<category domain="https://brainbaking.com/tags/privacy">privacy</category>
<description>
<![CDATA[
<p>Since dipping my toes into the subject of <a href="/tags/privacy">privacy</a>, I kept on exploring more opportunities to take back my own data. This started out quite innocent with a few <a href="/post/2020/06/tracking-and-privacy-on-websites/">changes to this site</a>, that evolved into taking great care <a href="/post/2021/01/digitizing-journals-using-devonthink/">not to spill my data</a> to &ldquo;the cloud&rdquo;. Thank you, <a href="https://laurakalbag.com">Laura</a> and <a href="https://ineed.coffee">Daniel</a>. It seems that a pattern emerges here. Consistently pulling the plug - I love it.</p>
<p>Since January this year, I migrated form GMail to <a href="https://protonmail.com">ProtonMail</a> and took that opportunity to finally settle with a short address on my own domain. The trouble is, simply installing the ProtonMail app on Android does next to nothing if your contacts and address book is are managed by Google. After importing the contacts into Proton, it is still a hassle to create a new one without opening the secure app. So, it was time to go cold turkey on this one. <em>Project Exit Google</em>. To do that, I needed more than a secure e-mail provider. I needed a whole new OS<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. <em>Enter <a href="https://lineageos.org/">LineageOS</a></em>.</p>
<blockquote>
<p>LineageOS is a privacy-focused open source Android OS.</p>
</blockquote>
<h2 id="1-the-installation">1. The Installation</h2>
<p>I&rsquo;ll be honest with you: it was a pain, and it took several days to get it just right. I have an older Sony XZ1 Compact smartphone, one that according to Google can only run up to Android 9. Well, wrong! With LineageOS, you not only get rid of all Google-focused services and unwanted tracking, you also get the latest Android features as a bonus.</p>
<p>That is, if you manage to get it installed. The <a href="https://download.lineageos.org/">downloads builds</a> already gave me trouble: no build for the XZ1. Thankfully, <a href="https://www.getdroidtips.com/lineage-os-17-sony-xperia-xz1-compact/">getdroidtips.com</a> has published a bunch of phone-specific tutorials - only these proved to be very confusing: which tool do I need first? Flash the what now? Reboot how many times? Put that where?</p>
<p>The concept is as follows:</p>
<ol>
<li>Unlock your phone using the <a href="https://developer.android.com/studio/command-line/adb">Android Debug Bridge</a>.</li>
<li>Flash a recovery image of <a href="https://twrp.me/">TWRP</a>.</li>
<li>Use TWRP in recovery mode to prepare the installation by formatting/cleaning/&hellip;</li>
<li>Flash a bootable LineageOS image using TWRP.</li>
<li>Reboot and pray.</li>
<li>If you must: flash an <a href="https://opengapps.org/">Open GApps</a> image - of course I didn&rsquo;t.</li>
</ol>
<p>Unfortunately, I first got stuck in a boot loop due to incompatible TWRP/Lineage versions. The combination <code>lineage-17.1-20201217-UNOFFICIAL-v1.7-lilac</code> and <code>twrp-3.5.0-0-20210117-lilac.img</code> solved that. Next, I had issues with hard disk encryption that went away after repeatedly trying to wipe various things in TWRP. Do not forget to make a backup of your stuff&hellip;</p>
<h2 id="2-it-boots-now-what">2. It boots. Now what?</h2>
<p>Great! Did you configure encryption settings?</p>
<p><figure>
<a href="../lineage-splash.jpg" class="lbox">
<img loading="lazy" src="../lineage-splash.jpg" title="My Lineage Home Screen.">
</a>
<figcaption>My Lineage Home Screen.</figcaption>
</figure>
</p>
<p>Now all we need to do is to find decent replacements for Google&rsquo;s convenient services and apps. Don&rsquo;t get me wrong, I love Google products. I just don&rsquo;t like the free tracking that comes with it. I&rsquo;ve read bloggers complaining about &ldquo;going back to the Dark Ages&rdquo; because of the loss of Google fluff. Fortunately, using LineageOS feels far from being stuck with secondary-choice material.</p>
<p>Lineage is basically a cleaned-up vanilla Android. As you can see from the screenshot above, you can still install any software you&rsquo;d like, although some might not work that perfectly, since the Google Play store is gone. ProtonMail&rsquo;s push notifications don&rsquo;t work, for instance - but that is a good thing, right? Instead, Lineage relies on the <a href="https://auroraoss.com/">Aurora Store</a> and of course <a href="https://f-droid.org/en/packages/">F-Droid</a>. The first is an anonymous shell on top of the Play Store, and the latter&hellip; well, is kind of the junkyard, since sadly not many developers choose to push to the F-Droid repository. Of course, installing a downloaded <code>.apk</code> file works just as well. Yes, both stores will still auto-update your apps. Yes, your favorite banking app still works (at least mine does).</p>
<h3 id="privacy-aware-communication-apps">Privacy-aware communication apps</h3>
<p>Below is a list of apps I&rsquo;ve tried and now rely on:</p>
<ul>
<li><em>Messaging</em>: <a href="https://telegram.org/">Telegram</a>, <a href="https://www.signal.org/">Signal</a>, &hellip; all work. Sadly, so does WhatsApp.</li>
<li><em>Email</em>: the ProtonMail app (although honestly not that great)</li>
<li><em>Social Media</em>: <a href="https://tusky.app/">Tusky</a> is a great Mastodon client!</li>
</ul>
<p>I also use Proton to manage my contacts. After importing from my Google Account before installing Lineage, I now can import/export using a <code>vCard</code> file (although Lineage&rsquo;s default Contact app did not understand <code>v4.0</code>: simply replace all occurrences of <code>4</code> to <code>3</code> in the file itself). The process is not automated, but hey. New contacts by default reside in the smartphone, all I need to do is now and then pressing &ldquo;import&rdquo; again. Bye bye, Google-kept sensitive data of all my friends and family<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<h3 id="privacy-aware-google-maps-alternatives">Privacy-aware Google Maps alternatives</h3>
<ul>
<li><em>City navigation</em>: <a href="https://wego.here.com/">HERE WeGo</a> worked great and has an acceptable privacy policy.</li>
<li><em>Hiking</em>: <a href="https://osmand.net/">OsmAnd</a> uses Open Streetmap data and has the ability to seamlessly download map data. It&rsquo;s not great for in-car use, though.</li>
</ul>
<p>I thought finding a decent alternative was going to be difficult, but I was pleasantly surprised by these two. Give them both a go, even if you&rsquo;re on the vanilla Android OS! If all else fails, you can still surf to maps.google.com.</p>
<h3 id="a-privacy-aware-google-calendar-alternative">A privacy-aware Google Calendar alternative</h3>
<p>Here&rsquo;s where things get a bit more complicated. I heavily relied on Google Calendar&rsquo;s ease of use and sync capabilities to inform my wife of things I&rsquo;ve planned (or the other way around), and she&rsquo;s on iOS. Furthermore, I wanted my MacBook to also use the same calendar: what&rsquo;s the purpose of a digital calendar if it does not synchronize?</p>
<p>After a few hours of fiddling, I had a <a href="https://radicale.org/3.0.html">Radicale CalDAV server</a> up and running on my own domain, that even works with SSL and the usual encryption stuff. Granted, data is not (yet) stored encrypted at rest, but at least it&rsquo;s on my own VPS! On Lineage, install <a href="https://www.davx5.com/">DAVx5</a> - it integrates nicely with the default calendar app. I also rely on <a href="https://icsx5.bitfire.at/">ICSx5</a> to sync my academic calendar using a <code>.ics</code> link. Both work perfectly.</p>
<h3 id="privacy-aware-cloud-syncing">Privacy-aware cloud syncing</h3>
<p>If you must use data syncing using a third party cloud such as iCloud/Google Drive/Dropbox, you still can. Simply use <a href="https://cryptomator.org/">Cryptomator</a> and encrypt everything client-side before sending it to the server. There are mobile clients available, and although it is a bit on the heavy side, it works.</p>
<p>For me though, I decided against using it. My photos are <em>not</em> synced, and I like that now. When I want to transfer something to another machine, I simply share locally through Bluetooth or using the nice <a href="https://openmtp.ganeshrvel.com/">OpenMTP</a> Android File Transfer app for MacOS.</p>
<h3 id="others">Others</h3>
<p><figure>
<a href="../lineage-bandcamp.jpg" class="lbox">
<img loading="lazy" src="../lineage-bandcamp.jpg" title="Looks a lot like stock Android!">
</a>
<figcaption>Looks a lot like stock Android!</figcaption>
</figure>
</p>
<p>A few other apps I regularly use that worked flawlessly on LineageOS:</p>
<ul>
<li>Firefox Mobile with the <a href="https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/">uBlock Origin</a> plugin</li>
<li>Goodreads</li>
<li><a href="https://freeotp.github.io/">FreeOTP</a><sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></li>
<li>Bandcamp (<a href="/2021/02/you-shouldnt-use-spotify/">You Shouldn&rsquo;t Use Spotify</a>)</li>
<li>Spotify (Don&rsquo;t believe everything I write)</li>
<li><a href="https://anysoftkeyboard.github.io/">AnySoftKeyboard</a></li>
</ul>
<p>After stress testing LineageOS for two weeks, I can safely say I&rsquo;m impressed. Even the battery life somewhat improved. Granted, I am not a heavy smartphone user. I hate carrying the thing around and sometimes &ldquo;forget&rdquo; it, much to my wife&rsquo;s frustration. But still - I thought getting rid of Google Calendar and others would involve more headaches. I have deleted most e-mails, all my photos, calendar items, and contacts from my Google account, and have not regretted it once. However, <em>do not delete your entire Google account</em>. It now serves as a good spam e-mail address! Give those pesky car salesman your GMail address and they&rsquo;ll think they&rsquo;ve got you. Ha!</p>
<p>If you also experimented with the OS, let me know what you think of Lineage. Which programs did not work that well? Did you experience any trouble with the Google withdrawal plan? <a href="https://chat.brainbaking.com/@wouter">Toot me</a>!</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>Others have solved this issue by trading Android <a href="https://kevq.uk/why-im-ditching-android">for iOS</a>. I think that&rsquo;s a bit ridiculous. Sure, Apple is less keen on making money through advertising than Google, but don&rsquo;t tell me iCloud services won&rsquo;t track you. Still, idle Android phones <a href="https://www.bleepingcomputer.com/news/google/idle-android-phones-send-data-to-google-ten-times-more-often-than-ios-devices-to-apple/">send data to Google ten times more often</a> than iOS devices to Apple. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Note that using WhatsApp also means that <em>all</em> your contacts are sent to their servers. Try this: open up the WhatsApp settings <code>-&gt;</code> Account <code>-&gt;</code> Request account info. This is <a href="https://signal.org/legal/">not the case with Signal</a>! <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Backup your settings before reinstalling your phone! I locked myself out of my Paypal account because of that&hellip; <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 March 2021.
</p>
]]>
</description>
</item>
<item>
<title>@darth_mall Interesting, did you use Bridgy to convert Mastodon posts into webmentions? Many site...</title>
<link>https://brainbaking.com/notes/2021/02/28h11m47s37/</link>
<comments>https://brainbaking.com/notes/2021/02/28h11m47s37/#commento</comments>
<pubDate>Sun, 28 Feb 2021 11:47:37 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/02/28h11m47s37/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A4jKa9Q2dIr3nGJlJY" href="https://vis.social/@darth_mall" rel="ugc">@<span>darth_mall</span></a></span> Interesting, did you use Bridgy to convert Mastodon posts into webmentions? Many sites seem to use it, but it of course only scans your own Twitter/Masto feed. IMO, this renders it a bit useless unless you're very popular (😰). Anyone you don't know could talk about a post on your site, but it won't be received since these systems do not push webmentions themselves. Furthermore, I do not see anyone manually posting a link at the end of a post - that kind of defeats the purpose. <br>That said, is it working for you?</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 28 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>Okay, so sending involves Webmention.app and IFTTT to poll my RSS feed (According to https://www....</title>
<link>https://brainbaking.com/notes/2021/02/27h18m00s19/</link>
<comments>https://brainbaking.com/notes/2021/02/27h18m00s19/#commento</comments>
<pubDate>Sat, 27 Feb 2021 18:00:19 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/02/27h18m00s19/</guid>
<description>
<![CDATA[
<p>Okay, so sending involves <a href="http://Webmention.app" rel="ugc">Webmention.app</a> and IFTTT to poll my RSS feed (According to <a href="https://www.jayeless.net/2021/02/integrating-webmentions-into-hugo.html" rel="ugc"><a href="https://www.jayeless.net/2021/02/integrating-webmentions-into-hugo.html">https://www.jayeless.net/2021/02/integrating-webmentions-into-hugo.html</a></a>). Holy shit. Is it even worth it&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 27 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>Trying to wrap my mind around WebMentions and how I could implement them without resorting to a t...</title>
<link>https://brainbaking.com/notes/2021/02/27h17m51s39/</link>
<comments>https://brainbaking.com/notes/2021/02/27h17m51s39/#commento</comments>
<pubDate>Sat, 27 Feb 2021 17:51:39 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/02/27h17m51s39/</guid>
<description>
<![CDATA[
<p>Trying to wrap my mind around WebMentions and how I could implement them without resorting to a third-party provider&hellip; <a href="https://sebastiandedeyne.com/adding-webmentions-to-my-blog/" rel="ugc"><a href="https://sebastiandedeyne.com/adding-webmentions-to-my-blog/">https://sebastiandedeyne.com/adding-webmentions-to-my-blog/</a></a> I wonder if a link such as this one would receive a webmention/pingback if I just write about it using Hugo.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 27 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>Has anyone else noticed posted links on Twitter get re-encoded into t.co URLs in order to gather ...</title>
<link>https://brainbaking.com/notes/2021/02/27h14m25s16/</link>
<comments>https://brainbaking.com/notes/2021/02/27h14m25s16/#commento</comments>
<pubDate>Sat, 27 Feb 2021 14:25:16 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/02/27h14m25s16/</guid>
<description>
<![CDATA[
<p>Has anyone else noticed posted links on Twitter get re-encoded into <a href="http://t.co" rel="ugc">t.co</a> URLs in order to gather even more 'insight' data? That said, I'm having trouble finding anyone on the Fediverse&hellip; Any hints?</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 27 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>@laura It did more than helping! I&amp;#39;m slowly but surely taking back my data. Started with Ever...</title>
<link>https://brainbaking.com/notes/2021/02/26h19m55s59/</link>
<comments>https://brainbaking.com/notes/2021/02/26h19m55s59/#commento</comments>
<pubDate>Fri, 26 Feb 2021 19:55:59 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/02/26h19m55s59/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A4fIvtjUepzOyQooXg" href="https://mastodon.laurakalbag.com/@laura" rel="ugc">@<span>laura</span></a></span> It did more than helping! I'm slowly but surely taking back my data. Started with Evernote -&gt; DEVONThink, got to Gmail -&gt; ProtonMail, and now to Android -&gt; LineageOS. All your fault 😂</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 26 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>Just saying hi @kogakure 👋 getting my feet wet with decentralized “tooting” (although I opted for...</title>
<link>https://brainbaking.com/notes/2021/02/26h13m48s06/</link>
<comments>https://brainbaking.com/notes/2021/02/26h13m48s06/#commento</comments>
<pubDate>Fri, 26 Feb 2021 13:48:06 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/02/26h13m48s06/</guid>
<description>
<![CDATA[
<p>Just saying hi <span class="h-card"><a class="u-url mention" data-user="A4fMTkA13Luczi3SCW" href="https://mastodon.social/@kogakure" rel="ugc">@<span>kogakure</span></a></span> 👋 getting my feet wet with decentralized “tooting” (although I opted for Pleroma, less drama to install in my own VPS it seemed)</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 26 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>Hi @laura thanks to your https://laurakalbag.com/what-is-mastodon-and-why-should-i-use-it/ I dipp...</title>
<link>https://brainbaking.com/notes/2021/02/26h13m08s52/</link>
<comments>https://brainbaking.com/notes/2021/02/26h13m08s52/#commento</comments>
<pubDate>Fri, 26 Feb 2021 13:08:52 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/02/26h13m08s52/</guid>
<description>
<![CDATA[
<p>Hi <span class="h-card"><a class="u-url mention" data-user="A4fIvtjUepzOyQooXg" href="https://mastodon.laurakalbag.com/@laura" rel="ugc">@<span>laura</span></a></span> thanks to your <a href="https://laurakalbag.com/what-is-mastodon-and-why-should-i-use-it">https://laurakalbag.com/what-is-mastodon-and-why-should-i-use-it</a>/ I dipped my toes into decentralized social networks 😅 FYI The “Whats wrong with Twitter” link on there is broken. Loving what you do so far, you made me reconsider accessibility and privacy features on my own site!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 26 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>@rubenerd just installed my own Pleroma server to say hi! Big fan of your micro-blog for ages here.</title>
<link>https://brainbaking.com/notes/2021/02/26h13m04s14/</link>
<comments>https://brainbaking.com/notes/2021/02/26h13m04s14/#commento</comments>
<pubDate>Fri, 26 Feb 2021 13:04:14 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/notes/2021/02/26h13m04s14/</guid>
<description>
<![CDATA[
<p><span class="h-card"><a class="u-url mention" data-user="A4fIbZoZ0HNJPHV4Vs" href="https://bsd.network/@rubenerd" rel="ugc">@<span>rubenerd</span></a></span> just installed my own Pleroma server to say hi! Big fan of your micro-blog for ages here.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 26 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>The insanity of collecting retro games</title>
<link>https://brainbaking.com/post/2021/02/the-insanity-of-retro-game-collecting/</link>
<comments>https://brainbaking.com/post/2021/02/the-insanity-of-retro-game-collecting/#commento</comments>
<pubDate>Sun, 21 Feb 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/02/the-insanity-of-retro-game-collecting/</guid>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<category domain="https://brainbaking.com/tags/games">games</category>
<description>
<![CDATA[
<p>When I posted my <a href="/post/2021/02/my-retro-desktop-setup/">retro 2021 desktop setup</a> at the beginning of this month, I unintentionally left out a photo of my SNES/Game Boy/whatever physical cartridge collection. You can marvel at my very limited (past) <a href="https://jefklakscodex.com/articles/features/gaming-setup-2007-flashback/">2007 gaming setup</a> and collection over at Jefklak&rsquo;s Codex - I&rsquo;ll go ahead and steal a few photos there to sprinkle them over this article.</p>
<p>As you might have read in the <a href="/2021/02/you-shouldnt-use-spotify/">You Shouldn&rsquo;t Use Spotify</a> article, I recently started thinking things through when spending my hard earned money. It was only a matter of time before arriving at the topic of retro gaming&hellip; And as with all things in this capitalistic world, things that become uncommon also have the tendency to become very, <em>very</em> expensive. Sadly, but perhaps not unexpectedly so, the same is true for retro game collecting. For instance, take a look at the second hand price history of what used to be a fairly common Nintendo DS game; <em>Castlevania Dawn of Sorrow</em>:</p>
<p><figure>
<a href="../valuegamenow.jpg" class="lbox">
<img loading="lazy" src="../valuegamenow.jpg" title="Castlevania Dawn of Sorrow price evolution at Game Value Now">
</a>
<figcaption>Castlevania Dawn of Sorrow price evolution at Game Value Now</figcaption>
</figure>
</p>
<p>The game was released in 2005. Ten years later, one paid on average <code>$20</code> for it - about half of the new price. Since then, prices have gone up. And up. And up. The last sudden big spark is the COVID-effect on game collecting: almost any well-received retro game suddenly costs about a third more than it used to be. Thank you, boredom. The effect isn&rsquo;t that dramatic for Dawn of Sorrow since DS games are &ldquo;relatively new&rdquo;. However, if you take a look at its older brother, <a href="https://gamevaluenow.com/gameboy-advance/Castlevania-Aria-of-Sorrow?gameid=167">Aria of Sorrow</a> for the Game Boy Advance, a complete box sets you back for almost <code>$160</code> - that is four times as much as the original price! Baffling.</p>
<p>As mentioned in <a href="https://www.nintendolife.com/news/2021/02/soapbox_retro_nintendo_games_cost_too_much_but_nostalgia_is_expensive">Nintendo Life&rsquo;s article</a> &ldquo;<em>Retro Nintendo Games Cost Too Much, But Nostalgia Is Expensive</em>, even GameCube games, that until recently were fairly affordable, have suddenly become (too) expensive. Why would you pay more than the original price for Smash Brothers Melee when the latest installment is available on the Nintendo Switch, and the gameplay is the same? Nostalgia indeed does seem to come at a steep price.</p>
<blockquote>
<p>Why would you want to pay more than the original price for Smash Brothers Melee on GameCube?</p>
</blockquote>
<p>Before the global pandemic, a few critics conspired that famous retro gamer <em>Metal Jesus Rocks</em> and his incredibly popular YouTube channel also negatively <a href="https://www.reddit.com/r/gamecollecting/comments/8jmiwi/how_metal_jesus_rocks_affects_retro_video_game/">affects retro game prices</a> with his reviews - and thus ultimately increasing demand. Metal Jesus is also a big fan of the <a href="https://hyperkin.com/retro/retron-5.html">Hyperkin Retron 5</a> all-in-one retro console. Yes, the one that used GNU GPL-licensed open source software without asking. I&rsquo;ve also read about his awesome collection in the UK magazine <em>Retro Gamer</em>. No doubt that must have inspired others - I know it inspired me. Well, until I saw the prices of many games&hellip;</p>
<p><figure>
<a href="../nostalgia_handhelds.jpg" class="lbox">
<img loading="lazy" src="../nostalgia_handhelds.jpg" title="A part of my 2007 handheld collection. I was stupid enough to sell that limited edition Game Boy Micro. It is now goes for over $200...">
</a>
<figcaption>A part of my 2007 handheld collection. I was stupid enough to sell that limited edition Game Boy Micro. It is now goes for over $200...</figcaption>
</figure>
</p>
<h2 id="where-does-that-money-go-to">Where does that money go to?</h2>
<p>Imagine you&rsquo;re buying a recently released game. I presume you want to support the game developers as much as possible. In that case, just like I wrote about <a href="/2021/02/you-shouldnt-use-spotify/">not using Spotify</a>, don&rsquo;t just stream it: buy it - preferably from the devs themselves. Great, you now helped finance a possible sequel!</p>
<p>But what about retro games? I just paid <code>$100</code> to a shady seller at eBay or a local flea market - does that mean a successor to Dawn of Sorrow is guaranteed? No. Konami fucked up the Castlevania series a long time ago, and the creator of the <em>Igavania</em> sub-genre, Koji Igarashi, left in 2014 to start his own studio <a href="https://artplayinc.com/">ArtPlay</a>. Even if the original devs did not leave at some point, money spent on second hand products simply do not end up in the hands of the creator. That does not mean that publishers and developers do not keep an eye out for games that are still in high demand.</p>
<p>The retro game collection hype created a lot of sleezy sharks that love to rip you off: from the common practice of counterfeiting catrdiges - which by now are difficult to discern with the naked eye - to asking absurd amounts of money for &ldquo;mint&rdquo; (boxed) versions of a game. This second hand market seems to bring out the worst in people. I&rsquo;ve witnessed and I&rsquo;ve been a victim of a lot of shady looking deals because of that.</p>
<p><figure>
<a href="/img/fake-gba.jpg" class="lbox">
<img loading="lazy" src="/img/fake-gba.jpg" title="Can you detect which GBA cart is fake?">
</a>
<figcaption>Can you detect which GBA cart is fake?</figcaption>
</figure>
</p>
<p>That brings me to the question: is it really worth it? Do I really want to spend a hundred bucks on a game, of which the dev company is defunct, knowing that my money will ultimately end up supporting this malpractice? There is a lot of proper research on the financial and psychological impact of a second-hand market system, and a lot of improper &ldquo;biz&rdquo; (<a href="https://www.gamesindustry.biz/articles/2012-03-19-used-games-business-is-killing-single-player-experience-says-frontier-developments">used games killed single player gaming</a>, <a href="https://www.gamesindustry.biz/articles/2012-04-12-the-real-cost-of-used-games">used games eliminates independent studios</a>, &hellip;), too much for me to skim through, so feel free to point out where my thinking derailed.</p>
<h2 id="okay-so-lets-pirate-instead">Okay, so let&rsquo;s pirate instead!</h2>
<p>No harm done, right? The game is twenty years old, the companies behind it are long gone, so who cares? I wrote about <a href="/post/2018/12/over-analoog-en-digitaal/">this topic</a> before. We&rsquo;re entering a gray area here, although a lot of people would love to shout <em>&ldquo;No way, it&rsquo;s black or white!&quot;</em> instead.</p>
<p>Although downloading emulators is of course legal, sharing copyrighted ROMs online clearly is not. There is no legal precedent for ripping and downloading ROMs for games you own, though an argument could be made for fair use, as lawyer Derek E. Bambauer <a href="https://www.howtogeek.com/262758/is-downloading-retro-video-game-roms-ever-legal/">points out</a>. Legal matters aside, my main interest is if it harms anyone if you decide to do so for older games. I think it&rsquo;s safe to say yes: many companies still own copyrights to older games - and many companies like Nintendo sill thrive on selling retro games.</p>
<blockquote>
<p>There is no legal precedent for ripping and downloading ROMs for games you own, though an argument could be made for fair use.</p>
</blockquote>
<p>Disney has a special strategy devoted to bringing classic animated videos back to life: they purposely put projects into a vault for many years, only to come back to it later on to reboot/remaster/whatever the original version. I&rsquo;d be less inclined to buy the remaster if I pirated the original a few weeks ago. <a href="https://jefklakscodex.com/articles/features/super-mario-64-aged-badly/">Super Mario 3D All Stars</a> is a compilation of three retro 3D Mario games that was released by Nintendo a few months ago. They even added an unfair amount of pressure to consumers by limiting the amount of physical releases. These games were hardly remastered at all, yet sold like hot cakes. I&rsquo;d be lying if I said I didn&rsquo;t buy it, although I owned all games at some point before.</p>
<p><figure>
<a href="../nostalgia_gamecubecrt.jpg" class="lbox">
<img loading="lazy" src="../nostalgia_gamecubecrt.jpg" title="A part of my 2007 GameCube collection. Even a mediocre game like Wario World, which saw a Player&#39;s Choice re-release, goes for $56 nowadays!">
</a>
<figcaption>A part of my 2007 GameCube collection. Even a mediocre game like Wario World, which saw a Player&#39;s Choice re-release, goes for $56 nowadays!</figcaption>
</figure>
</p>
<h2 id="okay-so-lets-buy-them-digitally">Okay, so let&rsquo;s buy them digitally!</h2>
<p>This remark misses the point. First, retro game collecting is mainly a physical act. For this reason, most serious game collectors wouldn&rsquo;t even consider downloading ROMs - legal or otherwise For this very same reason, I completely detest the trend towards digital gaming. Second, many games are simply not for sale anymore. Of course, many big publishers smell money when they look at their old game collection, and love to periodically re-release old stuff for us suckers to double-dip - no questions asked. But many of the best games have had their prime time, and are unlikely to see the light again, due to legal issues, defunct companies, missing source code, &hellip; As you might have guessed, these games are especially expensive in the second hand market.</p>
<p>Sites such as <a href="https://gog.com">Good Old Games</a> use your nostalgic preference for old junk to cash in. As mentioned before, I love Wizardry 8, and I own the original CDs. The game is also available on GOG. However, Sir-Tech does not exist anymore. I have no idea how this works in detail, but somehow <a href="https://www.nightdivestudios.com/">Nightdive Studios</a> grabs hold of the rights for the title and re-released it on GOG in 2013. That means buying it through the GOG digital platform possibly helps re-vitalizing other classic PC games, since it is Nightdive Studios' primary occupation. However, that does not mean that any of the hard working people of the original game are supported in any way.</p>
<hr>
<p>Buying Wiz8 at GOG does do <em>something</em> useful with your hard earned money. I doubt that buying a Castlevania Aria of Sorrow copy through eBay does the same - except perhaps the ability to put it in a glass cabinet to show off to your fellow retro nerds.</p>
<p>And yet, I really, <em>really</em> want to play Game Boy games on my original Game Boy. Seductive looking pieces of hardware like the <a href="https://www.analogue.co/pocket">Analogue Pocket</a> only makes things worse. Why isn&rsquo;t there a GOG-equivalent for obtaining legal copies of ROMs? I was so thrilled with the Wii&rsquo;s Virtual Console system, and so disappointed at the same time, as Nintendo&rsquo;s Spartan selection left people wanting for more. Furthermore, hacking your Wii to download that legally bought copy (in order to transfer it to a flashcard on your GB) was not only hard - it was also juridically questionable.</p>
<p>That said, I missed a big sale day at my <a href="https://retrogamestore.be/">local retro game store</a>. I was looking forward to mindlessly adding more junk to the shelves&hellip; Don&rsquo;t forget to bring your screwdriver to check the genuineness of the chip!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 21 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>How to write academic papers in Markdown</title>
<link>https://brainbaking.com/post/2021/02/writing-academic-papers-in-markdown/</link>
<comments>https://brainbaking.com/post/2021/02/writing-academic-papers-in-markdown/#commento</comments>
<pubDate>Sun, 14 Feb 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/02/writing-academic-papers-in-markdown/</guid>
<category domain="https://brainbaking.com/tags/publishing">publishing</category>
<category domain="https://brainbaking.com/tags/pandoc">pandoc</category>
<category domain="https://brainbaking.com/tags/Markdown">Markdown</category>
<category domain="https://brainbaking.com/tags/latex">latex</category>
<description>
<![CDATA[
<p>In 2020, I explained <a href="/post/2020/05/using-pandoc/">how to use pandoc</a> to publish a book. Essentially, I use the same workflow to write papers in academia. A couple of colleagues asked me how this was done, although they suspected it had something to do with <a href="https://pandoc.org/">Pandoc</a>. When I&rsquo;m not writing in collaboration with someone, and thus using <a href="https://overleaf.com/">Overleaf</a>, I like to keep things simple, by resorting to my favorite way of writing things: Markdown.</p>
<p>However geeky and cool LaTeX might be, it violates a lot of <em>Clean Code</em> rules by ignoring separation of concerns. Even <code>html</code> has most of the layout separated - albeit not in a particularly good way - using <code>css</code>. Having to write <code>\textbf{wowza}</code> just to get something in bold gets tiresome fast, and creating your own rules, tags, or scripts ultimately do not resolve the issue, they just work around it. I&rsquo;m not advocating for writing your dissertation in Word. It&rsquo;s simply very confusing to look at a document and try to read sections and streams of thought without the LaTeX syntax getting in the way.</p>
<p>Enter Markdown: instead of</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex">Hello <span style="color:#728e00">\textbf</span><span style="color:#728e00">{</span>bold<span style="color:#728e00">}</span> stuff! Oh wait, here&#39;s ``an image&#34; - weird quotations
<span style="color:#728e00">\begin</span><span style="color:#728e00">{</span>figure<span style="color:#728e00">}</span>[h!]
<span style="color:#728e00">\centering</span>
<span style="color:#728e00">\includegraphics</span><span style="color:#728e00">{</span>something.png<span style="color:#728e00">}</span>
<span style="color:#728e00">\caption</span><span style="color:#728e00">{</span>My caption. <span style="color:#728e00">\label</span><span style="color:#728e00">{</span>fig:delphi<span style="color:#728e00">}}</span>
<span style="color:#728e00">\end</span><span style="color:#728e00">{</span>figure<span style="color:#728e00">}</span>
Yeah. That sucks.
</code></pre></div><p>You write:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-md" data-lang="md">Hello **bold** stuff! Oh wait, here&#39;s &#34;an image&#34; - regular quotes, whew.
![<span style="color:#434f54">&#34;My caption.&#34;</span>](<span style="color:#434f54">something.png</span>)
Yeah. Much better.
</code></pre></div><p>Sure, there&rsquo;s still &ldquo;syntax&rdquo; to be learned the uninitiated. Still, it&rsquo;s a heck of a lot less, and it makes reading source files (<code>.md</code> instead of <code>.tex</code>) much, <em>much</em> easier. Take a look at an Overleaf window of our latest paper draft:</p>
<p><figure>
<a href="../overleaf.jpg" class="lbox">
<img loading="lazy" src="../overleaf.jpg" >
</a>
</figure>
</p>
<p>The left part - where you do the work - is simply hideous, and usually riddled with layout-specific syntax. Don&rsquo;t get me wrong, I love the collaborative plus-side of Overleaf, but it&rsquo;s still raw LaTeX. As a Java developer, I do not write <code>.class</code> files either: I write the <code>.java</code> ones and compile the latter.</p>
<h3 id="the-toolchain">The toolchain</h3>
<p>As mentioned in the <a href="/post/2020/05/using-pandoc/">pandoc article</a>, this is the setup:</p>
<script defer src="/mermaid/mermaid.min.js">
mermaid.initialize({
startOnLoad: true,
flowchart: {
useMaxWidth: true
}
});
</script>
<div class="mermaid" align="center" >
graph LR;
md[Plaintext, md =]
tex[LaTeX, tex =]
pdf[Postscript, pdf =]
md --> tex
tex --> pdf
</div>
<p>Simple enough, and the <a href="https://pandoc.org/MANUAL.html">Pandoc User Guide</a> helps you in understanding the specifics when converting from Markdown to Tex. The most challenging part of writing academic papers in Markdown is not the conversion process but the annoying details you have to get right when adhering to a layout/template of a conference or journal. I write most things in Sublime, and put simple commands in a <code>Makefile</code> in order for <code>⌘+B</code> (Build) to work. The build file itself is straightforward enough:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-make" data-lang="make"><span style="color:#d35400">all</span><span style="color:#728e00">:</span>
pandoc -f markdown+smart delphi_report.pd.md --include-in-header<span style="color:#728e00">=</span>delphi_report_preamble.tex --template<span style="color:#728e00">=</span><span style="color:#728e00">$(</span>templatedir<span style="color:#728e00">)</span>/acm-pandoc-conf.tex --filter panflute --natbib --variable --biblio-style<span style="color:#728e00">=</span><span style="color:#728e00">$(</span>csldir<span style="color:#728e00">)</span>/ACM-Reference-Format --bibliography<span style="color:#728e00">=</span>delphi.bib -t latex &gt; delphi.tex
xelatex delphi.tex
bibtex delphi
</code></pre></div><h3 id="templates">Templates</h3>
<p>You&rsquo;ll need both a <strong>Pandoc-specific</strong> template and a <strong>LaTeX-specific</strong> template. The latter is usually up for grabs at your favorite conference/journal submission website. For instance, at ACM-sponsored conferences, your <code>.tex</code> file usually starts with:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\documentclass</span><span style="color:#434f54">[sigconf]</span><span style="color:#728e00">{</span>acmart<span style="color:#728e00">}</span>
</code></pre></div><p>Meaning you&rsquo;ll need to have the file <code>acmart.cls</code> LaTeX class somewhere nearby. These files are automatically included in Overleaf after selecting the correct starting template. Right, nothing new here.</p>
<p>What is new, is the Pandoc template, called <code>acm-pandoc-conf.tex</code> in the above Makefile. This file adheres to Pandoc-specific syntax and allows you to fill in variables that are defined in the Frontmatter of Markdown files. The file will contain something like this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\documentclass</span><span style="color:#434f54">[sigconf,anonymous=$anonymous$]</span><span style="color:#728e00">{</span>acmart<span style="color:#728e00">}</span>
<span style="color:#95a5a6">% use packages, acm-specific commands, etc
</span><span style="color:#95a5a6"></span>
<span style="color:#7f8c8d">$</span><span style="color:#728e00">if</span><span style="color:#728e00">(</span><span style="color:#728e00">title</span><span style="color:#728e00">)</span><span style="color:#7f8c8d">$</span>
<span style="color:#728e00">\title</span><span style="color:#728e00">{</span><span style="color:#7f8c8d">$</span><span style="color:#728e00">title</span><span style="color:#7f8c8d">$</span><span style="color:#728e00">}</span>
<span style="color:#7f8c8d">$</span><span style="color:#728e00">endif</span><span style="color:#7f8c8d">$</span>
<span style="color:#7f8c8d">$</span><span style="color:#728e00">if</span><span style="color:#728e00">(</span><span style="color:#728e00">subtitle</span><span style="color:#728e00">)</span><span style="color:#7f8c8d">$</span>
<span style="color:#728e00">\subtitle</span><span style="color:#728e00">{</span><span style="color:#7f8c8d">$</span><span style="color:#728e00">subtitle</span><span style="color:#7f8c8d">$</span><span style="color:#728e00">}</span>
<span style="color:#7f8c8d">$</span><span style="color:#728e00">endif</span><span style="color:#7f8c8d">$</span>
<span style="color:#728e00">\maketitle</span>
<span style="color:#728e00">\bibliographystyle</span><span style="color:#728e00">{</span>ACM-Reference-Format<span style="color:#728e00">}</span>
<span style="color:#7f8c8d">$</span><span style="color:#728e00">body</span><span style="color:#7f8c8d">$</span>
<span style="color:#7f8c8d">$</span><span style="color:#728e00">if</span><span style="color:#728e00">(</span><span style="color:#728e00">bibliography</span><span style="color:#728e00">)</span><span style="color:#7f8c8d">$</span>
<span style="color:#728e00">\balance</span>
<span style="color:#728e00">\bibliography</span><span style="color:#728e00">{</span><span style="color:#7f8c8d">$</span><span style="color:#728e00">bibliography</span><span style="color:#7f8c8d">$</span><span style="color:#728e00">}</span>
<span style="color:#7f8c8d">$</span><span style="color:#728e00">endif</span><span style="color:#7f8c8d">$</span>
<span style="color:#728e00">\end</span><span style="color:#728e00">{</span>document<span style="color:#728e00">}</span>
<span style="color:#728e00">\endinput</span>
</code></pre></div><p>I published the full template as a <a href="https://gist.github.com/wgroeneveld/b6e2751c6da2a7bac73f668ddff5c3d0">GitHub gist</a>, in case anyone would like to reuse it.</p>
<p>Now, every <code>$var</code> sign will be auto-replaced with the corresponding key in your <code>.md</code> file. For example:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-md" data-lang="md">---
title: &#39;My Fancy Work&#39;
date: &#39;2019-07-16&#39;
anonymous: &#34;false&#34;
author:
<span style="color:#728e00">-</span> name: Wouter Groeneveld
institution: KU Leuven
orcid: https://orcid.org/0000-0001-5099-7177
city: Leuven
country: Belgium
email: wouter.groeneveld at university
<span style="color:#728e00">-</span> name: Other Guy
output: pdf_document
abstract: &#34;blah blah&#34;
published: true
bibliography: &#34;delphi&#34;
tags: [Publishing]
panflute-filters: [scientific-twocolumn-tables]
panflute-path: &#39;../../pandoc/filters&#39;
---
# INTRODUCTION
Knowledge of software development is becoming more and more important, as shortcomings in the software engineering workforce require companies to come up with creative solutions such as coding boot-camps, to initiate candidates into the wonderful world of programming. However, to be successful as a developer, it no longer suffices to be technically proficient [@garousi2019closing]. There is still no agreement on what separates a great developer from a good one, even if both the academic and industrial world are starting to acknowledge the need for something more besides cognitive knowledge, however good this might be [@capretz2017soft].
Software is first and foremost created by people, for people, hinting on the need for so-called &#39;_soft skills_&#39;, or, more generally, &#39;_non-cognitive abilities_&#39;, defined as the subset of abilities not related to technical skills.
</code></pre></div><p>This excerpt was taken from <a href="https://lirias.kuleuven.be/retrieve/549747/">my 2020 Delphi study</a>. Note the Section Header (<code>#</code>), easy way of citing (<code>[@key]</code>) and emphasizing terms (<code>_</code>). This gets compiled into the usual LaTex junk and you&rsquo;re off. You can make up as many variables as you&rsquo;d like, and also loop through things like multiple authors - see the full gist for more details.</p>
<h3 id="post-processing">Post-processing</h3>
<p>Did you notice the weird <code>panflute-filters</code> stuff? <a href="http://scorreia.com/software/panflute/">Panflute</a>, a Pandoc filter that makes Pandoc filters fun to write (according to the website), can be enabled with the <code>--filter panflute</code> flags after installing it as a Python 3 package. I use it to do the necessary post-processing on the generated Pandoc output - before it is made &ldquo;final&rdquo; as LaTex output. You can create custom hooks that lets you transform blocks, such as paragraphs, images, links, &hellip; This comes in handy when your conference works with a double-column template. Pandoc is not so keen on those, and you sometimes want to convert a figure into a double-column one, or the other way around: <code>\begin{figure}</code> to <code>\begin{figure*}</code> or something similar.</p>
<p>Of course, another way to do simple find and replace post-processing things is to just further transform the <code>.tex</code> output yourself using <code>sed</code> or whatever. This works, but is cumbersome, as sometimes you want to select specific blocks without resorting to artisan regular expressions that take hours to create. For something like <strong>tables</strong>, you&rsquo;d write the following Markdown:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-md" data-lang="md">blaaleft blaright
---------- -----------
something 9
something 10
Table: Demonstration of simple table syntax.
</code></pre></div><p>Pandoc by default generates something like this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\begin</span><span style="color:#728e00">{</span>longtable<span style="color:#728e00">}</span>[]<span style="color:#728e00">{</span>@<span style="color:#728e00">{}</span>lr@<span style="color:#728e00">{}}</span>
<span style="color:#728e00">\caption</span><span style="color:#728e00">{</span>Demonstration of simple table syntax.<span style="color:#728e00">}</span><span style="color:#728e00">\tabularnewline</span>
<span style="color:#728e00">\toprule</span>
blaaleft <span style="color:#728e00">&amp;</span> blaright<span style="color:#728e00">\tabularnewline</span>
<span style="color:#728e00">\midrule</span>
<span style="color:#728e00">\endfirsthead</span>
<span style="color:#728e00">\toprule</span>
blaaleft <span style="color:#728e00">&amp;</span> blaright<span style="color:#728e00">\tabularnewline</span>
<span style="color:#728e00">\midrule</span>
<span style="color:#728e00">\endhead</span>
something <span style="color:#728e00">&amp;</span> 9<span style="color:#728e00">\tabularnewline</span>
something <span style="color:#728e00">&amp;</span> 10<span style="color:#728e00">\tabularnewline</span>
<span style="color:#728e00">\bottomrule</span>
<span style="color:#728e00">\end</span><span style="color:#728e00">{</span>longtable<span style="color:#728e00">}</span>
</code></pre></div><p>With my filter, I managed to modify it to something like this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\begin</span><span style="color:#728e00">{</span>table<span style="color:#728e00">}</span>[h!]
<span style="color:#728e00">\centering</span>
<span style="color:#728e00">\caption</span><span style="color:#728e00">{</span>Demonstration of simple table syntax.<span style="color:#728e00">\label</span><span style="color:#728e00">{</span>table:Demonstration<span style="color:#728e00">_</span>of<span style="color:#728e00">_</span>sim<span style="color:#728e00">}}</span>
<span style="color:#728e00">\begin</span><span style="color:#728e00">{</span>tabular<span style="color:#728e00">}{</span>l r<span style="color:#728e00">}</span>
<span style="color:#728e00">\hline</span>
blaaleft <span style="color:#728e00">&amp;</span> blaright<span style="color:#728e00">\\</span> [0.5ex]
<span style="color:#728e00">\hline</span>
<span style="color:#728e00">\hline</span>
something <span style="color:#728e00">&amp;</span> 9<span style="color:#728e00">\tabularnewline</span>
something <span style="color:#728e00">&amp;</span> 10<span style="color:#728e00">\tabularnewline</span>
<span style="color:#728e00">\hline\end</span><span style="color:#728e00">{</span>tabular<span style="color:#728e00">}</span>
<span style="color:#728e00">\end</span><span style="color:#728e00">{</span>table<span style="color:#728e00">}</span>
</code></pre></div><p>Transforming the <code>longtable</code> into a <code>table</code> is simple enough, but this filter does more than that, as you can see. Passing in extra options as part of the <code>tabular</code> block is also possible. Inspect the full python file <a href="https://gist.github.com/wgroeneveld/9dbeb0d0b60c6cb5d8dfe9b938c5e94e">in this GitHub gist</a> (yes it&rsquo;s a bit messy). A word of warning: Panflute&rsquo;s latest version is a bit experimental and might not be compatible with the latest Pandoc release.</p>
<h3 id="other-nasty-stuff">Other nasty stuff</h3>
<p>In essence, I try to remove as much markup-specific syntax as possible by letting the templates do their thing. Now and then, this is simply not possible, especially for complicated formulas or tables. If all else fails, it is still possible to combine both languages and embed LaTeX inside your Markdown file. Use this as your last resort.</p>
<p>I also usually create a <code>preamble.tex</code> file that contains the necessary metadata for the conference, such as the ACM taxonomy, and a few extra TeX package includes. Furthermore, they&rsquo;re also handy when customizing standardized blocks, such as quotes in Markdown, prepended with <code>&gt;</code>. The package <code>etoolbox</code> allows you to customize these using something like:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\AtBeginEnvironment</span><span style="color:#728e00">{</span>quote<span style="color:#728e00">}{</span><span style="color:#728e00">\begin</span><span style="color:#728e00">{</span>tcolorbox<span style="color:#728e00">}</span>[leftrule=2mm,bottomrule=0mm,toprule=0mm,rightrule=0mm,boxsep=0mm,grow to right by=-3mm, grow to left by=-3mm]<span style="color:#728e00">\small</span><span style="color:#728e00">}</span>
<span style="color:#728e00">\AtEndEnvironment</span><span style="color:#728e00">{</span>quote<span style="color:#728e00">}{</span> <span style="color:#728e00">\end</span><span style="color:#728e00">{</span>tcolorbox<span style="color:#728e00">}}</span>
</code></pre></div><p>Remember, the less clutter in your Markdown, the less strain for your eyes! I also know people who write most of their stuff in Markdown, convert it into TeX using Pandoc, and then copy over the compiled garbage into Overleaf to continue and chip away at it together with others. Of course, you can also simply check in your <code>.md</code> source files and use Git to collaborate, although without something like Overleaf, your CI server - and preferably also yourself - will have to install the required build toolchain.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 14 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>You Shouldn&#39;t Use Spotify</title>
<link>https://brainbaking.com/post/2021/02/you-shouldnt-use-spotify/</link>
<comments>https://brainbaking.com/post/2021/02/you-shouldnt-use-spotify/#commento</comments>
<pubDate>Tue, 09 Feb 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/02/you-shouldnt-use-spotify/</guid>
<category domain="https://brainbaking.com/tags/music">music</category>
<description>
<![CDATA[
<p>Ruben Schade recently posted on his lovely micro-blog <a href="https://rubenerd.com/">Rubenerd</a> that <a href="https://rubenerd.com/going-to-shadu/">you shouldn&rsquo;t use Spotify</a>. That was new to me. I&rsquo;ve been a (paid) Spotify user since 2014, but I honestly never focused my critical thinking on why it is or is not a good service. I was intrigued by that short sentence, that was hastily mentioned without any context. So I started digging.</p>
<h2 id="part-i-streaming-or-downloading">Part I: Streaming or Downloading</h2>
<p>I&rsquo;ve never been an audiophile, and I probably never will be, but I like the idea of spending money wisely. Back in the day, in late nineties and early 2000s, I loved browsing CD stores to buy the latest Wu-Tang <em>shizzle</em> (yeah, I was that kind of guy) and maybe spot other interesting hip-hop stuff I never heard of before. But let&rsquo;s be completely honest here: who didn&rsquo;t primarily Napster/Limewire/Newsgroup/whatever music? Guilty as charged - my ridiculously small amount of pocket money was reserved for Game Boy games. Fast forward ten years, five iterations of iPods and Creative Zen <code>mp3</code> players, and we arrive at the wonderful world of <em>streaming music</em> instead of <em>downloading</em> it. Your disk will be grateful.</p>
<p>But your favorite music band won&rsquo;t be. According to <a href="https://www.theguardian.com/technology/2015/apr/03/how-much-musicians-make-spotify-itunes-youtube">The Guardian</a> and the <em>Information is Beautiful</em> infographic, a musician receives on average <code>$0.001128</code> every time you listen to a track. In practice, things aren&rsquo;t that simple, as Spotify (as almost every other streaming music provider) employs a <strong>pro rata</strong> payout model. The more sites and papers I read about this<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, the more confused I become. As far as I understand it, it goes something like this: when all I listen to is 2Pac, and I pay <code>€10</code>/month, a portion of my own money still goes to 2Pac&rsquo;s archenemy the Notorios B.I.G. - even though I did not actively &ldquo;support&rdquo; him.</p>
<p><a href="https://informationisbeautiful.net/visualizations/spotify-apple-music-tidal-music-streaming-services-royalty-rates-compared/">Information is Beautiful</a> goes even further by adding metadata, such as the number of plays needed to earn minimum wage, amount of free users for each streaming service, and so on. A musician needs to hit <code>336k</code> plays before earning <code>$1.472</code> (without taking any costs into account). When I try to compare this to a bought CD (I&rsquo;m treading on thin ice here), say <code>€15</code> for a CD with 15 tracks or <code>€1</code> per track, of which the artist would get for instance <code>23%</code> (See <a href="https://www.theguardian.com/technology/2015/apr/03/how-much-musicians-make-spotify-itunes-youtube">The Guardian</a> figure). That means <code>6400</code> per track. But since you can&rsquo;t buy a single one (usually, for a physical album), all that is needed to hit the minimum wage is <code>427</code> CD sales.</p>
<p>The difference is ridiculous. Simply staggering. I implore you to take a look at the aforementioned infographics. Yet, <code>23%</code> for a physical CD sale is still disappointing. Luckily, <a href="https://bandcamp.com/fair_trade_music_policy">Bandcamp</a> only takes <code>15%</code> and enables artists to publish their work without having to rely on a physical medium, or even a label company. That same CD, maybe now sold for only <code>€10</code> because it&rsquo;s digital, only needs <code>116</code> sales before reaching the threshold.</p>
<p>There are <a href="https://radarradio.net/blog/why-i-dont-use-spotify">many blog posts</a> entitled <em>&ldquo;why I don&rsquo;t use Spotify&rdquo;</em>, and there are just as many statements from streaming companies claiming that comparing streaming with buying is like comparing apples with oranges. And they are probably both right. Still, it breaks my heart that I used to think that streaming <a href="https://switchstancerecordings.bandcamp.com/album/into-bass-and-time">Into Bass and Time</a> from Ancient Astronauts would support the guys. It does, but barely. And my hard-earned money also ends up in the pockets of other artists.</p>
<p>Spotify used to stream pirated copies of music based on peer-to-peer networks. Only after a few years, they started &ldquo;sobering up&rdquo;, but still proudly claim that streaming music (on a free account) is the best alternative to illegally downloading music - and it seems to really <a href="https://www.engadget.com/2015-10-28-spotify-piracy-study.html">slightly reduce piracy</a> - but at a (steep) cost.</p>
<h2 id="part-ii-consumers-critical-thinking">Part II: Consumers' Critical Thinking</h2>
<p>Sometimes, I think that <em>critical thinking</em> every single second in your live on every single thing you do (or do not do) can be very, very tiresome. I have to think critically when at work, when buying groceries at the store, when buying a new laptop, when looking in the fridge and cooking, and apparently, also when putting on some music.</p>
<p>That got me thinking (urgh). Why does our society provide options that are decidedly <strong>unfair</strong>?<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> If there was only Fair Trade chocolate in the supermarket, I couldn&rsquo;t buy stuff that exploits African farmers. If there was only the option to buy from a fair streaming service, I wouldn&rsquo;t need to fry my brains trying to trace my subscription money. Granted, it is very frustrating to see so many big companies who are <em>not</em> as transparent as for instance Bandcamp&rsquo;s open policy.</p>
<p>The same is true for games. Do I buy them on Steam or Good Old Games? Should I wait for a <a href="https://www.humblebundle.com/about?hmb_source=navbar">Humble Bundle</a> that also donates to charities? Do the developers offer a way to directly buy from them?</p>
<p>The same is true for books. Did you know that on average, the profit margin of a physical book is less than <code>10%</code>? I earn about <code>€3</code> for each sale, and my book costs <code>€28.50</code>. Of course, <a href="https://www.bookdepository.com/">The Book Depository</a> and Amazon put even more pressure on that retail price and even dare to undercut the market (which is <a href="https://www.boekenprijs.be/over-site">illegal in Belgium</a>). Fabian Sanglard&rsquo;s <a href="https://fabiensanglard.net/gebbdoom/">Doom Game Engine Book</a> fares off much worse: <code>$1.59</code> of the <code>$54</code> goes to him. Luckily, he told me that many people make great use of the Paypal donate button. The only <em>fair</em> publisher I know of is <a href="https://pragprog.com/become-an-author/">The Pragmatic Bookshelf</a>, which state they pay out a royalty of <code>50%</code>. <em>&ldquo;Far more than the industry standards&rdquo;</em>. Indeed.</p>
<p><figure>
<a href="../profit.jpg" class="lbox">
<img loading="lazy" src="../profit.jpg" title="A simplified breakdown of my book profit margin. ">
</a>
<figcaption>A simplified breakdown of my book profit margin. </figcaption>
</figure>
</p>
<p>That got me thinking again (it&rsquo;s starting to hurt). Why are many <strong>artists</strong> - that create original, creative material, in some way or another - mistreated in our society? David Graeber&rsquo;s <a href="/post/2020/12/thoughts-on-bullshit-jobs/">Bullshit Jobs</a> also talks about this. Service jobs (Hello consultants and lawyers) earn millions, while many artists struggle to survive. Granted, even though Taylor Swift <a href="https://www.rollingstone.com/music/music-news/taylor-swift-abruptly-pulls-entire-catalog-from-spotify-55523/">pulled her songs</a> from Spotify in 2014 (and re-uploaded them later&hellip;), I highly doubt she&rsquo;s struggling - but many small artists are. I&rsquo;d love to be a full-time writer, but it is hardly feasible when writing about obscure subjects in a language other than English.</p>
<h2 id="why-i-sometimes-do-use-spotify">Why I sometimes do use Spotify</h2>
<p><em>Serendipity</em>. <em>Deliberate Discovery</em>. Browsing, having stuff suggested, listening to a few songs, and jumping to Bandcamp to buy the album. That last part is crucial, and I hope by now you know why. Sometimes, it does pay off to be a critical thinker.</p>
<p>Thanks, Ruben.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p><a href="https://repositories.lib.utexas.edu/bitstream/handle/2152/75450/gierharthunter_Thesis_How%20the%20Spotify%20Streaming%20Model%20Affects%20the%20Modern%20American%20Musician_2019.pdf?sequence=1&amp;isAllowed=y">Hunter Gierhar&rsquo;ts thesis</a> on <em>How the Spotify StreamingModel Affects the Modern American Musician</em> was especially interesting. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>The answer is capitalism. Everyone wants <em>free stuff</em>, and when they can&rsquo;t, they want the cheapest option, thereby forgetting to pay the creator. <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 9 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>My Retro Desk/Gaming Setup in 2021</title>
<link>https://brainbaking.com/post/2021/02/my-retro-desktop-setup/</link>
<comments>https://brainbaking.com/post/2021/02/my-retro-desktop-setup/#commento</comments>
<pubDate>Tue, 02 Feb 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/02/my-retro-desktop-setup/</guid>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>Thanks to my resurgent interest in retro computing, I discovered others' setups and blogs that inspired me to completely rework my home office. Of course, COVID-19 also made sure I invested in better office equipment at home. Well, <em>better</em> is subjective. It will never be as cool as <a href="https://www.bytecellar.com/photo_pano.html">The Byte Cellar</a>: I simply don&rsquo;t have the space (nor permission from my wife; nor the nostalgic connection with many older machines). &ldquo;<a href="https://www.resetera.com/threads/post-your-gaming-setup-2021-edition.354757/">Post your gaming setup</a>&rdquo; is a yearly tradition at the <a href="https://www.resetera.com/">ResetEra</a> forums, but the Reset community is mainly a next-generation console-centered one that showcases mostly shiny TVs in living rooms.</p>
<p>Still, I always feel a bit inspired flicking through photos of others' setups - so why not post my own that hopefully does the same. Inevitably, IKEA made some money in the progress. I&rsquo;ve looked at alternatives, but none are as ecological (the desk is made of recycled paper honeycomb) or as cheap as what IKEA offers. Searching on the net for &ldquo;<a href="https://duckduckgo.com/?q=ikea+linnmon+gaming&amp;t=ffab&amp;iar=images&amp;iax=images&amp;ia=images">ikea linnmon gaming</a>&rdquo; results in more inspiration material I dutifully stole some ideas from. Right, so here goes.</p>
<h2 id="an-overview">An overview</h2>
<p><figure>
<a href="../desk_overview.jpg" class="lbox">
<img loading="lazy" src="../desk_overview.jpg" title="The desk setup: an overview.">
</a>
<figcaption>The desk setup: an overview.</figcaption>
</figure>
</p>
<p>The room is small, so fitting in as much stuff as possible while still feeling spacious and calming was one of the main goals. The LINNMON desk is <code>60cm</code> deep, so installing an old CRT screen was sadly out of the question, unless I positioned it in a corner - which was already being occupied by my WinXP horizontal case (that allows for convenient cable hiding). I really wanted a nice curving corner desk especially for that. In the end, the setup consists of three pieces of LINNMON: one <code>1m</code> straight piece (to the left), one corner piece, and one <code>1.2m</code> straight piece (to the right).</p>
<p>Another priority was <em>cable management</em>. I hate the sight of cable clutter - or any sort of clutter, come to think of it. It prevents my mind from entering a clear and peaceful state where I can think straight. Beneath every piece of desk, I installed cable raceways, and I paid special attention to which cable should go to where. The switch was also taped upside-down to the center piece, to keep Ethernet cables out of sight as much as possible. All three parts have one single power strip that feed all electrical devices, and keep things separated. Let&rsquo;s take a closer look at what&rsquo;s installed.</p>
<h2 id="zoomed-in">Zoomed In</h2>
<h3 id="1-left-the-486-machine">1. Left: The 486 machine</h3>
<p><figure>
<a href="../desk_486.jpg" class="lbox">
<img loading="lazy" src="../desk_486.jpg" title="Zoomed in on the 80486.">
</a>
<figcaption>Zoomed in on the 80486.</figcaption>
</figure>
</p>
<p>Next to the doorway, we have the least amount of space. I would love to get a decent CRT screen coupled with <a href="/post/2020/09/reviving-a-80486/">my 486 machine</a>, but space constraints make this impossible. The <code>17&quot;</code> DELL screen does an okay job at displaying old VESA CGA/VGA resolutions, but it&rsquo;s far from great. At least now everything fits nicely. As a big fan of the original <a href="https://en.wikipedia.org/wiki/The_Secret_of_Monkey_Island">Monkey Island</a> games, I framed the cover art (printed as high quality posters), that blends perfectly with the 1990s retro theme.</p>
<p>In the above photo, it&rsquo;s a bit hard to see, but this setup already mixes old (the obvious 486) with new (the newer LCD screen, the <a href="/post/2020/09/486-upgrade-sd-hdd/">SD card based HDD</a> mod, and the <a href="http://localhost:1313/post/2020/09/486-upgrade-sound-blaster/">S2 wavetable board</a>). I especially love the mechanical old keyboard, which was taken apart and thoroughly cleaned a couple of months ago. Things still on the wish list: a set of original Roland speakers, and of course a Roland <a href="https://en.wikipedia.org/wiki/Roland_MT-32">MT-32 MIDI syntheziser</a> or one of the more recent <a href="https://en.wikipedia.org/wiki/Roland_Sound_Canvas">Sound Canvas</a> devices.</p>
<h3 id="2-middle-the-win98xp-machines">2. Middle: The Win98/XP machines</h3>
<p><figure>
<a href="../desk_win98.jpg" class="lbox">
<img loading="lazy" src="../desk_win98.jpg" title="Zoomed in on the Win98/WinXP setup.">
</a>
<figcaption>Zoomed in on the Win98/WinXP setup.</figcaption>
</figure>
</p>
<p>Here, again the space saving strategy is clearly visible: there&rsquo;s only one screen, the DELL UltraSharp 2007WFP I bought in 2007. The screen can handle VGA, DVI, S-Video and composite, and you can change input channels through the menu system. <a href="/post/2020/10/building-a-core2duo-winxp-retro-pc/">My WinXP machine</a> is setup for DVI, while <a href="/post/2020/10/building-an-athlon-win98-retro-pc/">my Win98SE machine</a> still relies on the good ol' analog VGA cable. I loved that Antec horizontal case back in the day because I could shove it under my drawer set, mounted and hanging on the desk backside.</p>
<p>Only having one physical location for both PCs does have some downsides: I had to buy an USB2 hub that allows me to quickly switch using keyboard and mouse from one PC to the next. Since the Win98 USB drivers aren&rsquo;t great, this was a bit of a pain to get working. Luckily, it&rsquo;s quite effortless now! The only thing that is still left to do is to make a simple analog audio mixer that allows me to use one set of speakers for both machines. Replugging cables is not much fun.</p>
<p>What <em>is</em> much fun, though, is classic 1999-style case modding: I tore apart the old AOpen classic beige PC midi tower with a whipsaw, bought a couple of 5/12V led strips, and put in a piece of plexiglass. The intention is to do the same for the 486. The reason why the towers are positioned like that is, again, space constraints, but now I can also show off the actual retro hardware! Bonus points for those who can guess which game is running (on Win98).</p>
<h3 id="3-right-the-macbook-air">3. Right: The MacBook Air</h3>
<p><figure>
<a href="../desk_mac.jpg" class="lbox">
<img loading="lazy" src="../desk_mac.jpg" title="The &#39;work&#39; corner: a MacBook and recent screen.">
</a>
<figcaption>The &#39;work&#39; corner: a MacBook and recent screen.</figcaption>
</figure>
 
On to the <em>work corner</em>, where I employed a minimalistic strategy that relies on a cool <a href="https://www.dell.com/en-us/work/shop/dell-ultrasharp-usb-c-hub-monitor-u2421e/apd/210-axmg/monitors-monitor-accessories">DELL UltraSharp U2421E</a> USB-C Hub Monitor and the <a href="https://www.twelvesouth.com/products/magicbridge">TwelveSouth MagicBridge</a> that marries the Apple Keyboard with the Trackpad. I bought the monitor last month and I&rsquo;m extremely pleased with it: it eliminates the need of an external hub <em>and</em> it eliminates the need to have an untidy power cable lying around, as it also charges through USB-C. Furthermore, you can even plug in an Ethernet cable - which I did - that allows for a more stable Internet connection. Working on <a href="/post/2020/12/developing-on-apple-m1-silicon/">my M1 MacBook Air</a> was never that satisfying. Unfortunately, the <code>24&quot;</code> DELL screen isn&rsquo;t the best in terms of pixel intensity, especially compared to the native screen of the Mac. Those specialized screens were much, much more expensive.</p>
<p>On top of the Win98 tower, you can spot an AirPlay-enabled Pioneer XW-SMA4-K from 2009 that&rsquo;s also connected to the switch. I&rsquo;ve had problems with streaming music to it because of the unstable WiFi signal and the slow WiFi receiver from my previous MacBook. A Stereo Jack plug works, but introduces another cable, and removes the biggest advantage of this setup: when I want to physically move my laptop to my lap in the comfy chair (see below), the music stops. The box is mainly used to stream music while working from home - to great frustration of my wife.</p>
<p>I also plan to connect the last piece of retro hardware, the Nintendo GameCube, to the screen using a <a href="https://www.eongaming.tech/product-page/gchd-mk-ii-rgblack">GCHD MK-II</a> HDMI adapter - the video signal of the laptop goes through USB-C. The only stupid mistake I made a couple of years ago was to sell of a large portion of my GameCube collection, including the amazing wireless WaveBird controller&hellip;</p>
<h2 id="the-book-wall">The Book Wall</h2>
<p><figure>
<a href="../desk_reverse.jpg" class="lbox">
<img loading="lazy" src="../desk_reverse.jpg" title="The other side of the wall: my mini-library.">
</a>
<figcaption>The other side of the wall: my mini-library.</figcaption>
</figure>
</p>
<p>When you turn your back to the retro crazyness, you will see a few bookcases and a cozy chair (Note the 486 keyboard in the lower right). The intention was to comfortably play on the GameCube from the chair, but <code>24&quot;</code> is a tad too small for that. I decided against buying a <code>27&quot;</code> screen, as that would be too big for the limited depth of the LINNMON setup. Thanks to COVID, the chair (yup, also IKEA) sees a lot of use when my back hurts because of that cheap IKEA office chair I still need to replace.</p>
<p>On the shelves, I keep a happy mix-mash of our non-fiction books, which is only a portion of what we have. I love being around books, so naturally, they had to be present. Those who look well enough will discover a few Magic: The Gathering boxes I couldn&rsquo;t fit in our boardgame closet - someday, we should sell some stuff&hellip;</p>
<h2 id="wait-i-sense-something-is-missing">Wait, I sense something is missing!</h2>
<p>Your senses would not be misleading you! My relished Game Boy (Color/Advance) and Nintendo (3)DS collection currently resides in multiple other rooms, scattered around the house. There wasn&rsquo;t enough room to show off dozens of plastic cases. Future work might include mounting simple shelves against the wall below the skylight. They do not need to be very sturdy so it shouldn&rsquo;t take up that much extra space.</p>
<p>The retro big box PC games and the Nintendo GameCube miniDVDs I still own are tucked away in the cabinet behind the reading chair. I sadly don&rsquo;t own that many anymore: moving three times didn&rsquo;t help in preserving these. Most of my retro PC collection nowadays consists of <a href="https://gog.com">gog.com</a> downloads, which is a bit of a pain to get up and running on older operating systems because of the Windows 10 installer. As for the Nintendo SNES cartridges and more recent Nintendo Switch games, they are of course kept in a drawer close to the TV, as both machines are connected to a screen in our living room.</p>
<p>I also have a mini SNES and mini PS1 lying around somewhere, but due to lack of HDMI ports on the TV, they don&rsquo;t see much use. That was another reason why I wanted that GameCube in my retro room. There are only so many consoles (and games) you can devote your time to, and I&rsquo;ve always been more of a PC and handheld gamer myself.</p>
<p>If there is anything you&rsquo;d like more specifications of, just let me know!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 2 February 2021.
</p>
]]>
</description>
</item>
<item>
<title>Win98 Upgrade: GeForce 3 Ti200 vs Riva TNT2</title>
<link>https://brainbaking.com/post/2021/01/win98-upgrade-geforce3/</link>
<comments>https://brainbaking.com/post/2021/01/win98-upgrade-geforce3/#commento</comments>
<pubDate>Thu, 28 Jan 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/01/win98-upgrade-geforce3/</guid>
<category domain="https://brainbaking.com/tags/geforce">geforce</category>
<category domain="https://brainbaking.com/tags/win98">win98</category>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/geforce3.jpg"/>
</p>
<p>After building a <a href="/post/2020/10/building-an-athlon-win98-retro-pc">Windows 98SE retro PC</a> in October 2020, I&rsquo;ve upgraded the sound card to a proper <a href="/tags/soundblaster">SoundBlaster</a>. Yet, little games made use of that capability because my graphics card lagged behind. The PC slotted a OEM version of a Riva TNT2 M64 card with <code>32MB</code> SD RAM. The chip has a sticker called <em>&ldquo;Sparkle&rdquo;</em> on it, but it sure wasn&rsquo;t sparkling that much as soon as I booted Unreal Tournament. So, the only logical conclusion to make was to do another upgrade.</p>
<p>What are the options? During the end of the nineties and the beginning of the 2000s, the video card market exploded. From dual-linked Voodoo cards on PCI ports to competitive ATI Radeon ones that also were quite new at that time. I had two options: either I stay true to the historical correctness of the retro computer, or I go all out and get the best my motherboard could possibly handle. I of course chose option number 3: something in-between.</p>
<h2 id="the-geforce-3-ti-200">The GeForce 3 Ti 200</h2>
<p><figure>
<a href="../geforce3.jpg" class="lbox">
<img loading="lazy" src="../geforce3.jpg" title="The MSI/Medion GeForce 3 Ti200 card.">
</a>
<figcaption>The MSI/Medion GeForce 3 Ti200 card.</figcaption>
</figure>
</p>
<p>The third generation of Nvidia&rsquo;s GeForce graphics processing units, the GeForce 3, was released in the beginning of 2001. I&rsquo;m pretty sure most people by then had moved on from Windows 98 to (hopefully) Windows 2000 - thereby safely sidestepping the disaster that Windows Me (or Millennium) was. Compared to the Riva TNT2, a chip also by Nvidia from early 1999, the GeForce 3 cards were beasts - yet only two years passed since the TNT2 release!</p>
<p>The TNT2 was never intended to be a big performer: the 1998 3Dfx Voodoo 2 and Voodoo 3 outperformed it in certain games. That is because the graphics APIs were not yet fully matured: you had your <strong>Glide</strong> drivers, that worked well with 3Dfx cards, your <strong>OpenGL</strong> ones, and Microsoft <strong>Direct3D</strong>. Some games could be patched to work better with a particular API, but most were pretty hard-wired. As a gamer with a Voodoo card, you&rsquo;d be forced to also periodically upgrade your AGP slot if you wanted access to all games. The Voodoo cards slotted in PCI ports, meaning you could mix and match, or even run them in SLI, a popular configuration in the Retro PC scene at <a href="https://vogons.org">VOGONS</a>. That is, if you&rsquo;re prepared to drop more than <code>€140</code> a piece - <a href="https://www.benl.ebay.be/sch/i.html?_from=R40&amp;_trksid=m570.l1313&amp;_nkw=voodoo+2&amp;_sacat=0">even nowadays</a>.</p>
<p>I have fond memories of the floating 3Dfx logo. I remember my dad flashing our Voodoo card in order to overclock it, an attempt that ended with smoke coming out of a capacitor. We brought it back to the store, and when the guy behind the counter asked whether or not we flashed the thing, my dad said &ldquo;of course not!&rdquo;. We promptly got a new one. However, until I can get hold of a Voodoo card at a fair price, I decided to resort to Nvidia&rsquo;s budget version of the GeForce 3 instead, that I found for only <code>€30</code>. The Ti 200 was basically a pumped-up GeForce 2 with <code>64MB</code> and a clock rate of <code>200MHz</code>. To me, it felt a bit more historically accurate compared to a high-end Ti 500 - although you can <a href="https://www.philscomputerlab.com/geforce3-ti-200.html">overclock the card</a> by adding active cooling. As a fan of <em>silent</em> PCs, I was keen on keeping the cooling as passive as possible. The result is a massive (well, for that time) black block on top of the GPU:</p>
<p><figure>
<a href="../geforcevsriva.jpg" class="lbox">
<img loading="lazy" src="../geforcevsriva.jpg" title="The GeForce 3 (left) compared to the TNT2 (right).">
</a>
<figcaption>The GeForce 3 (left) compared to the TNT2 (right).</figcaption>
</figure>
</p>
<p>Note that the GeForce3 has multiple video-out ports: a VGA one and an S-Video one - of course both still analog. Fitting the card inside your case can be a bit challenging if you didn&rsquo;t do proper cable management (whoops), as it&rsquo;s both longer and higher than its predecessor. My card was branded <em>MEDION</em> (by the German supermarket <em>ALDI</em>), but it&rsquo;s essential an <em>MSI</em>, so I don&rsquo;t care. It probably came from one of those cheap (but pretty good) MEDION computer builds. I got it from a friendly German IT parts recycler at eBay.</p>
<h2 id="performance">Performance</h2>
<p>Okay, let&rsquo;s see what happens after pulling out a screwdriver and replacing the TNT2. Windows 98SE still booted - that&rsquo;s a start. Of course, it does not recognize the card and reverts to 16-color mode. After digging up the right Nvidia driver set (and installing DirectX 9), rebooting a couple of times, it was time to play some games. I failed to find any &ldquo;GeForce3 VS TNT2&rdquo; articles on the internet that compare FPS stats, so I recorded a few of my own.</p>
<h3 id="dungeon-siege">Dungeon Siege</h3>
<p><a href="https://jefklakscodex.com/articles/reviews/dungeon-siege/">Dungeon Siege</a>, released by Gas Powered Games in 2002, is one of the first <a href="https://jefklakscodex.com/articles/features/the-best-and-worst-retro-hack-and-slash-games/">hack &amp; slash</a> games that was rendered in full 3D. This of course put quite a strain on PCs back then. Since I was replaying old H&amp;S games, and this one was released a year after the Ti200, it was a good candidate for a first stress test.</p>
<p><figure>
<a href="/post/2020/11/furyseye.jpg" class="lbox">
<img loading="lazy" src="/post/2020/11/furyseye.jpg" title="Dungeon Siege">
</a>
<figcaption>Dungeon Siege</figcaption>
</figure>
</p>
<p>To be honest, the game was unplayable with the Riva TNT2: it barely managed to pull off rendering <code>7</code> to <code>8</code> frames each second. I had to resort to my <a href="/post/2020/10/building-a-core2duo-winxp-retro-pc/">Windows XP build</a> to play it, before upgrading the graphics card, where it of course comfortably peaked at <code>60</code> FPS at a resolution of <code>1024x768</code> and every setting configured to high. The GeForce 3 fared much better than the TNT2: from <code>8</code> FPS to a whopping <code>23</code> in the midst of a heavy battle with spells flying all over the place. Remember, Generation Z kids: back then, if we got more than <code>15</code> FPS, we played it and did not complain. I wandered around in the swamps for a bit, and traveled to the Goblin-infested fortress, without major hickups, although the occasional dip in frames is still there.</p>
<h3 id="unreal-tournament">Unreal Tournament</h3>
<p>UT1, released in November 1999, was more interesting to test, because it supports multiple graphics APIs due to its launch in the midst of the &ldquo;AGP war&rdquo;. The Glide drivers are supposed to be good, but I cannot verify that. I can, however, try out a bunch of different options with both TNT2 and GeForce3 cards. Below is a summary of my findings (all details are set to <em>high</em> with skin to <em>medium</em>; resolution is always <code>1024x768</code>):</p>
<p><strong>Riva TNT2 M64</strong>:</p>
<ul>
<li><code>16bpp</code> (bits per pixel); Direct3D (default): <code>28</code> FPS</li>
<li><code>32bpp</code>; Direct3D: <code>14</code> FPS</li>
<li><code>32bpp</code>; OpenGL: <em>crash!</em> (whoops)</li>
</ul>
<p><strong>GeForce 3 Ti 200</strong>:</p>
<ul>
<li><code>16bpp</code>; Direct3D: <code>30</code> FPS</li>
<li><code>32bpp</code>; Direct3D: <code>15</code> FPS</li>
<li><code>32bpp</code>; OpenGL: <code>74</code> FPS</li>
</ul>
<p>These statistics were gathered using Fraps in the same multiplayer map, with the same weapon and the same movements/location. Strangely enough, Direct3D was no friend of the GeForce 3: the amount of FPS is virtually identical? I did install the latest UT1 patches, but it could very well be that I overlooked something. It was only after switching to OpenGL that I noticed a major performance boost. Messing with color depth is dangerous on the TNT2, it seems.</p>
<h3 id="wizardry-8">Wizardry 8</h3>
<p>As I mentioned in the original <a href="/post/2020/10/building-an-athlon-win98-retro-pc">Win98SE article</a>: the first thing I did after the video/audio drivers was of course installing <a href="https://jefklakscodex.com/tags/wizardry8/">Wizardry 8</a>, my all-time favorite PC RPG, released in 2001.</p>
<p><figure>
<a href="../wiz8.jpg" class="lbox">
<img loading="lazy" src="../wiz8.jpg" title="Wizardry 8: stranded on a beach, dangerous crabs nearby!">
</a>
<figcaption>Wizardry 8: stranded on a beach, dangerous crabs nearby!</figcaption>
</figure>
</p>
<p>Wiz8 was never the prettiest game of them all, and its development was riddled with more than a few hickups and tumbles. Sadly, Sir-Tech Canada eventually closed doors, so an official sequel is out of the question. There aren&rsquo;t a lot of graphics options to play with, and after choosing the OpenGL API drivers, all I can say is that both cards pull of rendering scenes in Wizardry 8 quite well. In and around the monastery, the begin location of the party, The TNT2 pushes frames to <code>19</code> FPS, while the GeForce 3 almost quadruples this to <code>75</code> FPS. Since this is not an action-packed frenetic shooting gallery, like Quake 3 or Unreal Tournament are, having semi-low frames is something you don&rsquo;t even notice. It played fine on the TNT2, and it plays fine on the GeForce 3.</p>
<h2 id="so-was-it-worth-it">So, was it worth it?</h2>
<p>That depends. If you&rsquo;re like me, and prefer RPG and turn-based games to shooters, then probably not so much. Yet, I liked being able to play Dungeon Siege on Windows 98 rather than Windows XP. It felt more authentic. The hack &amp; slash game Sacred deserves the WinXP machine since that game is from 2004: the mid-2000s, not the early ones.</p>
<p>The card is cheap, silent, the installation is painless, and I can finally attempt to reinstall my favorite Grand Theft Auto version: GTA Vice City, released in 2002. We&rsquo;ll see how the game fares with the card - or how the card fares with the game&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 28 January 2021.
</p>
]]>
</description>
</item>
<item>
<title>What is Creativity in Software Engineering?</title>
<link>https://brainbaking.com/post/2021/01/what-is-creativity-in-software-engineering/</link>
<comments>https://brainbaking.com/post/2021/01/what-is-creativity-in-software-engineering/#commento</comments>
<pubDate>Wed, 20 Jan 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/01/what-is-creativity-in-software-engineering/</guid>
<category domain="https://brainbaking.com/tags/creativity">creativity</category>
<category domain="https://brainbaking.com/tags/phd">phd</category>
<description>
<![CDATA[
<p>Last month, our paper entitled <em>&ldquo;Exploring the Role of Creativity in Software Engineering&rdquo;</em> got accepted for publication in the proceedings of the 43nd International Conference on Software Engineering: <a href="https://conf.researchr.org/track/icse-2021/icse-2021-Software-Engineering-in-Society">Software Engineering in Society</a> (ICSE-SEIS). Read the <a href="https://arxiv.org/abs/2101.00837">pre-print paper here</a>. In this article, I&rsquo;d like to summarize and rephrase our findings, since academic prose can be a bit&hellip; well&hellip; you know.</p>
<h2 id="why-the-sudden-interest-in-creativity">Why the sudden interest in creativity?</h2>
<p>Good question. In my PhD work, I try to identify - and later on, hopefully amplify - so-called <em>non-technical</em> skills that are needed to succeed as a software engineer. First of all, software engineering is my field of expertise: read the <a href="/about">about me</a> page if you didn&rsquo;t know that yet. Secondly, I wondered what else besides the technical mumbo-jumbo one really has to master in order to be a <em>proper</em> developer. This goes beyond programming languages, frameworks, typing and productivity knowledge.</p>
<p>In the previous years, I&rsquo;ve worked on:</p>
<ol>
<li>Trying to come up with a list of skills that are important, according to experts in the field;</li>
<li>Trying to come up with a list of skills currently taught in higher education;</li>
<li>Trying to match these and narrow down the results to reveal the biggest skill gap.</li>
</ol>
<p>Guess what. Creativity was in the top 3. But the more papers I read about the topic (of which surprisingly little specifically for software development!), and the more people I talked to, the less easily &ldquo;creativity&rdquo; could be defined. Hence the effort to facilitate a focus group, where 33 experts in 4 groups talked about their personal experience on the subject at hand.</p>
<p>I wrote about programming as a <a href="/post/2019/10/creative-cognitive-processes/">creative cognitive process</a> before, and tried to link the different existing frameworks out there. Most were too theoretical or contained too little context to be able to relate to practical software development. This time, we wanted to validate our thoughts by involving others.</p>
<h2 id="dimensions-of-creative-problem-solving">Dimensions of Creative Problem Solving</h2>
<p>After plowing through <code>399</code> lovely minutes of discussion, applying the needed qualitative tactics and methods, we came up with 7 main themes that, according to our interviewees, define creativity in the world of (agile/enterprise) software development. The paper contains much more details surrounding these, I merely try to summarize in this blog post.</p>
<p><figure>
<a href="../creativity-mindmap.jpg" class="lbox">
<img loading="lazy" src="../creativity-mindmap.jpg" title="A mind map of the 7 identified themes of creativity in software engineering.">
</a>
<figcaption>A mind map of the 7 identified themes of creativity in software engineering.</figcaption>
</figure>
</p>
<p>We did our best to be as specific as possible, using the wording of the participants as much as possible, but generalizations of course are bound to be made at some point in time. Also, instead of going for a vague term like &ldquo;creativity&rdquo;, we always talked <strong>in context of a programming problem</strong>. That is why the center states &ldquo;creative problem solving&rdquo; rather than &ldquo;creativity&rdquo;. Someone said:</p>
<blockquote>
<p>Creativity simply arises when you are solving a problem.</p>
</blockquote>
<p>Existing literature has proven before that creativity is context-dependent. Whether or not it&rsquo;s also domain-dependent is still an on-going debate.</p>
<h3 id="1-creative-techniques">1. Creative Techniques</h3>
<p>Let&rsquo;s start with obvious ones: when talking about creativity, someone is bound to mention &ldquo;brainstorming&rdquo; or &ldquo;combining ideas&rdquo;. Yet, if you don&rsquo;t know about these (practical) techniques, you&rsquo;ll have a harder time solving the problem at hand. For instance, until recently, I never heard about non-linear note-taking, <a href="https://zettelkasten.de/introduction/">until now</a>. It has completely changed the way I work!</p>
<p>The most interesting remark came from someone who said:</p>
<blockquote>
<p>Creativity is the brew of different inputs.</p>
</blockquote>
<p>Because of this, he actively sought out new information - anything that could help him in making the connection with the current problem. Thus, the more you know (and can remember!), the more you can link. And the more you can link, the more you can <em>cook up</em> a solution! That is why this term is colored both blue and purple.</p>
<p>More interesting common practices that were mentioned:</p>
<ul>
<li><em>Peeling the onion</em> by keeping on asking <em>&ldquo;why?&quot;</em>;</li>
<li><em>Rubber ducking</em>;</li>
<li>Switching gears: zooming out or zooming in;</li>
<li>Seeking out edge cases (hopefully in combination with unit tests);</li>
<li>&hellip;</li>
</ul>
<p>Things like <em>shower thoughts</em> reminded me and participants of Andy Hunt&rsquo;s <a href="https://www.goodreads.com/book/show/3063393">Pragmatic Thinking &amp; Learning</a>, one of the best books any developer can read.</p>
<h3 id="2-technical-knowledge">2. Technical Knowledge</h3>
<p>If creativity is the brew of different inputs, then you better be inputting a lot! Without any base knowledge of the problem at hand (syntax, alternative previous solutions, &hellip;), your creative mind will probably never even bootstrap. The obvious link to another popular non-technical skill, <em>continuous learning</em> (or <em>lifelong learning</em>) can be made here.</p>
<h3 id="3-communication">3. Communication</h3>
<p>Many people falsely assume that creativity is a very personal matter: the lone genius creating away of having awesome thought after thought. Yet it is usual within <a href="https://jessitron.com/2020/12/26/purple-developer/">the Camerata</a> where the magic happens: the group of like-minded people that share ideas, in a liquid network, as in Steven Johnson&rsquo;s <a href="https://www.goodreads.com/book/show/8034188">Where Good Ideas Come From</a>.</p>
<p>Rubber ducking is all good, but it&rsquo;s better to do it with a colleague: the sensible or insensible response might trigger a thought in your brain and end up helping your creative process. Rubber ducks don&rsquo;t talk back, as far as I know.</p>
<p>Communicating might also help with motivation - which in turn helps you being more creative (extrinsic motivation only goes that far). One participant said:</p>
<blockquote>
<p>Doing something without feedback is just too non-committal.</p>
</blockquote>
<h3 id="4-constraints">4. Constraints</h3>
<p>Besides of the exchange of ideas in the communication dimension, working with a fast feedback loop and doing stuff client-oriented introduces <strong>constraints</strong>. Constraints are the things of the Devil - the things we as developers usually curse at: time too short, nagging client, stupid bug report, and so forth. Yet, in reality, the <em>sweet spot of creativity</em> is having enough constraints to keep it challenging. Biskjaer talks about <a href="https://link.springer.com/article/10.1007/s10798-019-09496-7">How task constraints affect inspiration search strategies</a> - and that is exactly what happens with creative software developers.</p>
<p>Next time your team members complain about yet another constraint, tell them they&rsquo;re being more creative that way.</p>
<h3 id="5-critical-thinking">5. Critical Thinking</h3>
<p>Criticizing others' ideas (<em>&ldquo;That ain&rsquo;t gonna work!&quot;</em>) is easy. Coming up with good alternatives yourself is not. Separating the wheat from the chaff, in terms of conceptual ideas you and your team has on this one programming problem, is very important. My ex-colleagues neatly summarized this as: <em>&ldquo;don&rsquo;t ASS-ume, you make an ass out of u and me&rdquo;</em>. This was said quite often, for example when we assumed the <code>NullPointerException</code> was because of <code>x</code>, without digging deeper first.</p>
<p>Of course, the cause turned out to be a combination of <code>y</code> and <code>z</code>.</p>
<h3 id="6-curiosity">6. Curiosity</h3>
<p>Closely related to <strong>motivation</strong>. One participant said he had a lot of respect for creative solutions, also beyond the context of software engineering. Admiring something creative because of the creative aspects drives your own curiosity, pushing you to look for alternatives and niche paths you might never have looked at before. In short: get out of your comfort zone! Work cross-team, pick up that other programming language, read others' blogs (thanks!) - even if it makes you feel uncomfortable. That feeling is the feeling that you&rsquo;re <em>learning</em>.</p>
<p>Does this mean we always have to be curious? Unlikely. Use your critical thinking skills to decide! Participants emphasize the right combination between creativity and critical thinking, taking into account the context and constraints of the problem:</p>
<blockquote>
<p>Creativity is the means, not the goal.</p>
</blockquote>
<h3 id="7-creative-state-of-mind">7. Creative State of Mind</h3>
<p>Before being creative, you first have to be <em>allowed</em> to be creative: companies should also and actively support this! Setting the right scene to allow the flow of thought is a requirement of good creative problem solving. This means your environment should allow for freedom and flexibility.</p>
<h4 id="this-is-where-the-magic-happens">This is where &ldquo;the magic&rdquo; happens</h4>
<p>Funnily enough, creative thinking does not seem to happen exclusively on the workplace, behind your desk. Someone said ideas come to mind when standing in front of a traffic light, while others jot stuff down after a shower. I loved this statement:</p>
<blockquote>
<p>When I&rsquo;m at work, all I have to do is type out the solution in my head.</p>
</blockquote>
<p>Of course, <code>80%</code> of the work has been done <em>before</em> getting to work (or on the previous days/weeks at work).
I remember our boss being very angry because we were letting off steam by playing cards at 14h30 - just finishing up a game we had to interrupt. What he didn&rsquo;t see was our invisible collectible creative problem solving effort (and probably also sweat) we put in earlier. Like the guy who said I just type out stuff when I&rsquo;m at work. Managers like busy-work, but most if it is distinctively <em>not</em> creative: that part has already been done!</p>
<h2 id="future-work">Future Work</h2>
<p>There are many more variables involving creativity and sparking that creative <em>flow</em> (how to assess it, what are some limitations, what are motivations to be creative, &hellip;). We&rsquo;re planning on using the above dimensions to create a small survey in order to test how creatively students approach a programming project. I think we can safely presume that there is still a lot of unexplored ground to cover, and I love that - it means we can contribute something useful!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 20 January 2021.
</p>
]]>
</description>
</item>
<item>
<title>The Productive Programmer on Mac</title>
<link>https://brainbaking.com/post/2021/01/the-productive-programmer-on-mac/</link>
<comments>https://brainbaking.com/post/2021/01/the-productive-programmer-on-mac/#commento</comments>
<pubDate>Wed, 13 Jan 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/01/the-productive-programmer-on-mac/</guid>
<category>productivity</category>
<category>the productive programmer</category>
<category>neal ford</category>
<category>productivity tools macos</category>
<category>programming productively</category>
<category>productivity mac</category>
<category>iterm</category>
<category>alfred</category>
<category>sublime text</category>
<description>
<![CDATA[
<p>In 2010, I attended a <a href="https://devoxx.be/">Devoxx Conference</a> talk by Neal Ford called <em>&ldquo;Productive Programming&rdquo;</em>. Of course, I also bought the <a href="https://www.goodreads.com/book/show/3411606-the-productive-programmer?from_search=true&amp;from_srp=true&amp;qid=JyUZOnUvOl&amp;rank=1">accompanying book</a>, published in 2008. Eleven years ago, I also gained interest in <a href="/tags/self-improvement/">self-improvement</a>. Therefore, any sort of productivity tip was welcomed with open arms. I think/hope Neal converted many non-believers that day. It even gave me ideas to do a talk myself - which I did in the following year. It is a lot of fun to rummage through old notebooks as <a href="/post/2021/01/digitizing-journals-using-devonthink/">I&rsquo;m digitizing these</a>, to see which ideas from others got my own ideas flowing. Here is the proof:</p>
<p><figure>
<a href="../devoxx-note.jpg" class="lbox">
<img loading="lazy" src="../devoxx-note.jpg" title="Page 19 of my first &#39;real&#39; journal ever.">
</a>
<figcaption>Page 19 of my first &#39;real&#39; journal ever.</figcaption>
</figure>
</p>
<p>Back to <em>The Productive Programmer</em>. Neal Ford&rsquo;s premise was simple: you&rsquo;re a programmer, so use your PC as productive as you can. You&rsquo;re stuck behind the desk for eight hours a day anyway! While that idea wasn&rsquo;t exactly mind-blowing, the fact that so many people - colleagues - I knew still could not touch type, let alone consistently use shortkeys to refactor pieces of code, was baffling to me. So I decided to go all in and hopefully impress a few others on the way. Not to boast my ego, but to inspire others.</p>
<p>A Productive Programmer knows the <em>mechanics</em> of productivity, and he has gained enough experience through <em>practice</em> to seize opportunities to further improve things. In the light of my <a href="/post/2020/12/developing-on-apple-m1-silicon/">new M1 MacBook Air</a>, let us take a look at what that entails for a Mac user. The book might propose many tools that aren&rsquo;t relevant anymore, but the underlying concepts remain significant. I hope this will inspire students and smart people that recently joined the Mac club to pay attention to what they&rsquo;re doing. Always ask yourself: am I doing this a lot? Can this be done quicker?</p>
<h2 id="a-mechanics">A. Mechanics</h2>
<p>A quote from the book that resonated with me:</p>
<blockquote>
<p>Spend a little time each day to make every day more productive. <span>Neal Ford</span></p>
</blockquote>
<h3 id="1-acceleration">1. Acceleration</h3>
<p><figure>
<a href="../icon-iterm.png#right" class="lbox">
<img loading="lazy" src="../icon-iterm.png#right" >
</a>
</figure>
</p>
<p><em>Don&rsquo;t type the same commands again and again</em>. Find something to do the work for you. Neal suggests to use things that <em>remember history</em>: clipboard extenders, history keepers that can be automatically recalled, command prompt plug-ins, and so forth. These things seem so mundane and obvious nowadays. Yet, who knows every <a href="https://iterm2.com/features.html">obscure feature</a> of their <a href="https://www.zsh.org/">Zsh</a>-powered <a href="https://iterm2.com/">iTerm2</a>? A few I just learned yesterday:</p>
<ul>
<li><code>⌘+;</code> to auto-complete anything from history. I usually resort to Zsh&rsquo;s smart history.</li>
<li><code>⌥+SPACE</code> is my iTerm hotkey, an overlay window that appears out of nowhere. Always access to the command line!</li>
<li>In combination with Alfred: <code>⌘+SPACE</code>, <code>&gt;</code> to quickly output anything to cmd.</li>
</ul>
<p>Things like a built-in password manager, badges, image integration and clipboard managing are less useful for me, since I use other tools that work outside of a shell. I&rsquo;m still discovering new features and it&rsquo;s impossible to list them all here.</p>
<p><figure>
<a href="../icon-alfred.png#right" class="lbox">
<img loading="lazy" src="../icon-alfred.png#right" >
</a>
</figure>
</p>
<p>Another saying: <em>search trumps navigation</em>. Don&rsquo;t use Finder to click through all directories if you know what you&rsquo;re looking for: let the tools do the work for you. Remember Google&rsquo;s clean and simple search UI? There&rsquo;s one single input box: type and thou shall find. I cannot recount the number of times I&rsquo;ve pressed <code>CTRL+SHIFT+T</code> in Eclipse in my life, or <code>⌘+O</code> in IntelliJ. Why limiting yourself to only use these search tools inside a specific code editor, when you can have it across your Mac?</p>
<p>That&rsquo;s right, I&rsquo;m not talking about Spotlight but about <a href="https://www.alfredapp.com/">Alfred</a> that hijacked Spotlight&rsquo;s <code>⌘+SPACE</code> shortcut on my laptop. I&rsquo;ve never given it much thought until yesterday, but that small application might just as well be the best productivity boosting tool I&rsquo;ve used in years. The possibilities with Alfred are endless. Things I use:</p>
<ul>
<li>The clipboard history. Bye bye, Clipy - we&rsquo;ve had a good run!</li>
<li>Custom web searches: <code>gr</code> for a quick Goodreads lookup, <code>sc</code> for Google Scholar, <code>yt</code> for YouTube, &hellip; Remember the coolness of these quick searches in your shiny Google Chrome browser back in 2013? Well&hellip;</li>
<li>Snippets. Typing <code>bbblog</code> (Brain Baking Blog) <em>anywhere</em> pastes a Markdown snippet to start writing a new blog article, including my pre-set front matter and filled in date.</li>
<li>Workflows. Oh boy, where to begin?
<ul>
<li><code>tr</code> to quickly translate from Dutch to English when I&rsquo;m writing a paper (<a href="https://github.com/xfslove/alfred-google-translate">alfred-google-translate</a>).</li>
<li><code>pows</code> to quickly find a synonym using the Power Thesaurus when I&rsquo;m writing a paper (<a href="https://github.com/clarencecastillo/alfred-powerthesaurus">alfred-powerthesaurus</a>).</li>
<li><code>mdn</code> or <code>vue</code> to quickly find developer documentation of a JavaScript method in MDN or the VueJS docs. There are countless workflows like these!</li>
<li><code>dnt</code> to quickly look up something in DEVONthink.</li>
</ul>
</li>
</ul>
<p>You might have noticed the increased usage of the word <em>quickly</em>. I have the feeling that I only barely scratched the surface of Alfred. Oh, and it&rsquo;s <em>faster</em> than Spotlight, even for bootstrapping basic applications.</p>
<p><figure>
<a href="../alfred-demo.gif" class="lbox">
<img loading="lazy" src="../alfred-demo.gif" title="Accelerate your Workflow. From the alfred-powerthesaurus repo.">
</a>
<figcaption>Accelerate your Workflow. From the alfred-powerthesaurus repo.</figcaption>
</figure>
</p>
<h3 id="2-focus">2. Focus</h3>
<blockquote>
<p>The higher level of concentration, the denser the ideas. <span>Neal Ford</span></p>
</blockquote>
<p>This section of the book is a toned-down version of Cal Newport&rsquo;s <a href="https://www.goodreads.com/book/show/25744928-deep-work?from_search=true&amp;from_srp=true&amp;qid=sGwpE3mzlh&amp;rank=1">Deep Work</a>. He shows that tools like TweakUI for Windows XP (Hah! Remember that?) can de-clutter your Windows setup, creating more room in your head for actual ideas. Use virtual desktops, use <em>Distraction Free Modes</em>, such as Sublime Text&rsquo;s <code>⇧+⌘+⌥+F</code>.</p>
<p>Speaking of de-cluttering: I try to reduce the amount of visible icons in the top right menu bar as much as possible. I&rsquo;ve seen Mac owners that install a bunch of tools that eat up so many clean menu space that the program menu and the icons almost touch each other. Horrible. Having more stuff on screen makes me anxious and reduces my productivity, instead of increasing it. The Spotlight search icon and Alfred hat can be hidden (check). Things I regularly use are kept visible, such as a dedicated Bluetooth icon. In Big Sur, I also re-enabled the visible percentage of battery life.</p>
<p>An ex-colleague of mine used the Pomodoro technique and installed a small application that reminds him when to take a break and when to push on. Of course, you could track all these things and have it draw fancy graphs for you to marvel at (how bad you did that day). There is a plethora of apps for this at your disposal, but I personally never used any.</p>
<h3 id="3-automation">3. Automation</h3>
<blockquote>
<p>Don&rsquo;t Repeat Yourself (DRY)!<span>Neal Ford</span></p>
</blockquote>
<p><em>&ldquo;Can I script that?&quot;</em> should be the first thing that springs into your mind when you&rsquo;re doing something for the second time. Use <a href="https://ifttt.com/">IFTTT</a>, automate RSS filtering (or let Feedly do this for you). However, don&rsquo;t make the mistake of reinventing the wheel!</p>
<p>Another thing Neal was advocating for: use a <em>real</em> programming language when scripting. You never know when that <em>jig</em> will turn out to be a permanent part of your development cycle. If that is the case, it will get expanded. If that is the case, it better damn well be easily unit-testable!</p>
<p><figure>
<a href="../icon-firefox.png#right" class="lbox">
<img loading="lazy" src="../icon-firefox.png#right" >
</a>
</figure>
</p>
<p>In 2010, Selenium and WebDriver was thé tool to automate your browser, and to write acceptance tests with. Nowadays, we have <a href="https://www.cypress.io/">Cypress</a> and others that are gaining popularity. One thing that struck me in that Devoxx presentation was, why limit the usage of these tools to your workday? They can also be useful to automate mundane things such as form completions - outside of the enterprise application you&rsquo;re working on. <a href="https://www.tampermonkey.net/scripts.php">Tampermonkey</a> and <a href="https://monkeyscripts.org/">MonkeyScripts</a> also fall into this category.</p>
<p>Think about it - how many hours a day do you spend on a computer? I bet 80% of that time, you have at least one tab open in a browser, looking for something (shady?). Do not overlook your browser habits when thinking about automation. A recent one I discovered myself lately: in Firefox, there&rsquo;s a &ldquo;<a href="https://support.mozilla.org/en-US/kb/accessibility-features-firefox-make-firefox-and-we?redirectslug=Accessibility&amp;redirectlocale=en-US">search for text</a> as you start typing&rdquo; option that allows me to completely omit pressing <code>⌘+F</code>.</p>
<h3 id="4-canonicality">4. Canonicality</h3>
<p>Don&rsquo;t throw away binaries: (automatically) archive artifacts instead. Leverage continuous integration and deployment techniques, and device principles when thinking about your own workflow. Use virtualization, also back up your <em>configuration</em>: config is code!</p>
<p>To me, not only configuration, but also <em>documentation</em> is code:</p>
<blockquote>
<p>Out-of-date documentation is worse than none because it is actively misleading.<span>Neal Ford</span></p>
</blockquote>
<p>This is the single best reason to completely ditch (manually adding) Javadoc. Use tools like <a href="https://swagger.io/">Swagger</a> to create and automatically maintain your API documentation. Am I boring you by repeating words like <em>auto</em>?</p>
<h2 id="b-practice-your-editor">B. Practice: your Editor</h2>
<p><em>Learn to get to know your tools.</em> Do not just &ldquo;use&rdquo; them - understand them, click through all menus, write down the shortcuts, and try to learn one (of an action you of course actually use) very day. This isn&rsquo;t limited to just your (code) editor!</p>
<p><figure>
<a href="../icon-sublime.png#right" class="lbox">
<img loading="lazy" src="../icon-sublime.png#right" >
</a>
</figure>
</p>
<p>Talking about editors: pick one and dive deep - it&rsquo;s as simple as that. Editors come and go, but Vi and Emacs will probably stay forever, so both are a solid choice - if you can muster chewing through thick guides and a <em>very</em> steep learning curve. In 2012, I gave up on Vi (sorry, I&rsquo;m a softie) and bought <a href="https://www.sublimetext.com/">Sublime Text</a> together with my first MacBook - probably the best decisions I&rsquo;ve made that year. Sublime is available on any platform. Funnily enough, eight years later, I&rsquo;m still learning new Sublime tricks. Admittedly, it takes a lot of effort to deliberately learn new things when actually you want to concentrate at the task at hand. A few recent things I&rsquo;ve learned:</p>
<ul>
<li><code>⌘+B</code> to build a Markdown file using Pandoc and a custom Makefile.</li>
<li><code>^+⌘+T</code> as a custom shortcut that opens a new tab in the current path using the Terminus plugin. Thanks, <a href="https://www.youtube.com/watch?v=mV0ghkMwTQc">OdatNurd</a>!</li>
<li><code>⌘+R</code> (Go To Resource) also works with <a href="https://github.com/SublimeText-Markdown/MarkdownEditing">MarkdownEditing</a> and allows you to quickly jump to certain sections in your paper text.</li>
<li><code>⌥+⌘+V</code> in MarkdownEditing auto-creates a <code>[](link-from-clipboard)</code> nippet.</li>
<li>There are also snippets in here, although I use Alfred for that.</li>
</ul>
<p>And of course, the well-known <code>⇧+⌘+P</code> Command Palette that seems to be commonplace now - great! I also try to remap keys in other tools to resemble the ones I know by heart. This means less confusing and learning, and more time to focus on content.</p>
<p>Although I really, really, should take more time to thoroughly learn Sublime!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 13 January 2021.
</p>
]]>
</description>
</item>
<item>
<title>RSS Feeds, Hugo, and Lazy Image Loading</title>
<link>https://brainbaking.com/post/2021/01/hugo-rss-feeds-and-lazy-image-loading/</link>
<comments>https://brainbaking.com/post/2021/01/hugo-rss-feeds-and-lazy-image-loading/#commento</comments>
<pubDate>Tue, 05 Jan 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/01/hugo-rss-feeds-and-lazy-image-loading/</guid>
<category>hugo</category>
<category>rss</category>
<category>lazy image loading</category>
<category>lazy loading</category>
<category>rss images</category>
<category>hugo rss images</category>
<category>hugo noscript</category>
<description>
<![CDATA[
<h2 id="full-rss-content-in-hugo">Full RSS Content in Hugo</h2>
<p>Just a quick one I wanted to get out there in case you are, like me, using <a href="/post/2020/05/hugo-extended/">Hugo</a> to power a blog. Apparently, in 2017, the default <a href="https://discourse.gohugo.io/t/full-text-rss-feed/8368/3">behavior changed</a> from using the <code>.Content</code> to the <code>.Summary</code> variable in the default <a href="https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/embedded/templates/_default/rss.xml">rss.xml</a>.</p>
<hr>
<p><strong>Update, 12 March 2021</strong>: This article officially became obsolete! Just use <code>loading=&quot;lazy&quot;</code> - a lot less complicated and already <a href="/notes/2021/03/12h18m06s14/">decent browser support</a>. Yay for upgrades!</p>
<hr>
<p>What&rsquo;s the big deal? I had no idea, until I started using a proper RSS reader today - the open source <a href="https://ranchero.com/netnewswire/">NetNewsWire</a> for Mac. This is what your RSS feed will look like:</p>
<p><figure>
<a href="../netnewswire.jpg" class="lbox">
<img loading="lazy" src="../netnewswire.jpg" title="My Apple M1 article in an RSS reader. Where&#39;s all the text?">
</a>
<figcaption>My Apple M1 article in an RSS reader. Where&#39;s all the text?</figcaption>
</figure>
</p>
<p>The above screenshot might mislead you into thinking I simply captured only a part - I did not. That&rsquo;s the <code>.Summary</code>, right there. Since reading all &ldquo;the news&rdquo; in one place sounds intriguing, and I&rsquo;d like other visitors to enjoy my <em>full</em> blog posts in these tools too, I&rsquo;d have to change the default behavior. That can be easily done by copy-pasting the default into <code>layouts/_default/rss.xml</code> and altering it to your liking - such as swapping <code>.Summary</code> for <code>.Content</code>.</p>
<p>However, that brings us to to problem number two.</p>
<h2 id="lazy-loading-and-rss-feeds">Lazy loading and RSS Feeds</h2>
<p>Recently, after trying to maximize my <a href="https://developers.google.com/web/tools/lighthouse/">Lighthouse</a> score, especially on performance levels, I implemented <a href="https://github.com/aFarkas/lazysizes">lazysizes</a>, a simple solution to lazy load <code>&lt;img/&gt;</code> tags, thereby reducing the critical path for a single page to load. That requires a custom <code>render-image.html</code> (only available when using the Goldmark Markdown renderer) in <code>_default/_markup/</code> that looks like this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#434f54">figure</span>&gt;
&lt;<span style="color:#434f54">a</span> <span style="color:#434f54">href</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;{{ .Destination | safeURL }}&#34;</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;lbox&#34;</span>&gt;
&lt;<span style="color:#434f54">noscript</span>&gt;
&lt;<span style="color:#434f54">img</span> <span style="color:#434f54">src</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;{{ .Destination | safeURL }}&#34;</span> <span style="color:#a61717">{{</span> <span style="color:#434f54">with</span> <span style="color:#a61717">.</span><span style="color:#434f54">Text</span> <span style="color:#a61717">}}</span> <span style="color:#434f54">alt</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;{{ . }}&#34;</span><span style="color:#a61717">{{</span> <span style="color:#434f54">end</span> <span style="color:#a61717">}}</span> <span style="color:#a61717">{{</span> <span style="color:#434f54">with</span> <span style="color:#a61717">.</span><span style="color:#434f54">Title</span><span style="color:#a61717">}}</span> <span style="color:#434f54">title</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;{{ . }}&#34;</span><span style="color:#a61717">{{</span> <span style="color:#434f54">end</span> <span style="color:#a61717">}}</span>&gt;
&lt;/<span style="color:#434f54">noscript</span>&gt;
&lt;<span style="color:#434f54">img</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;lazyload&#34;</span> <span style="color:#434f54">data-src</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;{{ .Destination | safeURL }}&#34;</span> <span style="color:#a61717">{{</span> <span style="color:#434f54">with</span> <span style="color:#a61717">.</span><span style="color:#434f54">Text</span> <span style="color:#a61717">}}</span> <span style="color:#434f54">alt</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;{{ . }}&#34;</span><span style="color:#a61717">{{</span> <span style="color:#434f54">end</span> <span style="color:#a61717">}}</span> <span style="color:#a61717">{{</span> <span style="color:#434f54">with</span> <span style="color:#a61717">.</span><span style="color:#434f54">Title</span><span style="color:#a61717">}}</span> <span style="color:#434f54">title</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;{{ . }}&#34;</span><span style="color:#a61717">{{</span> <span style="color:#434f54">end</span> <span style="color:#a61717">}}</span>&gt;
&lt;/<span style="color:#434f54">a</span>&gt;
{{ with .Title }}
&lt;<span style="color:#434f54">figcaption</span>&gt;{{ . }}&lt;/<span style="color:#434f54">figcaption</span>&gt;
{{ end }}
&lt;/<span style="color:#434f54">figure</span>&gt;
</code></pre></div><p>Do not forget the <code>&lt;noscript/&gt;</code> tag in case JavaScript is disabled or the visitor will not see any images!<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> Same goes for the RSS feed: your <code>index.xml</code> that NetNewsWire loads will see an image tag, but not a <code>src</code> attribute. To fix that, I replaced the content, like so:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">{{ $lazyLoadImg := &#34;&lt;<span style="color:#434f54">img</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;lazyload\&#34;</span> <span style="color:#434f54">data-src</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34; }}
</span><span style="color:#7f8c8d">{{ $eagerLoadImg := &#34;</span><span style="color:#a61717">&lt;</span><span style="color:#434f54">img</span> <span style="color:#434f54">src</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;</span> <span style="color:#a61717">}}</span>
<span style="color:#a61717">{{</span> <span style="color:#a61717">$</span><span style="color:#434f54">content</span> <span style="color:#434f54">:</span><span style="color:#728e00">=</span> <span style="color:#7f8c8d">.Content</span> <span style="color:#a61717">|</span> <span style="color:#434f54">replaceRE</span> <span style="color:#a61717">$</span><span style="color:#434f54">lazyLoadImg</span> <span style="color:#a61717">$</span><span style="color:#434f54">eagerLoadImg</span> <span style="color:#a61717">|</span> <span style="color:#434f54">safeHTML</span> <span style="color:#a61717">}}</span>
<span style="color:#a61717">&lt;</span><span style="color:#434f54">description</span>&gt;
{{ $content }}
]]&gt;
&lt;/<span style="color:#434f54">description</span>&gt;
</code></pre></div><p>I know the documentation mentions <code>render-image.rss.xml</code> as a separate RSS renderer, but it <a href="https://discourse.gohugo.io/t/how-does-render-image-rss-xml-work/29935">as reported</a> before, it currently does not work (v0.79.1).</p>
<p><strong>Update, 9 Jan. 2021</strong>: It seems that the RSS reader <a href="https://feedly.com/">Feedly</a> processes <code>&lt;noscript/&gt;</code> tags, resulting in two displayed images instead of one. Another <code>replaceRE</code> to replace the tag fixes that, although it&rsquo;s starting to get messy&hellip;</p>
<h2 id="featured-images-in-rss-feeds">Featured images in RSS feeds</h2>
<p>I still wasn&rsquo;t satisfied. Some blog posts use a &ldquo;big image&rdquo; (or &ldquo;featured image&rdquo; masthead), that is part of the article header, and is currently not shown in the RSS reader. After inspecting the RSS specifications, it seems that a <code>&lt;img/&gt;</code> tag in the description is the only way to do it (provided a <code>CDATA</code> wrapper is present), as opposed to twitter cards that have a dedicated tag for this. So, the above description tag was extended, and now looks like this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#434f54">description</span>&gt;
{{ `<span style="color:#728e00">&lt;![CDATA[ ` | safeHTML }}
</span><span style="color:#728e00"> {{ if .Params.bigimg }}
</span><span style="color:#728e00"> &lt;p&gt;
</span><span style="color:#728e00"> &lt;img hspace=&#34;5&#34; src=&#34;{{ $baseurl }}bigimg/{{ .Params.bigimg }}&#34;/&gt;
</span><span style="color:#728e00"> &lt;/p&gt;
</span><span style="color:#728e00"> {{ end }}
</span><span style="color:#728e00">
</span><span style="color:#728e00"> {{ $content | safeHTML }}
</span><span style="color:#728e00"> ]]&gt;</span>
&lt;/<span style="color:#434f54">description</span>&gt;
</code></pre></div><p>Let&rsquo;s inspect the changes with our RSS reader:</p>
<p><figure>
<a href="../netnewswire2.jpg" class="lbox">
<img loading="lazy" src="../netnewswire2.jpg" title="Yes, a featured image and the rest of the text!">
</a>
<figcaption>Yes, a featured image and the rest of the text!</figcaption>
</figure>
</p>
<p>Scrolling down also reveals properly loaded images, hooray! Do not forget to add feed metadata to the <code>&lt;header/&gt;</code> tag so that NetNewsWire can automatically detect the location of your RSS feed:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#434f54">link</span> <span style="color:#434f54">href</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;{{ .RelPermalink }}&#34;</span> <span style="color:#434f54">rel</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;alternate&#34;</span> <span style="color:#434f54">type</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;application/rss+xml&#34;</span> <span style="color:#434f54">title</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;Brain Baking&#34;</span> /&gt;
&lt;<span style="color:#434f54">link</span> <span style="color:#434f54">href</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;{{ .RelPermalink }}&#34;</span> <span style="color:#434f54">rel</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;feed&#34;</span> <span style="color:#434f54">type</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;application/rss+xml&#34;</span> <span style="color:#434f54">title</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;Brain Baking&#34;</span> /&gt;
</code></pre></div><p><a href="/subscribe">Enjoy my RSS feeds</a>!</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>Try it your for yourself by disabling JS in your browser. Your blog should be accessible to anyone - no CSS, no JS, <a href="/post/2020/06/designing-with-accessibility-in-mind/">accessibility options</a> - try to include everyone. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 5 January 2021.
</p>
]]>
</description>
</item>
<item>
<title>Digitizing journals using DEVONthink</title>
<link>https://brainbaking.com/post/2021/01/digitizing-journals-using-devonthink/</link>
<comments>https://brainbaking.com/post/2021/01/digitizing-journals-using-devonthink/#commento</comments>
<pubDate>Fri, 01 Jan 2021 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/01/digitizing-journals-using-devonthink/</guid>
<category>devonthink</category>
<category>digitizing journals</category>
<category>digitalizing journals</category>
<category>from evernote to devonthink</category>
<category>scanning journals</category>
<category>tagging journals</category>
<category>scanning hand-written journals</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/devonexport.jpg"/>
</p>
<p>In 2017, I wrote a practical <a href="post/2017/07/journaling-in-practice/">guide to keeping a journal</a>, which also contained a digitalizing part involving Evernote. Since then, a few things happened that ultimately made me close my Evernote account for good, and resort to other methods I&rsquo;d like to explain here.</p>
<h2 id="why-i-quit-evernote">Why I Quit Evernote</h2>
<h3 id="1-privacy-and-security">1. Privacy and Security</h3>
<p>The primary reason to quit Evernote was taking back control of my own data. I don&rsquo;t want to throw my whole life on &ldquo;the cloud&rdquo; anymore - even if it&rsquo;s encrypted at rest on Google Cloud servers - to which I do not have any key, by the way. Oh, and
<a href="https://lifehacker.com/evernote-employees-can-read-your-notes-and-theres-no-w-1790099958">Evernote employees can read your notes</a>? I&rsquo;ve also heard stories of disappearing notes. Although that never happened here, it&rsquo;s kind of scary.</p>
<p>So, I purposely looked for a <strong>decentralized</strong> solution that does <em>not</em> force me to store my very personal data somewhere else besides on my own hardware. With DEVONthink, you can still sync between multiple devices using Dropbox, with client-side encryption. Making backups is a simple matter of zipping a single directory, and doing whatever the hell I want with it. The note database can also be encrypted, although I simply rely on <a href="https://support.apple.com/en-us/HT204837">FileVault</a>&rsquo;s disk encryption instead.</p>
<h3 id="2-functionality">2. Functionality</h3>
<p>DEVONthink has so many bells and whistles that it is impossible for me to list them here. Take a look at <a href="https://www.devontechnologies.com/apps/devonthink">the official website</a>. Of course, if you&rsquo;re a minimalist, that can also be a bad thing. Luckily, most features are discrete and the main UI is clean and can be customized to your liking. A few things I particularly liked, compared to the Evernote OSX application:</p>
<ul>
<li>Proper Markdown support, custom CSS, WikiLinks, &hellip;</li>
<li>Smart AI that suggests related notes.</li>
<li>A scriptable interface using AppleScript (not great, but it works)</li>
<li>Smart Rules that lets you auto-tag, move, rename, &hellip;</li>
</ul>
<h3 id="3-speed">3. Speed</h3>
<p>DEVONthik is <em>blazingly fast</em> on my <a href="/post/2020/12/developing-on-apple-m1-silicon/">M1 MacBook Air</a>. It literally takes a single second to boot, while the Electron-based Evernote app takes its sweet time. By then, I&rsquo;m over the <em>&ldquo;quickly, jot that down or I&rsquo;ll lose it!&quot;</em> pattern. Okay, that&rsquo;s a lie, I only take notes in my analog journal, but still.</p>
<h3 id="disatvantages-of-devon-tech">Disatvantages of DEVON Tech.</h3>
<ul>
<li><strong>It&rsquo;s expensive</strong>. True, but it&rsquo;s a <em>one-time</em> cost, not a yearly one! With Evernote increasing its prices to <code>$7</code> a month, after two years you&rsquo;ve almost covered the Pro edition. However, what I actually like about the price is that it forces me to <em>actually make use of it</em>. After all, I paid quite a bit of money (at once) on a single product. Better make the most of it, then!</li>
<li><strong>You&rsquo;re limited to Mac tech</strong>. Also true. Although I don&rsquo;t mind, I do wish I had an iPhone right now, because DEVONthink To Go is not available for Android, and that does sting. Avoiding vendor lock-in is important, especially as you want your note-taking system to last preferably your entire life. Export options are plenty, and notes are simply files in folders.</li>
</ul>
<h2 id="migrating-from-evernote-to-devonthink">Migrating from Evernote to DEVONthink</h2>
<p>My Evernote journal stack was easily exported into a weird <code>.enex</code> format that turned out to contain a simple XML structure. A few <a href="https://gist.github.com/evernotegists/6134552">parsing gists</a> helped me cook up a script to automatically import this data into DEVONthink. Yes, there&rsquo;s a Import menu, but it requires Evernote to be installed, and by then, my account as already closed.</p>
<p>The <a href="https://discourse.devontechnologies.com/t/easy-capture-of-pdf-from-web/4137/3">DEVON community</a> helped with tips on <a href="http://myproductivemac.com/blog/devon-think-part-3-importing-and-indexing14102015">importing</a> and <a href="https://wp.honekamp.net/2019/01/04/automate-storing-of-images-with-pythonista-and-devonthink/">image importing</a>, and I ended up with a Python script that combines AppleScript (using <a href="https://pypi.org/project/appscript/">appscript</a>, which is deprecated and &ldquo;unsupported&rdquo;, but still works on Big Sur) to command DEVONthink and raw python to parse the XML structure:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"> <span style="color:#434f54">journaldb</span> <span style="color:#728e00">=</span> <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">devon</span><span style="color:#728e00">.</span><span style="color:#434f54">create_record_with</span>({<span style="color:#434f54">k</span><span style="color:#728e00">.</span><span style="color:#434f54">type</span>:<span style="color:#434f54">k</span><span style="color:#728e00">.</span><span style="color:#434f54">group</span>,<span style="color:#434f54">k</span><span style="color:#728e00">.</span><span style="color:#434f54">name</span>: <span style="color:#434f54">filename</span><span style="color:#728e00">.</span><span style="color:#434f54">replace</span>(<span style="color:#7f8c8d">&#34;.enex&#34;</span>, <span style="color:#7f8c8d">&#34;&#34;</span>)},<span style="color:#434f54">in_</span><span style="color:#728e00">=</span><span style="color:#434f54">db</span>)
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">devon</span><span style="color:#728e00">.</span><span style="color:#434f54">create_record_with</span>({<span style="color:#434f54">k</span><span style="color:#728e00">.</span><span style="color:#434f54">type</span>:<span style="color:#434f54">k</span><span style="color:#728e00">.</span><span style="color:#434f54">picture</span>, <span style="color:#434f54">k</span><span style="color:#728e00">.</span><span style="color:#434f54">tags</span>: <span style="color:#434f54">tags</span>, <span style="color:#434f54">k</span><span style="color:#728e00">.</span><span style="color:#434f54">name</span>: <span style="color:#434f54">title</span>, <span style="color:#434f54">k</span><span style="color:#728e00">.</span><span style="color:#434f54">data</span>: <span style="color:#434f54">url</span>},<span style="color:#434f54">in_</span><span style="color:#728e00">=</span><span style="color:#434f54">journaldb</span>)
</code></pre></div><p>In order to pass the URL, the Base64-encoded image data from the <code>.enex</code> export is first copied to a local file. The full gist code is <a href="https://gist.github.com/wgroeneveld/25139d401840bbfd65e0152a5791ba3f">available here</a>.</p>
<h2 id="how-to-digitize-hand-written-journals">How to Digitize Hand-written Journals</h2>
<h3 id="1-scanning">1. Scanning</h3>
<p>Since the Android Evernote scanner app - which worked quite well, to be honest - isn&rsquo;t an option for me anymore, I needed to find another way to efficiently digitize my stuff. After reading <a href="http://www.markwk.com/digitalize-paper-journals.html">Mark Koester&rsquo;s guide</a> on digitalizing journals with a scanner app, I decided to give <a href="https://www.thegrizzlylabs.com/genius-scan">Genius Scan</a> a try. Others I&rsquo;ve tried are Adobe Scan (requires login, nope!) and Smart Doc Scanner (too clumsy to quickly scan multiple pages).</p>
<p>Scanning an entire journal (240 pages) took <code>20</code>min. However, the app only managed to identify and properly cut the pages about <code>30%</code> of the time, and regularly rotates scans even though I don&rsquo;t want that. I do like writing with a lot of colors, pasting pieces of cut-out papers and images in-between. That might have confused it. Furthermore, the quality of the scans themselves isn&rsquo;t great (even after selecting the <em>&ldquo;Highest&rdquo;</em> image quality), compared to the scans made by the Evernote app. I&rsquo;m not sure whether I can recommend it, but it&rsquo;s the best of the worst. I tried both scanning single pages and two pages at once (by opening up the journal) and the latter worked much better.</p>
<p>Although Genius Scan quickly lets you create a single PDF document for each journal, I don&rsquo;t want a <em>single</em> file: I want separate files for each page to tag in DEVONthink. No problem: after transferring the PDF to your workstation, use ImageMagick: <code>convert -density 150 journal.pdf -quality 90 journal.jpg</code> creates <code>journal-i.jpg</code> for each page (<code>48</code>s for 248 pages on the <a href="/post/2020/12/developing-on-apple-m1-silicon/">Apple M1</a> - <code>300</code>dpi creates blown-up <code>4</code>MB files that I don&rsquo;t need). Then, simply drag these into DEVONthink after creating a new group for the journal and the painful tagging process can begin&hellip;</p>
<p>As for note names, I used the pattern <code>#XPYYY</code> where <code>X</code> was the journal index and <code>YYY</code> was the page number. A very handy feature of DEVONthink is the <em>Automatic WikiLinks</em> one that creates linkks to journal pages if you mention them in a note. This does not work if a note starts with a hashtag. I converted these using the Script - Rename - Rename using RegEx menu. Do <em>not</em> rename them on disk: this will corrupt your note DB. I simply replaced <code>#</code> with <code>b</code> (for &ldquo;book&rdquo;). I&rsquo;ve seen others use a timestamp in their filename, but that makes linking even more difficult.</p>
<p><figure>
<a href="../devon-wikilink.jpg" class="lbox">
<img loading="lazy" src="../devon-wikilink.jpg" title="Autocompleting links to journal pages in Markdown.">
</a>
<figcaption>Autocompleting links to journal pages in Markdown.</figcaption>
</figure>
</p>
<h3 id="2-tagging">2. Tagging</h3>
<p><em>Fast</em> tagging is an art. With DEVONtink and a bit of shortcut trickery, you&rsquo;ll do just fine. Select a scanned picture. Click on &ldquo;Tags&rdquo; on the right and add some. Press Enter. Use <code>CTRL+TAB</code> and <code>DOWN</code> to quickly go to the next. If you didn&rsquo;t touch your trackpad, just click again to re-enter the next set of tags. I usually browse through the same physical journal in case I feel like re-reading or the scanned image is a bit blurry. This process takes about <code>1.5</code>hrs per journal. A few more tips:</p>
<ul>
<li>If you&rsquo;re obsessed about structure: DEVONthink supports hierarchical tags.</li>
<li>Don&rsquo;t overdo it. I used to tag way too much, or use too fine-grained things. If you, like me, use tags primarily to quickly <em>find</em> stuff, be mindful of the name and amount.</li>
</ul>
<h3 id="3-other-metadata">3. Other metadata</h3>
<p>With Evernote, I <a href="(post/2017/07/journaling-in-practice/)">used to annotate</a> each individual note with the correct date as appearing on the physical paper. I stopped doing that because it takes too much time, and it is irrelevant: either the date stamp, positioned in a corner, is also scanned, or I can deduce the period by simply looking at the <em>Location</em>: each group is labeled as follows:</p>
<pre><code>Book XX MMYYYY - MMYYYY
</code></pre><p>Where <code>XX</code> is a simple serial number and both dates denote the beginning and ending period of that particular notebook. If, for some reason, that still isn&rsquo;t enough, I simply locate the physical copy and look at that one instead. For me, the digital versions are never meant to replace the originals: they are merely there as a backup and a quick way to find notes.</p>
<p><figure>
<a href="../devon-notes.jpg" class="lbox">
<img loading="lazy" src="../devon-notes.jpg" title="Tags (left), Journals (Middle), selected Page and tags (right).">
</a>
<figcaption>Tags (left), Journals (Middle), selected Page and tags (right).</figcaption>
</figure>
</p>
<p>If that is not enough for you, DEVONthink offers the ability to add custom metadata fields.</p>
<h2 id="so-im-a-devonthinker-now-whats-next">So I&rsquo;m a DEVONthinker now. What&rsquo;s next?</h2>
<p>Customize your setup. Browse through online DEVONthink <a href="http://myproductivemac.com/blog/making-devonthink-and-hazel-play-nicely1522017">productivity tips</a>. Read Stefan Imhoff&rsquo;s <a href="https://www.stefanimhoff.de/zettelkasten-note-taking-devonthink/">Zettelkasten Note-taking Method</a> with DEVONthink. I&rsquo;m far from a note-taking ninja myself, and it&rsquo;s very inspiring to read how others tackle this. As he put it:</p>
<blockquote>
<p>Putting notes into folders is the beginners approach.</p>
</blockquote>
<p>The Zettelkasten method basically equals to the practice of <em>non-linear note-taking</em>:</p>
<ol>
<li>You take notes. Good, but not great.</li>
<li>You also tag notes. Better, as it groups them into clusters, but still not great.</li>
<li>You create links between tags/notes. Congrats, you&rsquo;re <em>zettlekast</em>-ing!</li>
</ol>
<p>Remember, digitizing your journal is <em>only the beginning</em>. So we&rsquo;re officially a note-taking newbie now. On to level 2!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 2021.
</p>
]]>
</description>
</item>
<item>
<title>Programming on the Apple M1 Silicon</title>
<link>https://brainbaking.com/post/2020/12/developing-on-apple-m1-silicon/</link>
<comments>https://brainbaking.com/post/2020/12/developing-on-apple-m1-silicon/#commento</comments>
<pubDate>Sun, 27 Dec 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/12/developing-on-apple-m1-silicon/</guid>
<category>m1 programming</category>
<category>apple m1 development</category>
<category>m1 apple java</category>
<category>m1 jdk</category>
<category>apple m1 gradle</category>
<category>big sur productivity tools</category>
<category>java arm64</category>
<category>netbeans m1 apple</category>
<category>intellij m1 apple</category>
<category>gba m1 apple</category>
<category>arduino m1 apple</category>
<category>go m1 apple</category>
<category>python m1</category>
<category>hugo m1 apple</category>
<category>pandoc m1 apple</category>
<category>mactex m1 apple</category>
<category>javascript m1 apple</category>
<category>javascript arm64</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/macbookairs.jpg"/>
</p>
<p>Ever since I read Kay Singh&rsquo;s Apple Silicon M1: <a href="https://singhkays.com/blog/apple-silicon-m1-black-magic/">Black. Magic. Fuckery</a> article, I couldn&rsquo;t stop wanting one. My 2012 MacBook Air was in need of a replacement, and although still <em>very</em> serviceable for a 8+year old laptop, not upgrading OSX and a shortened battery lifespan were getting irritating. So, Santa (well, you know) bought me a M1 2020 MacBook Air. At first, I wanted to hold off for a while, after many of the developer tools I use were officially supporting ARM64. But hey, what the heck.</p>
<p>As there&rsquo;s not a lot of information out there on the M1 from a developers perspective, except <a href="https://steipete.com/posts/apple-silicon-m1-a-developer-perspective/">a few</a> <a href="https://medium.com/before-semicolon/is-m1-mac-worthy-or-good-for-developers-developer-review-3ed832f4105e">other blogs</a> here <a href="https://codetober.com/software-development-on-the-new-m1-macbook-pro-13/">and there</a>, I wanted to chime in and share my initial findings. Bear in mind that this will very likely change in the near future, as many developers are starting to support the new architecture. An interesting site to check whether your software works is <a href="https://isapplesiliconready.com/">isapplesiliconready.com</a> and <a href="https://doesitarm.com/kind/developer-tools/">doesitarm.com</a> - although these are not always up to date and sometimes provides false information! Be sure to go after the source yourself.</p>
<p>Whatever you do, be sure to upgrade Big Sur to <code>11.1</code> first - that will take a while (and eat up more HDD space). I went with the <code>512GB</code> Air version with eight cores. I don&rsquo;t care about CPU throttling - even with the 25% performance hit, it still outperforms heavyweight Intel MacBook Pros!</p>
<h2 id="productivity-tools">Productivity tools</h2>
<p>Before getting to the programming part, let&rsquo;s take a look at the basic tools I couldn&rsquo;t live without. First, install <strong><a href="https://iterm2.com/">iTerm 2</a></strong>. It&rsquo;s already M1-ready, and Big Sur moved from Bash to Zsh, another good shell I still know from my Gentoo days. Check out technofob.com&rsquo;s <a href="https://technofob.com/2020/12/24/the-ultimate-mac-m1-terminal-iterm2-oh-my-zsh-zsh-syntax-highlighting/">oh-my-zsh config</a> for colors and such, and maybe add <a href="https://gist.github.com/knadh/123bca5cfdae8645db750bfb49cb44b0">extras</a> in your <code>~.zsh</code>.</p>
<p>Now that you have a shell, we need cmdline stuff. The master branch of Homebrew is ARM64-complaint and you can <a href="https://soffes.blog/homebrew-on-apple-silicon">install two homebrews</a> for the bottles that are still lagging behind - or compile them from source using <code>brew install --build-from-source</code>. I&rsquo;ve successfully built these from source: sqlite, openssh, python3.9, imagemagick. I set up the M1 homebrew version in <code>/opt/homebrew</code> - and so far, every installation didn&rsquo;t need a Rosetta alternative - yet. (Heads up: <a href="https://github.com/Homebrew/discussions/discussions/285">unrar is gone</a>! See link for alternate formula.)</p>
<p>A few other critical pieces of software:</p>
<p>Already running native:</p>
<ul>
<li>The <a href="https://brave.com/">Brave</a> nightly build. Most Chromium-based browsers work.</li>
<li><a href="https://rectangleapp.com/">Rectangle</a>, the upgraded Spectacle one.</li>
<li><a href="https://www.alfredapp.com/">Alfred</a> - of course! I became a convert after fiddling with it, replacing Spotlight and Clipy (see below).</li>
</ul>
<p>Still on Rosetta - but development on the way:</p>
<ul>
<li><a href="https://github.com/Clipy/Clipy">Clipy</a> clipboard utility, the upgraded ClipMenu one.</li>
<li>Hopefully Opera someday soon.</li>
<li><a href="https://www.sublimetext.com/3">Sublime Text 3</a>. Preview builds of Visual Studio code are already released.</li>
<li><a href="https://discussion.evernote.com/forums/topic/131507-apple-silicon-m1-version-of-evernote-10/">Evernote</a>. It runs on Electron, a known-to-be CPU hungry JS shell. The Rosetta one works, but is a bit sluggish and uses a significant amount of battery.</li>
<li>Update jan. 2021: The latest <a href="https://www.gimp.org/downloads/">GIMP</a> 2.10 is finally released for OSX, but there are known Big Sur issues. I didn&rsquo;t run into a single one.</li>
</ul>
<p>Update 12 jan. 2021: Sublime <a href="https://www.sublimetext.com/docs/3/build_systems.html">Build Systems</a> still use <code>/bin/bash</code> to execute the <code>exec_cmd</code> or <code>cmd</code> commands. This means that your <code>$PATH</code> will be screwed up. There are a couple of options to mitigate this. Fiddling with the internal <code>exec.py</code> file did not work for me. In the end, I simply re-created a <code>.bash_profile</code> file in my home dir to set the path for Sublime Text 3 builds. Using <a href="https://github.com/randy3k/Terminus">Terminus</a> does not help.</p>
<p><a href="https://www.reddit.com/r/spotify/comments/jyrsxw/when_will_spotify_support_the_new_m1_macbooks/">Spotify is a mess</a>, according to some, while others claim that Rosetta is &ldquo;good enough&rdquo;. I&rsquo;d like to run as much stuff as possible native, I guess we&rsquo;ll have to wait. For now, &ldquo;it just works&rdquo;, but as Evernote, is far from optimized.</p>
<p><figure>
<a href="../mbairsvs.jpg" class="lbox">
<img loading="lazy" src="../mbairsvs.jpg" title="Left: M1 MacBook Air 2020. Right: x86_64 MacBook Air 2012. Note the differences in screen size. The Gold is a bit more Pink than I&#39;d like, but it&#39;s growing on me!">
</a>
<figcaption>Left: M1 MacBook Air 2020. Right: x86_64 MacBook Air 2012. Note the differences in screen size. The Gold is a bit more Pink than I&#39;d like, but it&#39;s growing on me!</figcaption>
</figure>
</p>
<h2 id="java-development">Java development</h2>
<p>The Azul community released <a href="https://www.azul.com/downloads/zulu-community/?os=macos&amp;architecture=arm-64-bit&amp;package=jdk">ARM64 Java builds</a> that are blazingly fast. There are <a href="https://izziswift.com/java-jdk-for-apple-m1-chip/">other solutions</a>, but the Zulu builds I tested so far are great. They even ported the JDK13/JDK11/JDK8 older ones. I settled for v15, since Gradle does not like Java 16 yet, according to the <a href="https://docs.gradle.org/current/userguide/compatibility.html">compatibility matrix</a>. Gradle <code>6.7</code> builds fine with the ARM64 development kit.</p>
<p>The biggest hurdle for me was <strong>JavaFX</strong>, the UI libraries we use to teach students the Model-View-Controller principle. It <a href="https://nequalsonelifestyle.com/2020/11/23/apple-silicon-benchmarks-pt2-javafx/">reportedly</a> works under Rosetta, but I wanted to try it native anyway, and got a nice <code>no toolkit found</code> exception, not unlike <a href="https://github.com/javafxports/openjdk-jfx/issues/237">this one</a>. Funnily enough, it <em>builds</em> fine, but it does not <em>execute</em>: JavaFX looks for a native UI renderer and cannot find one.</p>
<p>Installing JDKs with different architectures turned out not to be problematic, and I can quickly switch between both using an alias:</p>
<pre><code>alias jdkarm=&quot;export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-15.jdk/Contents/Home&quot;
jdkarm
alias jdkx86=&quot;export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-15.0.1.jdk/Contents/Home&quot;
export PATH_TO_FX=/Users/wgroeneveld/development/java/javafx-sdk-15.0.1/lib
</code></pre><p>Paths shouldn&rsquo;t be hardcoded, but <code>/usr/libexec/java_home -a</code> didn&rsquo;t work for me. Building this <a href="https://github.com/KULeuven-Diepenbeek/db-course/tree/main/examples/jdbc-fxml-start">sample FXML project</a> using <code>./gradlew clean build</code> took about a second natively:</p>
<ul>
<li>ARM64: <code>1378</code>ms</li>
<li>x86_64 Rosetta2: <code>9646</code>ms! (second time: <code>2459</code>ms, still almost double)</li>
<li>x86_64 MacBook Air 2012: <code>14590</code>ms (second time: <code>3200</code>ms)</li>
</ul>
<p><figure>
<a href="../javaperformance.jpg" class="lbox">
<img loading="lazy" src="../javaperformance.jpg" title="Lower is better. Compile performance in ms.">
</a>
<figcaption>Lower is better. Compile performance in ms.</figcaption>
</figure>
</p>
<p>As you can see, combining Rosetta with another &ldquo;Virtual&rdquo; Machine is not a particularly great idea. Remember that the 2012 MacBook Air only has <code>4GB</code> of memory, with eight year old tech.</p>
<h3 id="netbeans-ide">NetBeans IDE</h3>
<p>NetBeans: 12.2 includes Big Sur/Rosetta2 support, but is not running natively. It auto-detects the JDK ARM64 build, which is even more annoying, as setting the default Java Platform is a pain. The &ldquo;best&rdquo; way is to manually override <code>netbeans_jdkhome</code> in <a href="https://developer.apple.com/forums/thread/664759">netbeans.conf</a>. Compared to IntelliJ, NetBeans truly is a piece of shit. Of course, the x86_64 setting also slows down NetBeans itself, not only the project you wish to compile/run.</p>
<h3 id="intellij-ide">IntelliJ IDE</h3>
<p>IntelliJ: 2020.3 ARM64 <a href="https://youtrack.jetbrains.com/issue/JBR-2526">test builds</a> are available. It seems that the Rust debugger is not hitting the breakpoints. There&rsquo;s also a preview <a href="https://blog.jetbrains.com/phpstorm/2020/12/phpstorm-2020-3-1-rc/">PHPStorm build</a>, although I haven&rsquo;t tried it yet. After opening a Gradle <code>6.3</code> project, IntelliJ complains about an invalid Gradle configuration, claiming that JDK15 isn&rsquo;t compatible with this version of Gradle, although it builds fine on cmdline. Fixing the distribution URL in gradle-wrapper.properties to <code>6.7.1</code> does the trick:</p>
<pre><code>distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
</code></pre><p>After that, the Azul JDK combined with the IntelliJ preview build is a snappy experience and pleasant to work with. Debugging works fine, just as a few third-party libraries I tried - as long as you stay away from JavaFX.</p>
<h2 id="net-development">.NET Development</h2>
<p>I still need to try this with Rider and Mono. Khalid Abuhakmeh wrote about his experience in a <a href="https://blog.jetbrains.com/dotnet/2020/12/11/net-development-on-apple-silicon/">jetbrains blogpost</a>, concluding that it was pleasant to work with .NET on the M1. Bear in mind that he&rsquo;s talking about Rosetta.</p>
<h2 id="cccross-compiling">C/C++/Cross-compiling</h2>
<p>First, get Xcode from the App Store. Yoink, <code>12GB</code>!</p>
<p>Next, the <strong>CLion</strong> IDE: the debugger cannot be launched, official ARM support is currently not there yet, but they&rsquo;re <a href="https://youtrack.jetbrains.com/issue/CPP-23494#focus=Comments-27-4615098.0-0">working on it</a> (last update: 25th of December). One of the perks of being an early adopter, I guess&hellip; I don&rsquo;t want to try this in Rosetta as I only need CLion every odd semester for my teaching activities, and hopefully, by then it&rsquo;ll be okay.</p>
<p>Until then, I&rsquo;ll compile and debug cmdline. <strong>CMake</strong> works flawlessly, using the master version of brew: <code>==&gt; Pouring cmake-3.19.2.arm64_big_sur.bottle.tar.gz</code>. Using it to compile the <code>1.10</code> release of Google Test gives C++11 errors so you&rsquo;ll have to add a <code>-DCMAKE_CXX_STANDARD=17</code> flag to CMake as per <a href="https://github.com/google/googletest/issues/1519">this ticket</a>. Compiling itself was extremely quick, compared to what I&rsquo;m used to on my 2012 MacBook Air.</p>
<h3 id="game-boy-advance">Game Boy Advance</h3>
<p>Cross-compiling <strong>GBA stuff</strong> using <a href="https://github.com/devkitPro/pacman/releases/latest">pacman</a> worked flawlessly, obviously in Rosetta mode. I doubt it will ever be released natively. Cross-compiling the whole <a href="https://github.com/wgroeneveld/gba-sprite-engine">gba-sprite-library</a>, including four demo projects, took <code>15343</code>ms. I was surprised that this worked without any problems, and a Rosetta-enabled mGBA happily plays my binaries! On the 2012 laptop, it takes more than twice that long: <code>32950</code>ms.</p>
<h3 id="arduino">Arduino</h3>
<p>After finding not so promising <a href="https://www.reddit.com/r/arduino/comments/jwpuuu/arduino_on_new_apple_macbooks_with_m1_chip/">Reddit posts</a>, I had to try it out myself. A <a href="https://github.com/arduino/Arduino/issues/10836">Github issue</a> tells us Rosetta is supported and &ldquo;somewhere in the future&rdquo; native support should be coming - Linux ARM64 builds are already available.</p>
<p>After installing the Arduino IDE (which runs on a JRE, by the way), right-clicking and pressing &ldquo;Get Info&rdquo; reveals <em>Kind: Application (Intel)</em>. It boots up fairly slowly, but compiling and uploading work without problems. Performance is a non-issue here, you won&rsquo;t be compiling megabytes of C code anyway.</p>
<h2 id="javascript">JavaScript</h2>
<p>Node <code>15.5.0</code> and its package manager have native bottles uploaded in the master Homebrew repository. Everything works flawlessly after a <code>brew install npm</code>. Do yourself a favor and install a Chromium-based browser to check out <a href="https://developers.google.com/web/tools/lighthouse/">Lighthouse</a>.</p>
<h2 id="go">Go</h2>
<p>It&rsquo;s been a while since I programmed in Go, but Dids created <a href="https://gist.github.com/Dids/dbe6356377e2a0b0dc8eacb0101dc3a7">a gist</a> entitled <em>&ldquo;Compile Go for Apple Silicon (M1)&quot;</em>, where he explains how to compile Go natively. I have yet to try it out.</p>
<h2 id="python">Python</h2>
<p>Although python <code>3.8</code> comes included with Big Sur, python <code>3.9</code> compiled without any issues from source using Homebrew. However, since OSX always seems to come with an annoyingly old <code>2.7</code> version, you have to create a symlink in <code>/usr/local/bin</code> to set the default version to 3.9. You may also need to re-link Python:</p>
<pre><code>brew unlink python &amp;&amp; brew link python
sudo ln -s -f /opt/homebrew/bin/python3.9 /usr/local/bin/python
sudo ln -s -f /opt/homebrew/bin/pip3.9 /usr/local/bin/pip
</code></pre><h2 id="writing">Writing</h2>
<p><strong>Hugo</strong> extended works like a charm on ARM64. Pfew!</p>
<p>As for my needed <strong>LaTeX</strong> tools: the <a href="https://www.tug.org/mactex/aboutarm.html">MacTeX about ARM page</a> tells me that full native support will arrive in spring 2021. Until then, Rosetta to the rescue (it also requires <code>6.7GB</code>&hellip;). I do hope that switching will not be problematic, as I can&rsquo;t wait until then.</p>
<p>As for <strong>pandoc</strong> that converts my Markdown to LaTeX, compiling from source downloads the x86_64 version of the <a href="https://www.haskell.org/ghc/">GHC</a> Haskell compiler. As expected, compilation crashed:</p>
<pre><code>ghc@8.8: The x86_64 architecture is required for this software.
Error: An unsatisfied requirement failed this build.
</code></pre><p>So, I reverted to the <a href="https://pandoc.org/installing.html">x86 installer pkg</a>, which seems to work fine. After the necessary installations, I re-compiled a recently accepted ICSE paper (involving make, pandoc, panflute, pdflatex, bibtex, yaddayadda), and it took <code>7700</code>ms on the 2012 Air, while the Rosetta x86_64 version took <code>4447</code>ms. Consider me happy! It will be <em>very</em> interesting to see this number further reduced in spring 2021.</p>
<h2 id="virtualization">Virtualization</h2>
<p>The universal memory structure of the M1 architecture has its advantages, but these obviously fade when dual booting. Furthermore, using something like VirtualBox gets you into <a href="https://codetober.com/software-development-on-the-new-m1-macbook-pro-13/">further trouble</a> by evenly splitting RAM. It <a href="https://forums.virtualbox.org/viewtopic.php?f=8&amp;t=98742">looks like</a> VirtualBox support will never be coming as it requires a x86 CPU.</p>
<p>Alternative options are <a href="https://www.parallels.com/blogs/parallels-desktop-apple-silicon-mac/">Parallels</a>, which has a technical preview already published, and VMWare Fusion, which announced <a href="https://twitter.com/VMwareFusion/status/1326229094648832000">on Twitter</a> that they&rsquo;re working on it.</p>
<p>As of now, there is no possibility for me to run my virtual image of Linux for the Operating Systems course I&rsquo;m teaching. I guess I&rsquo;ll be using a Dell laptop for this purpose&hellip; I don&rsquo;t mind, my 2012 MacBook Air didn&rsquo;t have the required memory to comfortably work with it anyway, so I already resorted to another machine.</p>
<p><strong>Edit 25 jan. 20121</strong>: Eleanor pointed me towards a gist to get <a href="https://gist.github.com/niw/e4313b9c14e968764a52375da41b4278">qemu running on M1</a>. This means it is possible to run Windows 10 and Ubuntu Server on your ARM Mac! On performance: A simple factorial program in ghci is noticeably faster on Ubuntu (ARM64) via qemu than on MacOS via Rosetta. Follow Sevarg&rsquo;s <a href="https://www.sevarg.net/2021/01/09/arm-mac-mini-and-boinc/">recent guide</a> to get Ubuntu running under QEmu!</p>
<h2 id="so-is-it-worth-it">So&hellip; Is it worth it?</h2>
<p>It depends. If you&rsquo;re like me, and you have been waiting for a long time to upgrade, now is the best possible time to take the plunge. However, if you already own a more recent MacBook (I hope it&rsquo;s with a decent keyboard: this one types lovely, compared to my wife&rsquo;s 2017 <em>butterfly</em> keyboard on the MacBook Pro - what a train-wreck), it might be a better idea to wait half a year.</p>
<p>Currently, with the software I daily use, about <code>50%</code> of them are running under Rosetta. It is impressive nonetheless: it is seamless and still very fast - except if you&rsquo;re a Java developer and somehow have to support JavaFX. Don&rsquo;t forget that the M1 chip comes with other awesome perks:</p>
<ul>
<li><code>18h</code> battery life (more like 10+ with regular compile jobs, but still great)</li>
<li>Greatly improved screen compared to my 2012 laptop</li>
<li>I finally bought a <code>QUERTY</code> one.</li>
<li><code>8GB</code> is more than <code>4GB</code>.</li>
<li>We used the 2020 Air to video-call (using browser-based <a href="https://meet.jit.si/">Jitsi</a>) over Christmas, while we used the 2012 Air during Christmas Eve - the fan went on and it crashed once.</li>
<li>The instant-on effect is <em>amazing</em>, compared to waiting up to ten seconds.</li>
<li>I can finally play <a href="https://www.reddit.com/r/macgaming/comments/k5sf57/baldurs_gate_3_on_apple_m1_performance_review/">Baldur&rsquo;s Gate III</a>!</li>
</ul>
<p>Like Kay said: Black. Magic. Fuckery!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 27 December 2020.
</p>
]]>
</description>
</item>
<item>
<title>Thoughts on Bullshit Jobs</title>
<link>https://brainbaking.com/post/2020/12/thoughts-on-bullshit-jobs/</link>
<comments>https://brainbaking.com/post/2020/12/thoughts-on-bullshit-jobs/#commento</comments>
<pubDate>Sun, 20 Dec 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/12/thoughts-on-bullshit-jobs/</guid>
<category domain="https://brainbaking.com/tags/jobs">jobs</category>
<category domain="https://brainbaking.com/tags/academia">academia</category>
<description>
<![CDATA[
<p>In 2013, David Graeber, a professor of Anthropology, published an essay on the phenomenon of Bullshit Jobs in <a href="https://www.strike.coop/bullshit-jobs/">Strike! Magazine</a>. This work was further expanded in his 2018 book <a href="https://www.goodreads.com/book/show/34466958-bullshit-jobs">Bullshit Jobs: A Theory</a>. I&rsquo;ve read the latter, but highly recommend everyone to read the former instead, as it much more concisely summarizes the essence.</p>
<h3 id="defining-a-bullshit-job">Defining a bullshit job</h3>
<p>What&rsquo;s a bullshit job, you ask? I&rsquo;m pretty sure everybody instinctively knows what a bullshit job entails, but just to be clear, David provides a working definition: <em>a bullshit job is a form of paid employment that is so completely pointless, unnecessary, or pernicious that even the employee cannot justify its existence even though, as part of the conditions of employment, the employee feels obliged to pretend that is not the case</em>. Since then, it has been expanded by others to also include, among others, a <a href="https://austingmackell.medium.com/explaining-bullshit-jobs-with-monetary-theory-11be9bb99d35">monetary theory</a>.</p>
<blockquote>
<p>A bullshit job is paid employment that is so completely pointless that even the employee cannot justify its existence.</p>
</blockquote>
<p>You know, the sort of very useful governmental paper pushing that is required when registering a travel passport, making a complaint, or trying to convince your bank employee that no, you&rsquo;re not going to take that extra insurance. There are obvious examples, but as I read the book, and as David also admitted, very large portions of virtually <em>any job</em> contain bullshit parts. And bullshit percentages are increasing at an alarming rate.</p>
<p>There is, however, one small but important detail present in the definition: it is <strong>the employee</strong> him/herself who cannot justify the existence. I&rsquo;m not entirely convinced that this is the only kind of bullshit job. Imagine a HR advisor that admits his/her job is useless: bullshit job. Imagine another HR advisor who thinks he/she&rsquo;s doing incredible valuable work, while in fact, it&rsquo;s the same bullshit. Does the latter mean the job is not a bullshit job? We all know a lot of people in denial working bullshit jobs&hellip;</p>
<p>The theory on why society does not object to bullshit jobs is also worth looking at. According to Graeber, social value and pay are inversely correlated: hospital cleaners and garbage collectors contribute to our social structure, but barely get paid anything, while corporate lawyers effectively hurt our social culture, and get a paid royal amount for doing so. There seem to be papers on the discussion of jobs and their (perceived?) social value, of which a few are referenced in the book.</p>
<p>This is a summary of the social value breakdown, found in a 2017 study, categorized by jobs (<a href="https://www.journals.uchicago.edu/doi/abs/10.1086/693393?casa_token=46Fn4qTkh1cAAAAA:aR3HQynt1SCG2WjPx1eh2GSkxaciKEmGYgIrmB9te230mEyN2MCBGzpjzBLseSGfmRKPMQUl4ow">Taxation and the Allocation of Talent</a> by Lockwoot et al.):</p>
<p><figure>
<a href="../taxationchart.jpg" class="lbox">
<img loading="lazy" src="../taxationchart.jpg" alt="Taxation and the Allocation of Talent" >
</a>
</figure>
</p>
<p>Isn&rsquo;t that something - research that claims researchers produce the most valuable output (economically speaking) for society?</p>
<h3 id="bullshit-in-the-software-engineering-industry">Bullshit in the software engineering industry</h3>
<p>In my <a href="/post/2018/10/a-decade-in-the-industry/">a decade in the industry</a> post, I reflect on ten years as an agile software developer working for various privately held companies. After reading bullshit jobs, a lot of <em>&lsquo;shit&rsquo;</em> I&rsquo;ve done there can be easily categorized as bullshit:</p>
<ul>
<li>Meetings: standups, sprint plannings, retrospectives, &hellip;</li>
<li>A favorite of mine: filling in timesheets</li>
<li>&hellip;</li>
</ul>
<p>Let&rsquo;s be honest. A lot of &lsquo;Scrum Best Practices&rsquo; are totally bullshit. We never adhered to the indicated planning. We never did anything else in retros except complain. Every standup goes like this: &ldquo;I did x yesterday. Today same&rdquo;. Although admittedly, it is not the practice but the person and the company who is to blame. Still, we&rsquo;re not finished, the worst is yet to come:</p>
<ul>
<li>Implement features that are never used;</li>
<li>Fix bugs that someone else breaks the same day;</li>
<li>Work on something for months that you know will be canceled. Receive an e-mail that confirms it&rsquo;s trashed;</li>
<li>Writing business reports that are never read;</li>
<li>&hellip;</li>
</ul>
<p>To anyone who isn&rsquo;t familiar with <a href="https://en.wikipedia.org/wiki/Dilbert_principle">The Dilbert Principle</a>: promoting incompetent people to management to get them out of the workflow fits perfectly with this theme.</p>
<blockquote>
<p>Leadership is nature&rsquo;s way of removing morons from the productive flow <span>Dogbert (Dilbert)</p>
</blockquote>
<p>A social value of <code>0</code>, according to the above graph, is in my opinion dependent on what kind of software you&rsquo;re creating. In general, being a software developer for a large company does not necessarily entail virtuous behavior, nor does it mean finding meaning. So I quit and joined the academic world to teach undergraduates how to do a bullshit job.</p>
<h3 id="bullshit-in-computing-academia">Bullshit in computing academia</h3>
<p>Now that I&rsquo;m an academic, I&rsquo;m not particularly better off. In fact, if I look around and see what professors are doing and what David talks about, it&rsquo;s a lot worse. Like I <a href="/post/2020/02/agile-academia">previously wrote</a>, e-mail is the main communication channel now, and a lot of <em>bullshit mail</em> prevents me from actually doing what I&rsquo;m supposed to be doing. Luckily, as a PhD researcher, most of the bullshit is off-loaded to the professors:</p>
<ul>
<li>Meetings, meetings more meetings: at faculty, department, campus, &hellip; level;</li>
<li>Writing 20-page long documents to hopefully get a grant, knowing you won&rsquo;t;</li>
<li>Various hideous administrative tasks;</li>
<li>&hellip;</li>
</ul>
<blockquote>
<p>These <em>&lsquo;strategic vision documents&rsquo;</em> aren&rsquo;t going to write themselves, you know!</p>
</blockquote>
<p>The supply and demand of administrative services has risen up to <code>+240%</code> between 1985 and 2005 (p. 161), meaning both industry and academia are heavily burdened by paper pushing. These <em>&lsquo;strategic vision documents&rsquo;</em> aren&rsquo;t going to write themselves, you know! David admits that his tenure as a professor in reality entails that about <code>50%</code> of his job is total and utter bullshit (p. 263). That is not something to look forward to.</p>
<p>The question is, is a professor a schoolteacher (social value <code>+1</code>), a researcher (social value <code>+9</code>), or a manager (<code>-0.8</code>)? Furthermore, I&rsquo;ve read a lot of published research that can safely be called bullshit. Simply reducing a job or even entire sector to a financial number to see if it adds or subtracts from the economy overall seems to be bullshit too.</p>
<h3 id="coping-with-bullshit-jobs">Coping with bullshit jobs</h3>
<p>The book contains hilarious statements from various people who invented ways to do whatever they want, without raising suspicion. In a bullshit job, it is important to act like you&rsquo;re busy, when in fact, you&rsquo;re not. Or you might be busy, but doing meaningless stuff instead of what <em>should</em> be be keeping you busy.</p>
<ul>
<li>There&rsquo;s a guy who installed <a href="http://lynx.browser.org">Lynx</a>, the command-line browser. This makes him look like an expert scripting away at a terminal, when in fact he&rsquo;s editing Wikipedia articles all day;</li>
<li>Someone managed to squeeze his work into one day a week. The rest of the week, he&rsquo;s &lsquo;working from home&rsquo; - meaning learning quantum physics;</li>
<li>Spending an unusual amount of time in the bathroom;</li>
<li>&hellip;</li>
</ul>
<p>It is both funny and painful to read. The question on why we put up with &lsquo;managerial feudalism&rsquo;, as David calls it, still remains. For instance, why would David himself (or myself?) not quit his academic position and focus on writing books and essays instead? There, a lot of bullshit dropped in an instant. I guess status still plays a big role that is all too briefly mentioned in the book. I do not believe that researchers in general provide more to society than IT consultants. I could write software that helps elderly people accessing multimedia. Or I could write a meaningless paper about the non-existence of vampires (yes, it has been done). Which one would you call bullshit?</p>
<p>I&rsquo;m unsure on what to do with this information. Although not exactly new to me, it is still saddening to see the breadth and depth of bullshit jobs in our society. Maybe we should start asking ourselves if we are willing to put up with this? Life&rsquo;s too short, cut the crap! Find a way to disconnect &lsquo;work&rsquo; from &lsquo;revenue&rsquo; and try to free yourself to pursue more worthwhile things.</p>
<p>Such as baking bread, for instance.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 20 December 2020.
</p>
]]>
</description>
</item>
<item>
<title>Win98 Upgrade: Sound Blaster Audigy</title>
<link>https://brainbaking.com/post/2020/11/win98-upgrade-sound-blaster-audigy/</link>
<comments>https://brainbaking.com/post/2020/11/win98-upgrade-sound-blaster-audigy/#commento</comments>
<pubDate>Tue, 24 Nov 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/11/win98-upgrade-sound-blaster-audigy/</guid>
<category domain="https://brainbaking.com/tags/soundblaster">soundblaster</category>
<category domain="https://brainbaking.com/tags/win98">win98</category>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/audigy.jpg"/>
</p>
<p>My initial <a href="/post/2020/10/building-an-athlon-win98-retro-pc">Windows 98SE retro PC build</a> came with a free <a href="https://en.wikipedia.org/wiki/Sound_Blaster#Ensoniq_AudioPCI-based_cards">Ensoniq AudioPCI</a> based card, a cheap 1998 OEM alternative to the <em>AWE64</em> or the <em>Sound Blaster Live!</em>_ line. The Sound Blaster PCI128 or _Vibra128_ is basically the same card, as it contains a Creative AudioPCI chip. The card is good enough if you&rsquo;re not picky, but it comes with a few major downsides:</p>
<ol>
<li>No external header pins for those cool looking <code>5.2&quot;</code> audio drive bays;</li>
<li>No EAX support for games;</li>
<li>Horrible, <em>horrible</em> Sound Blaster 16 (SB16) DOS emulation (see below);</li>
<li>No digital audio out;</li>
<li>Analog audio out is not that great.</li>
</ol>
<p>And since I bought a <a href="/post/2020/11/winxp-upgrade-sound-blaster-xfi">Creative X-Fi</a> for my WinXP machine, I was in the mood for another Sound Blaster upgrade. The X-Fi is the last entry in the fifth generation of Creative SB PCI cards, of which the Audigy, PCI 512, Sound Blaster Live! and PCI 128 are also a part. In 1998, I actually used to own a variant of a SB Live! card, but the analog audio output port is of questionable quality (although I never noticed that as a kid). The main problem with going for subjective history-accuracy here is the sheer variability of quality on Live! cards, so hunting down the right <code>CT4830</code> or whatever version is challenging.</p>
<p><figure>
<a href="../audigy-vibra128.jpg" class="lbox">
<img loading="lazy" src="../audigy-vibra128.jpg" title="The Audigy next to its predecessor, the Sound Blaster Vibra128.">
</a>
<figcaption>The Audigy next to its predecessor, the Sound Blaster Vibra128.</figcaption>
</figure>
</p>
<p>The eBay price range also dictated my decision to simply buy an Audigy (first edition) <code>SB0090</code> card instead - these cards are from 2001, which is still not too recent. At <a href="https://vogons.org">VOGONS</a>, the consensus for a Windows 98 build is an Audigy 2 ZS, which has updated DAC and op-amps to produce more than <code>108</code> dB and support surround 7.1. The ZS is not made to work with Win9x and I didn&rsquo;t want to overdo it, so I settled with a <code>SB0090</code> instead, costing a whopping <code>10 EUR</code>&hellip;</p>
<p>So, what does Wikipedia have to say about this card?</p>
<blockquote>
<p>It has an <code>EMU10K2</code> chip, an updated version of the Live! <code>EMU10K1</code>, that supports EAX 3.0 Advanced HD and up to 5.1 channel output.</p>
</blockquote>
<p>The hardware can handle the mixing of 64 DirectSound3D channels, compared to only half (32) on the Live! cards. But I want to compare it to the Audio PCI or PCI128 card I threw out - well it&rsquo;s better than that successor. We&rsquo;re not going to learn much by looking at the numbers. Let&rsquo;s do some test recordings instead and let the results speak for themselves.</p>
<p><figure>
<a href="../audigy.jpg" class="lbox">
<img loading="lazy" src="../audigy.jpg" title="The Sound Blaster Audigy SB0090 card with shiny IO ports.">
</a>
<figcaption>The Sound Blaster Audigy SB0090 card with shiny IO ports.</figcaption>
</figure>
</p>
<h3 id="the-eax-experience-in-games">The EAX experience in games</h3>
<p>Installing the card was painless, except for removing the old Sound Blaster drivers, as the uninstaller crashed. Windows 98 is <em>very</em> picky when it comes to swapping in and out pieces of hardware, so I was a bit worried there, and tried to manually cleanup the mess, with varying degrees of success. The Audigy installation CD ISO is available at <a href="http://vogonsdrivers.com">vogonsdrivers.com</a>, and after installing the DOSDRV and 1.12 patch, rebooting a few times because of the obligatory blue screen, I moved on to testing games.</p>
<p>First up: <em>Dungeon Siege</em>. It has excellent EAX support that enhances the feeling of actually being in the Kingdom of Ehb - or at least in its many dungeons and caves filled with stuff to whack at. Listen to a short clip with EAX enabled on the new card:</p>
<div class="video-mask">
<video width="100%" controls preload="metadata">
<source src="/vid/ds-eax.mp4#t=0.5" type="video/mp4">
Your browser does not support HTML video. Here's a link to the MP4-encoded video instead: <a href="/vid/ds-eax.mp4">/vid/ds-eax.mp4</a>.
</video>
</div>
<p>Now listen to the very same scene recorded with the Vibra128 card, which cannot do EAX:</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ds1_noeax_pcm128.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ds1_noeax_pcm128.mp3">/audio/ds1_noeax_pcm128.mp3</a>.
</video>
</div>
<p>What should be immediately noticeable is the reflective, muffled sound coming from the EAX-enabled card because the party enters a cave. The bouncy sound of the squeaks of the valve , followed by the goblin fight that sound very, <em>very</em> flat on the PCI128 card. Admittedly, Dungeon Siege likes to overdo this effect and it does get old every time you enter a huge cave (which is about half the game). It is clear that the difference is very audible and does affect my mood when playing a game: &ldquo;immersiveness&rdquo; of course is relevant.</p>
<p>The Audigy install CD-ROM comes with a nice &ldquo;mine demo&rdquo; that showcases all different EAX effects (sound reflection etc). Phils Computer Lab has <a href="https://www.youtube.com/watch?v=C4SWsC86jZw">more audio samples</a> available at YouTube.</p>
<p>Now, If you&rsquo;d ask me what the difference is between playing Dungeon Siege with a Sound Blaster Audigy on Windows 98 or with an X-Fi on Windows XP, the answer I would give is <em>I don&rsquo;t know</em>. To be honest, that difference would be marginal - at least to my ears.</p>
<h3 id="sb16-and-mpu-401-dos-emulation">SB16 and MPU-401 DOS emulation</h3>
<p>I&rsquo;ll be brief and resort to my <em>Rise of the Triad</em> comparison again:</p>
<h4 id="sound-blaster-16">Sound Blaster 16</h4>
<p><strong>The Reference</strong>; an authentic SB16 on my <a href="/post/2020/09/486-upgrade-sound-blaster">486 PC</a>:</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_sb16.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_sb16.mp3">/audio/ROTT_sb16.mp3</a>.
</video>
</div>
<p><strong>The PCI128 card</strong>;</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_sb16_pcm128.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_sb16_pcm128.mp3">/audio/ROTT_sb16_pcm128.mp3</a>.
</video>
</div>
<p><strong>The Audigy card</strong>;</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_sb16_audigy.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_sb16_audigy.mp3">/audio/ROTT_sb16_audigy.mp3</a>.
</video>
</div>
<p>What on earth is that PCI128 card doing? I have never heard anything that bad in a long time&hellip; So yeah, if being able to play older DOS games is of any importance to you, then I implore you to upgrade. SB16 emulation is clearly not one of its strong points. Just to be sure, let&rsquo;s listen to the classic <em>grabbag</em> Duke Nukem 3D tune with the music configured to Sound Blaster:</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/dn3d_sb16_pcm128.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/dn3d_sb16_pcm128.mp3">/audio/dn3d_sb16_pcm128.mp3</a>.
</video>
</div>
<p>That&rsquo;s just <em>sad</em>. Fortunately, the Audigy clearly knows how to handle the emulation, although it does not sound as clear as it should compared to the reference audio. The tones sound a bit harsh on the edges, but it&rsquo;s as good as it&rsquo;s going to get for OPL3 emulation. Unless one uses a ISA motherboard and slots in a proper Sound Blaster AWE64&hellip;</p>
<p>The Audigy to the rescue:</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/dn3d_sb16_audigy.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/dn3d_sb16_audigy.mp3">/audio/dn3d_sb16_audigy.mp3</a>.
</video>
</div>
<h4 id="mpu-401">MPU-401</h4>
<p>In the end, the <em>proper</em> way to play Duke Nukem 3D is with General MIDI support (recorded with Audigy):</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/dn3d_mpu_audigy.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/dn3d_mpu_audigy.mp3">/audio/dn3d_mpu_audigy.mp3</a>.
</video>
</div>
<p><figure>
<a href="../dn3d.jpg" class="lbox">
<img loading="lazy" src="../dn3d.jpg" title="Let&#39;s Rock!">
</a>
<figcaption>Let&#39;s Rock!</figcaption>
</figure>
</p>
<p>A monumental difference compared to both SB16 variants! Now, let&rsquo;s compare the same <em>Rise of the Triad</em> level 1 music again, this time by configuring <code>SNDSETUP.EXE</code> with &ldquo;Wave Blaster&rdquo; or &ldquo;General MIDI&rdquo; options (both are the same on emulated hardware).</p>
<p><strong>The Reference</strong>; an authentic SB16 on my <a href="/post/2020/09/486-upgrade-sound-blaster">486 PC</a> with S2 Wavetable daughter board:</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_waveblaster.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_waveblaster.mp3">/audio/ROTT_waveblaster.mp3</a>.
</video>
</div>
<p><strong>The PCI128 card</strong>;</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_mpu_pcm128.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_mpu_pcm128.mp3">/audio/ROTT_mpu_pcm128.mp3</a>.
</video>
</div>
<p><strong>The Audigy card</strong>;</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_mpu_audigy.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_mpu_audigy.mp3">/audio/ROTT_mpu_audigy.mp3</a>.
</video>
</div>
<p>Both cards are clearly different than the S2, but the S2 isn&rsquo;t exactly a genuine piece of general MIDI hardware, and I sadly do not own proper Roland audio hardware. However, when comparing PCI128 with Audigy, differences are suddenly much more subtle. To be honest, I can&rsquo;t really make out any when I listen on my laptop speakers. The difference is present when using high quality headphones, but either version is more than good enough for me.</p>
<h3 id="more-toys-to-play-with">More toys to play with</h3>
<p>The Audigy supports proper Sound Font switching, you can mess around with the EAX effects on the desktop using a very annoying TaskBar, and there are a bunch of other goodies present - provided you wish to install those. A audio CD daemon, the PlayCenter, the AudioHQ configuration center, MIDI finetuning properties, Wave Studio to record stuff, and so forth. Software support of the Vibra128 card pales compared to this.</p>
<p><figure>
<a href="../audigytools.jpg" class="lbox">
<img loading="lazy" src="../audigytools.jpg" title="Look at all these &#39;creative&#39; Creative tools, especially the taskbar!">
</a>
<figcaption>Look at all these &#39;creative&#39; Creative tools, especially the taskbar!</figcaption>
</figure>
</p>
<p>Of course, in the end, it&rsquo;s the audio playback that matters, not the software tools that I barely touch anyway, although it is nice to be able to have the power to configure it all. In any case, I can conclude that this hardware upgrade again was worth the effort and I enjoyed a day of fiddling with it. Just be sure to never play SB16-enabled games on your PCI128!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 24 November 2020.
</p>
]]>
</description>
</item>
<item>
<title>The Internet Killed Secrets in Games</title>
<link>https://brainbaking.com/post/2020/11/the-internet-killed-secrets-in-games/</link>
<comments>https://brainbaking.com/post/2020/11/the-internet-killed-secrets-in-games/#commento</comments>
<pubDate>Thu, 19 Nov 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/11/the-internet-killed-secrets-in-games/</guid>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/gob2joker.jpg"/>
</p>
<p>After <a href="https://jefklakscodex.com/articles/reviews/sacred/">finishing <em>Sacred</em></a> and planning to replay other nostalgic hack &amp; slash games, I am currently working my way through 2002&rsquo;s <em>Dungeon Siege</em> for the second time. Somewhere deep in the crystal caves, there&rsquo;s a semi-hidden treasure chest that contains <strong>Fury&rsquo;s Eye</strong> - and I have no idea what to do with it.</p>
<p>Or rather, I <em>had</em> no idea. Until I clicked on <a href="https://steamcommunity.com/sharedfiles/filedetails/?id=1264921426">this link</a> that meticulously explains every single nook and cranny in the Dungeon Siege Kingdom. It turns out that Fury&rsquo;s Eye is part of a three-item requirement to transfer your party to a hidden location in the game, a homage to Diablo II&rsquo;s classic and <em>very secret</em> cow (I&rsquo;m sorry, <a href="https://diablo.fandom.com/wiki/Hell_Bovine"><em>Hell Bovines</em></a>) level, that requires players to combine a Tome of Town Portal and a bloody leg using a device called the Horadric Cube. Still with me?</p>
<h3 id="a-case-against-the-availability-of-information">A case against the availability of information</h3>
<p>The gist is this: I came across an item that uncovers a secret, and instead of trying to do uncover it myself (and probably miserably failing), I simply &ldquo;googled&rdquo; it. This subconscious instant gratification move completely bypasses both frustration and fun I could have extracted out of the experimentation with Fury&rsquo;s Eye. Why is it so easy to go to <a href="https://gamefaqs.gamespot.com">GameFAQs.com</a>? I love digesting details on character builds, strategies and tips before and during a play through - in fact, I have my own website <a href="https://jefklakscodex.com">Jefklak&rsquo;s Retro Gaming Codex</a> dedicated to things like that.</p>
<p><figure>
<a href="../furyseye.jpg" class="lbox">
<img loading="lazy" src="../furyseye.jpg" title="Fury&#39;s Eye - what was I supposed to do with this again?">
</a>
<figcaption>Fury&#39;s Eye - what was I supposed to do with this again?</figcaption>
</figure>
</p>
<p>And yet, I&rsquo;m angry at myself for so easily falling back to the knowledge of the masses, before giving it a go myself. Dungeon Siege is definitely <em>not</em> the kind of game that deserves that kind of devoted attention, mind you. However, Diablo II does. But who tries to jam together a leg found in Tristram with a Town Portal Tome? Who does that? There are about a million other possible (wrong) item combinations to be made. Because you think that&rsquo;s the most efficient way to portal the leg out of here?</p>
<p>Without external help, chances are very slim of discovering angry axe-wielding cows (sorry, <em>Hell Bonvi</em>-what was it again?) in Diablo II yourself. Before the Internet, there were game magazines. I fondly remember reading up on Nintendo Power how to discover hidden stuff in Kirby&rsquo;s Dreamland. As a kid, I did not have the needed perseverance nor knowledge to find out about these things by myself. But the fact that one has to rely on others - by means of interrogating Game Boy owning friends - is/was a very good thing.</p>
<p>In <a href="https://jefklakscodex.com/articles/reviews/gobliins2/">Gobliins 2</a>, a point &amp; click adventure game from 1992, you can consult the hint system if you&rsquo;re stuck - only a couple of times <strong>per game</strong>. They call these &ldquo;jokers&rdquo;: once you&rsquo;ve used them all up, it&rsquo;s up to you to figure out the puzzle yourself. That meant frenetically writing down the English text, asking someone to translate it for me (I was 7), and still scratching your head because the hints were mostly cryptic. I loved the limitedness of these jokers. Every adventure players knows this dilemma if they&rsquo;re stuck: to look up a walkthrough or not? The fact that it&rsquo;s become easier means having to exercise more cognitive demanding willpower not do to it. After all, it&rsquo;s only two clicks away.</p>
<p><figure>
<a href="../d2cows.jpg" class="lbox">
<img loading="lazy" src="../d2cows.jpg" title="Moo-mo-momo-mooh! Src: Diablo Wikia">
</a>
<figcaption>Moo-mo-momo-mooh! Src: Diablo Wikia</figcaption>
</figure>
</p>
<p>When she was little, my wife played the game Lucky Luke on the Super Nintendo, a tough run-and-gun 2D game that employs a common strategy to prolong the play time of older games: it&rsquo;s hard and you get limited continues. When she was stuck on a certain part, only with one continue left, she paused the game and had her father call a support line. In the early nineties, it was actually possible to telephone an anonymous expert and yell &ldquo;<em>Help, only one continue left, should I go left or right in that mine tunnel?</em>&rdquo; Of course, you&rsquo;d only do that if (1) you were <em>really, really</em> stuck, and (2) you had the money to pay the expensive telephone bill.</p>
<p>Information has always been available: whether in game magazines, through support lines, or on the internet. The fact that it has become as easy as grabbing your smartphone and typing a few keywords inevitably means guides and walkthroughs will be consulted much more often<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. And that will make or break that gaming experience&hellip;</p>
<h3 id="a-case-in-favor-of-availability-of-information">A case in favor of availability of information</h3>
<p>Without guides, I probably would not have enjoyed games as much as I do. As a kid, I printed out maps and class guides of <em>Might and Magic VIII</em>, a first person RPG released in 2000 by New World Computing. Without this information, the game would become a slog quite quickly, as you need to travel to masters of certain skills to hone your own, and these are scattered throughout the world and sometimes very hard to track down. Furthermore, if you created a character that specializes in certain skills, only to discover halfway through that these skills you invested in totally sucked, you&rsquo;d probably never make it to the finish line. Thank you, <a href="http://www.zimlab.com/wizardry/recovered/flamestryke/mm8/flamestrykes_mm8.html">Flamestryke&rsquo;s MM8 Wiki</a>.</p>
<p>Of course the internet - and the instant availability of information - made our lives as a gamer easier. Yet, there&rsquo;s a thin line between <em>easier</em> and <em>too easy</em>, and lately, I have the feeling that I&rsquo;m unconsciously leaning towards the latter.</p>
<p>In the end, there&rsquo;s always the <a href="https://www.retromags.com">retromags.com</a> and <a href="https://archive.org/details/gamemagazines">Internet Archive Game Magazine</a> databases to dig through, but that&rsquo;s beside the point. The point is that instant gratification has become the norm, not the exception, and I&rsquo;m typing this to point a finger to someone in particular: me.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>This also frequently happens when having a conversation or watching television, and encountering something you don&rsquo;t know yet, or want to brag about (especially that). Whip out that smartphone and prove them wrong! One of the consequences of this is an <em>&ldquo;I&rsquo;m sorry, what was it that you said?&quot;</em> conversation. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 19 November 2020.
</p>
]]>
</description>
</item>
<item>
<title>WinXP Upgrade: Sound Blaster X-Fi</title>
<link>https://brainbaking.com/post/2020/11/winxp-upgrade-sound-blaster-xfi/</link>
<comments>https://brainbaking.com/post/2020/11/winxp-upgrade-sound-blaster-xfi/#commento</comments>
<pubDate>Sun, 08 Nov 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/11/winxp-upgrade-sound-blaster-xfi/</guid>
<category domain="https://brainbaking.com/tags/soundblaster">soundblaster</category>
<category domain="https://brainbaking.com/tags/winxp">winxp</category>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/xfi.jpg"/>
</p>
<p>Ever since the &ldquo;<em>Sound Blaster</em>&rdquo; brand became iconic in those <a href="/post/2020/09/486-upgrade-sound-blaster/">486 PCs</a>, I became a big fan of most products Creative brought to the market. Their iconic big boxes that accompanied new sound cards were always a joy to open up, and the last PCI card in their Sound Blaster range from 2005, the X-Fi, is no different.</p>
<p>I&rsquo;ve been doing some research on the Sound Blaster family, and Wikipedia <a href="https://en.wikipedia.org/wiki/Sound_Blaster">summarizes the cards</a> quite nicely. In short, there are 5 generations of older cards I&rsquo;m interested in:</p>
<ol>
<li>8-BIT ISA cards, the original <em>Sound Blaster 1.0/2.0</em> (1989);</li>
<li>16-BIT ISA cards, the <em>SB Pro 1.0/2.0</em> (1991);</li>
<li>The <em>Sound Blaster 16</em>, which I <a href="/post/2020/09/486-upgrade-sound-blaster/">wrote about</a> earlier, and <em>Vibra 16</em> (1992);</li>
<li>The <em>AWE32</em> (1994) and <em>AWE64</em> (1996) digital sample-based synthesis cards;</li>
<li>The PCI cards; roughly divided in <em>PCI128</em>/<em>AudioPCI</em> and <em>Live!</em> (1998), the <em>Audigy</em> (2001), and the <em>X-Fi</em> (2005).</li>
</ol>
<p>My <a href="/post/2020/10/building-a-core2duo-winxp-retro-pc/">WinXP retro machine</a> never housed a soundcard: instead, it was the first PC I built that relied on embedded, onboard audio, coming from the motherboard. The <a href="https://www.manualslib.com/manual/709493/Msi-Ms-7357-V1-X.html?page=75#manual">MSI MS-7357</a> mobo has a Realtek <code>ALC888</code> audio chip soldered on that is capable enough in its own right. However, it pales in comparison with the Sound Blaster X-Fi or <em>eXtreme Fidelity</em>.</p>
<p><figure>
<a href="../xfi.jpg" class="lbox">
<img loading="lazy" src="../xfi.jpg" title="The Sound Blaster X-Fi PCI Xtreme Music Edition.">
</a>
<figcaption>The Sound Blaster X-Fi PCI Xtreme Music Edition.</figcaption>
</figure>
</p>
<p>Multiple versions of the card exist, but luckily, in comparison to the confusing <em>Live!</em> or <em>SB16</em> revisions (of which there are good and less than stellar cards to pick from), the differences are negligible. Well, that&rsquo;s not entirely true, as there exist different <a href="https://en.wikipedia.org/wiki/E-mu_20K">chip versions</a> of the <code>EMU20K1</code> audio chips with a bit of increased RAM. I went ahead and ordered the cheapest I could find for <code>18EUR</code>, apparently the <em>Extreme Music</em> variant. It sadly came without awesome looking drive bay as the <em>Fatal1ty</em> pro ones, but the <code>AD_EXT</code> pins are all there, so that&rsquo;s for on the wish list.</p>
<p>Now, what does this card do, compared to its elder brother the Audigy, or even the well-loved Audigy 2 ZS, the &ldquo;best&rdquo; Win9x card? According to Wikipedia, it was:</p>
<blockquote>
<p>The most powerful, offering an extremely robust sample rate conversion engine in addition to enhanced internal sound channel routing options and greater 3D audio enhancement capabilities.</p>
</blockquote>
<p>What does that mean? Well, the 51 million transistors operating at <code>400 MHz</code> compute about <strong>24 times</strong> faster than the Audigy processor. Okay, so it&rsquo;s <em>very</em> speedy. What else? Well, it has EAX 5.0 support, a 24-bit crystallizer that can emphasize low or high pitched portions of sound, a completely overhauled sampling engine and better mixing support, &hellip; The list goes on.</p>
<p>I love the neat placement of the micro resistors and the overall look and feel of this black card:</p>
<p><figure>
<a href="../xfi-zoom.jpg" class="lbox">
<img loading="lazy" src="../xfi-zoom.jpg" title="Don&#39;t you just love the intricate details (and powerful opamps) on here?">
</a>
<figcaption>Don&#39;t you just love the intricate details (and powerful opamps) on here?</figcaption>
</figure>
</p>
<h3 id="in-game-performance">In-Game Performance</h3>
<p>We&rsquo;re off to a good start here. After slotting it in and installing the drivers and tools, it&rsquo;s time for some games (and for more fiddling with settings). I disabled the Realtek chip in the BIOS to avoid conflicts or loading of unused drivers.</p>
<p>Most games sound just a little bit more clear, but I am no audiophile. Admittedly, the initial excitement wore off pretty quickly. The main problem is that it is very hard to directly compare onboard audio with something like this without changing the default audio settings in the Creative tools and the games themselves. Furthermore, recording samples for this article sound like crap on my MacBook Air because of the <em>Intel HD Audio</em> system. It seems that writing about subtle audio differences is much easier than adding an audio excerpt: it will depend on the audio hardware you have installed yourself when listening to it!</p>
<p>For example, this is a short Unreal Tournament 2004 clip, where audio hardware acceleration and EAX is turned on and off, <em>before</em> fiddling with the Creative Console to increase the bass:</p>
<div class="video-mask">
<video width="100%" controls preload="metadata">
<source src="/vid/ut2004_withoutbass.mp4#t=0.5" type="video/mp4">
Your browser does not support HTML video. Here's a link to the MP4-encoded video instead: <a href="/vid/ut2004_withoutbass.mp4">/vid/ut2004_withoutbass.mp4</a>.
</video>
</div>
<p>However feeble my attempt to capture the deltas, nobody will deny the superiority of EAX-enhanced sound. Next, I switched on <em>Bass Boost</em> and the X-Fi <em>Crystallizer</em>. Notice the bassy &ldquo;thuds&rdquo; when clicking on the buttons in the upper menu. It sounds very hollow on my MacBook, but the difference is there:</p>
<div class="video-mask">
<video width="100%" controls preload="metadata">
<source src="/vid/ut2004_withbass.mp4#t=0.5" type="video/mp4">
Your browser does not support HTML video. Here's a link to the MP4-encoded video instead: <a href="/vid/ut2004_withbass.mp4">/vid/ut2004_withbass.mp4</a>.
</video>
</div>
<p>When actually playing, the game sounds absolutely <em>fantastic</em>! The difference is even more pronounced when plugging in high quality headphones, thanks to the CMSS-3D feature of the sound card: the X-Fi 3D virtualization does a great job in giving the illusion of being fully immersed in the sound and music. Admittedly, the difference between the Realtek and the X-Fi, without relying on the added features, is far from mind-blowing. As <a href="https://www.tomshardware.com/reviews/high-end-pc-audio,3733-19.html">Tom&rsquo;s Hardware</a> already pointed out (in 2014), <em>anything above $2 buys more features, not better quality</em>. CMSS 3D and EAX do add to the total quality, though.</p>
<h4 id="fps-performance">FPS Performance</h4>
<p>According to hardware reviews such as <a href="https://www.guru3d.com/articles_pages/x_fi_xtreme_music_sound_blaster_review,1.html">Guru 3D</a>, the fast <code>EMU20K1</code> chip should even give a graphics performance boost: less work for your CPU to be done. However, I measured FPS on multiple games, and I could not see a substantial fluctuation between normal (embedded) audio or hardware-enabled (X-Fi) audio. That might be because my system is already quite powerful for a 2005 computer, or because the Realtek chip does the job good enough, or because the games are programmed the way they are.</p>
<p>To be fair, there was a <em>slight</em> performance gain:</p>
<p><figure>
<a href="../xfiperformance.jpg" class="lbox">
<img loading="lazy" src="../xfiperformance.jpg" alt="xfi performance chart" >
</a>
</figure>
</p>
<p>The real gain is proper EAX support, superior IN/OUT ports, bass boost, virtual 3D audio stuff, etc &hellip; The card software even lets you choose something called &ldquo;<em>Sound Banks</em>&rdquo; for MIDI synthesizing if that&rsquo;s your thing or if you plan to emulate an ISA Sound Blaster card in Win9x compatibility mode:</p>
<p><figure>
<a href="../xfitools.jpg" class="lbox">
<img loading="lazy" src="../xfitools.jpg" title="A bunch of Creative Tools to fiddle with various settings.">
</a>
<figcaption>A bunch of Creative Tools to fiddle with various settings.</figcaption>
</figure>
</p>
<p>To convince the reader that the X-Fi is very capable of pulling off DOS music tricks, by configuring games to use <em>&ldquo;GENERAL MIDI&rdquo;</em>, here are some Rise of the Triad music samples originating from my <a href="/post/2020/09/486-upgrade-sound-blaster">SB16 article</a>. Recorded with the X-Fi, on my 486 with the SB16 Sound Blaster music option:</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_sb16.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_sb16.mp3">/audio/ROTT_sb16.mp3</a>.
</video>
</div>
<p>The same SB16, with the S2 WaveBlaster daughterboard enabled:</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_waveblaster.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_waveblaster.mp3">/audio/ROTT_waveblaster.mp3</a>.
</video>
</div>
<p>On WinXP with the X-Fi and General MIDI, using sound font &ldquo;<a href="https://www.philscomputerlab.com/general-midi-and-soundfonts.html">ChromiumRevA</a>&quot;:</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_XFi_Chorium.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_XFi_Chorium.mp3">/audio/ROTT_XFi_Chorium.mp3</a>.
</video>
</div>
<p><em>Oh my, oh my</em>. I&rsquo;m not sure whether I prefer this over the S2, but it might convince me to occasionally play older games in DOSBox again! There are more cool sound fonts available, there is no definitive version, it all depends on the game.</p>
<p>I can happily conclude that the PCI slot will remain to be occupied by the X-Fi card, and the embedded audio will remain to be disabled. If it was all worth it for casual games such as playing <em>Plants VS Zombies</em> without headphones, I don&rsquo;t know&hellip; But for a few (European) bucks, why wouldn&rsquo;t you? Grab them now before they become as scarce as the upper tier Sound Blaster 16 cards!</p>
<p>More information:</p>
<ul>
<li>LGR <a href="https://www.youtube.com/watch?v=-TpGtrhpDuI&amp;t=326s">X-Fi Platinum XP Upgrade</a></li>
<li>Phils Computer Lab <a href="https://www.youtube.com/watch?v=gSBMrHfsXjE">Sound Blaster X-Fi MB3</a> review</li>
<li><code>AD_EXT</code> <a href="https://pinouts.ru/Audio-Video-Hardware/sb_audigy2_ad_ext_pinout.shtml">pinout scheme</a> - the same as Audigy&rsquo;s <code>AUD_EXT</code>. It is possible to tap into SPDIF, MIDI, and GP signals separately. Note that your front panel headphone jack will likely pick up static noise except if it&rsquo;s wired directly onto the Sound Blaster using these pins. Another reason to buy the drive bay!</li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 8 November 2020.
</p>
]]>
</description>
</item>
<item>
<title>Personal Desktop Screenshots of Olde</title>
<link>https://brainbaking.com/post/2020/11/desktop-screenshots-of-olde/</link>
<comments>https://brainbaking.com/post/2020/11/desktop-screenshots-of-olde/#commento</comments>
<pubDate>Sun, 01 Nov 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/11/desktop-screenshots-of-olde/</guid>
<category domain="https://brainbaking.com/tags/linux">linux</category>
<description>
<![CDATA[
<p>Rummaging through old data is fun. It&rsquo;s like rediscovering a part of yourself you have long forgotten. Since the last few months I&rsquo;m in a nostalgic hardware mood, let&rsquo;s revisit some old desktops of which I meticulously kept screenshots from 2004 to 2008 from various systems. Sadly, the SuSE Linux <code>6.3</code> screenshots are forever gone&hellip; And before 2003, it was not yet cool enough to share desktop screens on-line (that is: I didn&rsquo;t know how!).</p>
<h3 id="the-gentoo-linux-20040-machine">The Gentoo Linux 2004.0 Machine</h3>
<p>Once I got hooked on Linux during my first university years, I decided in order to become a real pro, one has to install everything form source. <em>Every-thing</em> (Gentoo). Oh, and kernel-patch your own vanilla Linux kernel - that too. Many weeks later; I discovered FVWM, and after even more weeks of fiddling with config files, my desktop looked like this:</p>
<p><figure>
<a href="/img/desktopshots/feb2004.jpg" class="lbox">
<img loading="lazy" src="/img/desktopshots/feb2004.jpg" title="FVWM, 02/2004">
</a>
<figcaption>FVWM, 02/2004</figcaption>
</figure>
</p>
<p>Remember the floating duck, that indicates CPU/Memory usage? The more water, the more RAM, and the more waves, the more CPU usage. Funny, and completely useless.
A few months later, the status bar started to look like a cheap OSX knock-off:</p>
<p><figure>
<a href="/img/desktopshots/fvwm_aug2004.jpg" class="lbox">
<img loading="lazy" src="/img/desktopshots/fvwm_aug2004.jpg" title="FVWM, 08/2004">
</a>
<figcaption>FVWM, 08/2004</figcaption>
</figure>
</p>
<p>I still remember it took me ages to get the battery and temperature levels working (on the bottom right). <code>ACPI</code> and Linux <code>2.4</code> were not playing along, and the ugly Perl scripts didn&rsquo;t particularly help either. At least I remembered correctly to take a screenshot while the context-menu is open to showcase it can do <em>transparency</em>! Wowza! That was something that required a lot of effort back in the day, and even hardware acceleration.</p>
<p><figure>
<a href="/img/desktopshots/lila_sept2004.jpg" class="lbox">
<img loading="lazy" src="/img/desktopshots/lila_sept2004.jpg" title="FVWM, 09/2004">
</a>
<figcaption>FVWM, 09/2004</figcaption>
</figure>
</p>
<p>The next month, it looks like the then popular &ldquo;Lila icons&rdquo; made its way to my machine, and I started loving Xfce&rsquo;s file manager, &ldquo;<a href="https://docs.xfce.org/xfce/thunar/start">Thunar</a>&rdquo;. It still exists today. Xfce 4 was a big step up but couldn&rsquo;t dethrone FVWM - instead, I ended up using its tools. Still not satisfied with the big icons on the menu, I decided to make them even more Mac-alike by zooming in on hover:</p>
<p><figure>
<a href="/img/desktopshots/engagebusy_febr2005.jpg" class="lbox">
<img loading="lazy" src="/img/desktopshots/engagebusy_febr2005.jpg" title="FVWM, 02/2005">
</a>
<figcaption>FVWM, 02/2005</figcaption>
</figure>
</p>
<p>While sticking to my faithful FVWM window manager, I did take a peek or two at <a href="https://www.enlightenment.org">Enlightenment</a>&rsquo;s alpha version &ldquo;<code>E17</code>&rdquo;, that eventually did get released in 2013. Note the Linux kernel on the upper left: <strong>2.6.9-nitro4</strong>. That&rsquo;s right, in 2005, I switched from 2.4 to a bleeding edge thing, and even reformatted the whole thing in ReiserFS!</p>
<h3 id="from-gentoo-to-freebsd-53">From Gentoo to FreeBSD 5.3</h3>
<p>In 2005, something else happened. I got tired of compiling everything from scratch, and fixing countless of <code>./configure</code> and <code>make</code> scripts. I got tired of Linux all-together and decided to try a BSD alternative - of course further tweaking my beloved FVWM configs:</p>
<p><figure>
<a href="/img/desktopshots/fvwm_confnew_20051027_1.jpg" class="lbox">
<img loading="lazy" src="/img/desktopshots/fvwm_confnew_20051027_1.jpg" title="FVWM@FreeBSD, 27/10/2005">
</a>
<figcaption>FVWM@FreeBSD, 27/10/2005</figcaption>
</figure>
</p>
<p>It did not last long. When I graduated in 2007, my work life took over and prevented me to fiddle with config files. Free time was best spend <em>off</em>-screen. I did, however, still play and fiddle with my WinXP machine.</p>
<h3 id="the-windows-xp-32-bit-machine">The Windows XP 32-bit Machine</h3>
<p><figure>
<a href="/img/desktopshots/Win32_Clean_11-05-2005.JPG" class="lbox">
<img loading="lazy" src="/img/desktopshots/Win32_Clean_11-05-2005.JPG" title="WinXP, 11/05/2005">
</a>
<figcaption>WinXP, 11/05/2005</figcaption>
</figure>
</p>
<p>It was usually kept clean, with a gaming-related background, and of course gaming-related shortcuts on the desktop itself. The theme looks like it&rsquo;s WindowBlinds, however. However, on some screenshots I recognize work from my thesis in 2007. It seems that <code>LaTeX</code> compilation was also done on Windows. Because why not.</p>
<p><figure>
<a href="/img/desktopshots/20070128_win32_mooi.jpg" class="lbox">
<img loading="lazy" src="/img/desktopshots/20070128_win32_mooi.jpg" title="WinXP, 28/01/2007">
</a>
<figcaption>WinXP, 28/01/2007</figcaption>
</figure>
</p>
<p>Note the Systray icons: MSN Messenger, CPU temp/fan control of my then powerful <a href="https://www.cnet.com/reviews/dell-inspiron-5150-5150sap-review/">Dell Inspiron 5150</a> laptop with a Pentium IV <code>3 GHz</code> CPU, battery, a globe with an &ldquo;<code>a</code>&rdquo; symbol I cannot remember, and <a href="https://symless.com/synergy">Synergy</a>, a handy tool (then free, now <code>$29</code>) which allowed me to utilize one keyboard/mouse to control both laptop and desktop PC.</p>
<p>However, after being fed up with the default XP colors, I apparently decided to try something radically different. I&rsquo;m sure it involved WindowBlinds and other fancy things I cannot remember anymore. Do you recognize Windows XP in the following screenshot? I don&rsquo;t. I must have been bored.</p>
<p><figure>
<a href="/img/desktopshots/klaklan_20072002.jpg" class="lbox">
<img loading="lazy" src="/img/desktopshots/klaklan_20072002.jpg" title="WinXP, 20/02/2007">
</a>
<figcaption>WinXP, 20/02/2007</figcaption>
</figure>
</p>
<p>The Windows Explorer thing gives it away. No wait, the <code>uname -a</code> output does: &ldquo;<code>MINGW32_NT-5.1</code>&rdquo; Why install gVim/MSys *Nix tools on there when you can dual boot and have a Unix-powered laptop nearby? Because we can?</p>
<h3 id="osx-1011">OSX 10.11</h3>
<p>In 2012, I bought a MacBook Air to carry with me on the train ride to work. It changed the way I work forever, and I never looked back. All the Unix tools are there, and all the simplicity and ease of use is there. It&rsquo;s an old laptop by 2020 means (Only updated until 10.11), but still works well:</p>
<p><figure>
<a href="/img/desktopshots/osx.jpg" class="lbox">
<img loading="lazy" src="/img/desktopshots/osx.jpg" title="OSX 10.11, 11/2020">
</a>
<figcaption>OSX 10.11, 11/2020</figcaption>
</figure>
</p>
<p>I recently <a href="/post/2020/12/developing-on-apple-m1-silicon/">Upgraded to a M1 Silicon MacBook</a>. Besides throwing away illegal <code>.mp3</code> files in favor for a Spotify subscription, I also traded in (g)Vim for Sublime Text 3 because I was never that good at Vi&rsquo;s shortcut scheme anyway. I still have installed and occasionally work on Linux distributions but can&rsquo;t bring myself to put in enough time to decently configure it. Instead, a quick Ubuntu install does the job. It&rsquo;s far from amazing or my golden &ldquo;FVWM Years&rdquo;, but again: it works.</p>
<p>And that&rsquo;s good enough for me, in 2020.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 November 2020.
</p>
]]>
</description>
</item>
<item>
<title>Building a Core2Duo Windows XP Retro PC</title>
<link>https://brainbaking.com/post/2020/10/building-a-core2duo-winxp-retro-pc/</link>
<comments>https://brainbaking.com/post/2020/10/building-a-core2duo-winxp-retro-pc/#commento</comments>
<pubDate>Sun, 25 Oct 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/10/building-a-core2duo-winxp-retro-pc/</guid>
<category domain="https://brainbaking.com/tags/winxp">winxp</category>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>Earlier in October, I blogged about <a href="/post/2020/10/building-an-athlon-win98-retro-pc/">building an athlon win98 PC</a> which allowed me to replay Quake 1, 2, and 3 on original hardware. It is time to move on from Windows 98 and take the leap of faith, from DOS-based Windows operating systems, to one of the most popular Windows flavours of olde: Windows XP, released in 2001. XP was indeed a bit special becuase it was supposed to replace both Windows Me for &ldquo;home users&rdquo; and Windows 2000 for &ldquo;profs&rdquo; (although out of frustration, I ended up working with NT-based systems more often than DOS-based). WinXP&rsquo;s legacy only increased due to the unstable mess of its successor, Windows Vista.</p>
<p>The classic OS has had an extremely long lifespan, being discontinued in 2008, and having had the luxury of three officially released service packs. Generally speaking, there are also three &ldquo;WinXP era&rdquo; PC builds to be put together:</p>
<ol>
<li>Early WinXP (2001): <code>512 MB</code> SD RAM, Pentium III/IV <code>2 GHz</code>, GeForce 3/4 AGP</li>
<li>Mid WinXP (2003): <code>1 GB</code> DDR RAM, Pentium IV <code>3 GHz</code> GeForce FX AGP</li>
<li>Late WinXP (2006): <code>2 GB</code> DDR2 RAM, Core2Duo <code>2 GHz</code>, GeForce 8800 GTS PCI-E</li>
</ol>
<p>Technology evolved rapidly (as usual) during these times: from SD to DDR, from single to dual core, and from AGP interfaces to <a href="https://nl.wikipedia.org/wiki/PCI_Express">PCI Express</a> in 2004. Since I have a fairly powerful Win98SE build with <code>512MB</code> SD RAM, I am more interested in era two and three. Back in 2007, I completely redid my gaming rig, focused on <strong>noise reduction</strong>. I slowly but surely hated the noisy stock Athlon fans and had discovered <a href="https://silentpcreview.com">silentpcreview.com</a> and their excellent community forums. Based on silence before power, I put together a lovely horizontal desktop PC with a sleek looking Antec case.</p>
<h3 id="so-which-specs">So&hellip; Which specs?</h3>
<p>In 2007, I had just begun to work, so I was still on a budget. The Core2Duo CPUs were becoming mainstream and pushed out single cores for good, while the GeForce 8800 GTS was the top of the line if you wanted to push those frames per second to the limit - including the excess noise and heat generation. Since I wanted silence, I got a fanless passive 8600GT - a mistake, since in my microATX case I couldn&rsquo;t get rid of the heat. The GPU easily peaked towards <code>80°C</code>, not something I was comfortable with. I ended up adding another fan between the graphics card and my TV card, losing two more slots.</p>
<p><figure>
<a href="../winxp-geforce.jpg" class="lbox">
<img loading="lazy" src="../winxp-geforce.jpg" title="GeForce 8600GT (left) and Radeon HD5570 (right).">
</a>
<figcaption>GeForce 8600GT (left) and Radeon HD5570 (right).</figcaption>
</figure>
</p>
<p>When I rescued the PC from a dusty closet earlier this month, I went over the options again. I had spare parts lying around from a more recent 2012 Core i5 build, and ultimately decided to swap graphics cards. The AMD Radeon HD5570, as you can see from the photo above, is a lot less beefy:</p>
<ul>
<li>It has a HDMI output port (Not very WinXP-ish but hey, it&rsquo;s there);</li>
<li>It&rsquo;s a single-slot card and my case is small;</li>
<li>It&rsquo;s <em>much</em> more powerful (<code>1 GB</code> DDR3 VRAM??), and <em>much</em> more energy-friendly.</li>
<li>It&rsquo;s free&hellip;</li>
</ul>
<p>The biggest disadvantage is the whiny tiny fan that loves to make a LOT of noise - not exactly what I was aiming for. A <code>5V</code> molex mod luckily shut it up. Also, buying a 8800GTS would force me to upgrade my <code>350W</code> PSU. The full build looks like this:</p>
<ul>
<li>Intel <a href="https://nl.wikipedia.org/wiki/Intel_Core_2">Core2Duo</a> E6550@<code>2.3 GHz</code></li>
<li><a href="https://www.cpu-upgrade.com/mb-MSI/G33M_(MS-7357).html">MSI G33M MS-7357</a> DDR2 micro-motherboard, PCI-E 1.0</li>
<li>2x<code>1 GB</code> Geil Dual Channel DDR2-RAM</li>
<li>Seagate <a href="https://nl.hddzone.com/seagate-st3320620as-harde-schijf-pcb/">Barracuda 7200.10 RPM</a> <code>320 GB</code> HDD</li>
<li>AMD Radeon HD5570</li>
<li>Integrated audio and network ports (I might change that someday)</li>
<li><a href="https://techgage.com/article/antec_nsk2400_htpc_case/">Antec NSK2400 HTPC Case</a> Silent</li>
<li>Coupled with the awesome <a href="https://www.cnet.com/products/dell-ultrasharp-2007wfp-series/specs/">Dell UltraSharp 2007WFP</a> 20&quot; wide-screen IPS monitor.</li>
</ul>
<p>I&rsquo;m not too worried about the retro-correctness &ldquo;level&rdquo; of things inside the case, but the HD5570 is an <code>$80</code> entry-level card from 2012, so it&rsquo;s not too unbalanced. A few days ago, I bought a Core2Duo E7400@<code>2.8 GHz</code> for only <code>5 EUR</code> but sadly my motherboard refused to accept it as I cannot seem to get past POST with it installed in the socket 775 holder. Oh well, the difference won&rsquo;t be groundbreaking.</p>
<p><figure>
<a href="../winxp-cores.jpg" class="lbox">
<img loading="lazy" src="../winxp-cores.jpg" title="Installing the core and mounting the cooling block.">
</a>
<figcaption>Installing the core and mounting the cooling block.</figcaption>
</figure>
</p>
<p>Every single fan inside the case has been modded: <code>7V</code> for the <code>350W</code> PSU and both Nexus Silent 120mm orange fans, and <code>5V</code> for the tiny AMD thing. The CPU cooler was mounted with a silent 80mm Bapst fan. The result? The GPU fan is <strong>still</strong> the noisiest! Nevertheless, Heat dissipation is good enough. The Nexus fans can&rsquo;t reach the back of the PCI-E cards so the passive 8600GT was never a good idea. The Radeon peaks to <code>60°C</code> with a small <code>5V</code> fan, still way below dangerous levels.</p>
<h3 id="performance">Performance</h3>
<p>Simply put: it&rsquo;s great. Until your heart desires playing The Witcher 2 on a decent resolution with medium settings: the game runs relatively smooth but doesn&rsquo;t go beyond 18FPS. Still, for such a system, it&rsquo;s good enough for me. Looking at the <a href="https://www.systemrequirementslab.com/cyri/requirements/the-witcher-2-assassins-of-kings/11073">minimum specifications</a> of the game, it seems that CPU/RAM is the bottleneck here. Whatever - most games I will be playing will be either early to mid winxp-era games anyway. Unreal Tournament 2004? +100FPS. Rainbow Six 3: Raven Shield? Capped at a comfortable 60FPS. Age of Empires III - a game I somehow never managed to run? +60FPS. Neverwinter Nights 2 struggles running smoothly, but that&rsquo;s due to the sluggish engine implementation.</p>
<p><figure>
<a href="../winxp3-aoe3.jpg" class="lbox">
<img loading="lazy" src="../winxp3-aoe3.jpg" title="Age of Empires III, everything maxed, on 1680x1050: above 60FPS.">
</a>
<figcaption>Age of Empires III, everything maxed, on 1680x1050: above 60FPS.</figcaption>
</figure>
</p>
<p>Even DScaler 4.x coupled with my trusty Pinnacle PCTV Rave PCI TV-Card works like a charm, connecting the Composite output of my GameCube to the system. That&rsquo;s how I played console games in 2003&hellip; Fortunately, nowadays we can safely replace a blurry mess with razor-sharp pixels outputted by FPGA-powered projects like Carby or the <a href="https://www.eongaming.tech/product-page/gchd-mk-ii-hdmindigo">EON GCHD Mk-II</a> adapter. That means I moved my trusty silver GameCube to a newer HDMI-enabled screen. I might try HDMI PCI-E capture cards next in this build, but the motherboard is only capable of PCI-E 1.0 speeds (<code>250 MB</code>/s per pin instead of PCI-E 2.0&rsquo;s <code>500 MB</code>).</p>
<p>After installing some games and tweaking Windows a bit:</p>
<p><figure>
<a href="../winxp1.jpg" class="lbox">
<img loading="lazy" src="../winxp1.jpg" title="The WinXP Service Pack 3 System Properties with a cold GPU.">
</a>
<figcaption>The WinXP Service Pack 3 System Properties with a cold GPU.</figcaption>
</figure>
</p>
<p>So that&rsquo;s it, now I own a 486 DX2-66 <a href="/post/2020/09/reviving-a-80486">DOS 6.22/Windows 3.11</a> PC, an <a href="/post/2020/10/building-an-athlon-win98-retro-pc/">Athlon Windows 98SE</a> PC, and a &ldquo;newer&rdquo; late era Windows XP machine! I had to completely reorganize my office space to accommodate all three computers including a newer screen and space for my work MacBook - but it was all worth it! Maybe one day I will be brave enough to take photos of the space and upload it to <a href="https://www.reddit.com/r/retrobattlestations/">Reddit&rsquo;s Retro Battle Stations</a>.</p>
<p>Oh, and never install Windows XP on a hard disk that already contains a Linux distribution. Microsoft installers love to overwrite the Master Boot Record without asking&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 25 October 2020.
</p>
]]>
</description>
</item>
<item>
<title>Building an Athlon Windows 98 Retro PC</title>
<link>https://brainbaking.com/post/2020/10/building-an-athlon-win98-retro-pc/</link>
<comments>https://brainbaking.com/post/2020/10/building-an-athlon-win98-retro-pc/#commento</comments>
<pubDate>Sat, 17 Oct 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/10/building-an-athlon-win98-retro-pc/</guid>
<category domain="https://brainbaking.com/tags/win98">win98</category>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>After the previous months' <a href="/post/2020/09/reviving-a-80486/">reviving of a 80486 PC</a>, including <a href="/post/2020/09/486-upgrade-sd-hdd/">upgrade 1</a> and <a href="/post/2020/09/486-upgrade-sound-blaster/">upgrade 2</a>, it is time to revisit the last decent DOS-based Windows operating system: Windows 98 Second Edition. Earlier, I admitted the <code>66MHz</code> DX2 processor just wasn&rsquo;t good enough for Duke3D and Quake. I do have a Windows XP box (meat for another blog post), so I wanted to build something in-between. And yes, I will happily ignore the existence of Windows Me(h).</p>
<p>The 486 PC is able to run games from the early eighties to 1995. My Windows XP machine is a late WinXP era PC that is able to play games up to 2011. I needed something that sits comfortably in between these two timelines. The original Pentium CPU wasn&rsquo;t on my mind since a fast 486 (DX4) is able to beat it. As a kid, in the year 2000 I was a proud owner of a newly released AMD Athlon Thunderbird <code>1GHz</code>, upgrading from a Pentium II. It was the year of the Gigahertz barrier breach:</p>
<p><figure>
<a href="../ClockSpeed.png" class="lbox">
<img loading="lazy" src="../ClockSpeed.png" title="Stock CPU clock speed history. Source: maximumpc.com">
</a>
<figcaption>Stock CPU clock speed history. Source: maximumpc.com</figcaption>
</figure>
</p>
<p>As clearly visible in <a href="https://web.archive.org/web/20150418074002/http://www.maximumpc.com:80/article/home/history_dream_how_ultimate_pc_has_evolved_15_years">the graph</a>, 2000 was a big turning point for CPU speed. The Thunderbird was one of the first, that was also easily overclockable. AMD&rsquo;s K7 Athlon XP breached <code>2GHz</code> only two years later. So, the quest became clear and my mind was set: chasing nostalgic values again. I even managed to find my original <a href="https://www.cnet.com/products/aopen-hq45-mid-tower-atx-series/">AOpen HQ45 mid tower</a> again!</p>
<h3 id="so-which-specs">So&hellip; Which specs?</h3>
<p>I had no intentions to build a ridiculously overpowered &ldquo;<em>ultimate win98 gaming PC</em>&rdquo;, as many other bloggers <a href="https://www.tomvanbrienen.nl/building-a-new-ultimate-windows-98-retro-pc-in-2020/">like</a> <a href="https://retrorevive.enochdew.com/uwin98/">to</a> <a href="https://www.overclockers.co.uk/forums/threads/building-the-ultimate-windows-98-gaming-pc.18845723/">call</a> it, I wanted something with subjective nostalgic value that is able to run any game from 1996 till 2003. More than <code>500MHz</code> certainly is overkill if you only want Win98 to run smoothly. At work, I managed to salvage an <code>1.4GHz</code> Thunderbird that might still work. Alas, it turned out to be dead<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> - but at least the motherboard was okay.</p>
<p><figure>
<a href="../mobos.jpg" class="lbox">
<img loading="lazy" src="../mobos.jpg" title="Which motherboard to pick, which slots to prefer?">
</a>
<figcaption>Which motherboard to pick, which slots to prefer?</figcaption>
</figure>
</p>
<p>Another old and very much yellowed PC tucked away in a storage area brought salvation: it held an Athlon XP 2200+. That was not really what I was looking for, but the socket matched, and in the end I simply underclocked the newer CPU to <code>1.35GHz</code> by setting the FSB speed to 100 and switching out motherboards. It came with an AGPx8 board with DDR memory, and I was looking for a more authentic SD-based one.</p>
<p>It is important to take a moment to look at various motherboard features, such as the interfacing support. I found another old board with one ISA-slot, but it only supports socket-A CPUs up to <code>1.0GHz</code>. Do I really need an ISA-based Sound Blaster in this PC? The 486 will more than suffice for OPL3/WaveTable music. In the end, I chose a board that supports both DDR and SD (but not both), and went with the latter. This is what I managed to scrape together:</p>
<ul>
<li>AMD <a href="https://nl.wikipedia.org/wiki/Athlon_XP">Athlon XP Thoroughbred</a> 2200+ underclocked at <code>1.35GHz</code></li>
<li>Gigabyte/ECS <a href="https://soggi.org/motherboards/ecs-elitegroup/K7S5A.htm">K7S5A</a> motherboard (2xUSB1.1 and another USB1.1 header, wow!)</li>
<li>2x<code>256MB</code> PC133 Geil SD-RAM</li>
<li>Seagate Barracuda 7200rpm <code>80GB</code> IDE</li>
<li><a href="https://www.techpowerup.com/gpu-specs/riva-tnt2-m64.c1304">nVidia Riva TNT2 M64</a> OEM AGP graphics card</li>
<li>Creative <a href="https://en.wikipedia.org/wiki/Sound_Blaster#Fifth_generation_Sound_Blasters,_PCI_cards,_multi-channel_and_F/X">Sound Blaster PCI Vibra 128</a> (fifth gen.) - included with case</li>
<li>A generic Realtek Ethernet RJ-45/Coax jack PIC network card</li>
<li><a href="https://www.cnet.com/products/aopen-hq45-mid-tower-atx-series/">AOpen HQ45 ATX mid tower</a> with a newer <code>250W</code> PSU - <code>€50</code></li>
</ul>
<p>Although some of the cards aren&rsquo;t exactly something to write home about (A GeForce 3 Ti200 I once owned would also be authentic), they will do just fine until I come across something better. Ebay is sometimes too depressing: instant gratification at the cost of steep shipping prices.</p>
<p>This is what the assembled motherboard looks like:</p>
<p><figure>
<a href="../win98cards.jpg" class="lbox">
<img loading="lazy" src="../win98cards.jpg" title="Inside the belly of the Win98 PC - plenty of space left!">
</a>
<figcaption>Inside the belly of the Win98 PC - plenty of space left!</figcaption>
</figure>
</p>
<p>One of the things I did order as soon as I powered on the machine was a silent cooler. The stock Thermaltake socket A cooler pictured above sounds like a jet taking off! I might also drill some holes and install another Nexus 120mm system fan running at <code>7V</code> to get rid of the heat. The AOpen case isn&rsquo;t the best regarding air flow. Also, if anyone has suggestions on which cool/fun PCI/AMR cards to install, feel free leave a comment below.</p>
<h3 id="the-unstableness-of-windows-98-se">The (un)stableness of Windows 98 S.E.</h3>
<p>After <a href="https://winworldpc.com/product/windows-98/98-second-edition">downloading Windows 98</a> and burning the ISO (Burning a CD! The last time I did this was about 15 years ago. <em>Exciting!</em>), I was ready to FAT32-format the HDD with plenty of space for bigger games. The installation process blazed through in about 15 minutes (the specs are a bit high for a Win9x OS), but after the third reboot, blue screens started to appear. Here we go again&hellip;</p>
<p>Fortunately, a second clean reinstall fixed that. I must have missed something. Next up were the nVidia drivers, but how to transfer data from other PCs onto this one? Removable USB media was not recognized - neither was the first Ethernet card I installed. Internet Explorer 5 managed to open <a href="http://vogonsdrivers.com">vogonsdrivers.com</a> after swapping cards, allowing me to browse to proper Win9x USB drivers. A reboot or 20 later, my USB stick was finally working in Windows Explorer.</p>
<p>I decided to also install the <a href="http://htasoft.com/u98sesp/">Unofficial Win98SE Service Pack</a> 3.64, maintained by the community - that&rsquo;s why the screenshot below shows &lsquo;Windows ME&rsquo; in the System Settings. It contains a lot of upgraded system files from later operating systems. It&rsquo;s also possible to install a modern fork of Mozilla using something called &lsquo;KernelEx&rsquo;, a layer of Win2000/XP drivers that make it possible to run more Win programs on DOS-based Win systems. Ultimately, I decided against using that, as I have another WinXP machine and Opera 10 works with (some) HTTPS websites.</p>
<p><figure>
<a href="../win98screen1.jpg" class="lbox">
<img loading="lazy" src="../win98screen1.jpg" title="Win98 SE with an active Plus! theme. Wizardry 8 rearing to go!">
</a>
<figcaption>Win98 SE with an active Plus! theme. Wizardry 8 rearing to go!</figcaption>
</figure>
</p>
<p>The Pinnacle PCTV Rave PCI tuner card I once had installed in a case such as this one refused to work on Win98, while it works flawlessly on the WinXP machine. I do have to admit that back in the day I quickly switched from Win98/Me to NT4/2000 after being fed up with the frequent crashes, odd error messages on bootup/shutdown and general unstableness of the operating system. Even simply uninstalling stuff like the Pinnacle software and drivers caused problems after rebooting. The hardware specs certainly can handle Win2000/XP but solely for nostalgic reasons, I wanted one PC with Win9x.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Microsoft_Plus!">MS Plus!</a> themes still make me smile. Who doesn&rsquo;t like wiggling his mouse pointer all day if it&rsquo;s an animated bee, or hearing the startup/shutdown jungle noise? The first thing I did after the video/audio drivers was of course installing <a href="https://jefklakscodex.com/tags/wizardry8/">Wizardry 8</a>, my all-time favorite PC RPG, released in 2001. Now, on to GOG.com/my gaming rack to fetch Unreal Tournament/Diablo II/GTA2/Baldur&rsquo;s Gate/Might and Magic VIII and others!</p>
<p>Looking for more pictures of retro setups? Browse through Reddits' <a href="www.reddit.com/r/retrobattlestations/">Retro Battle Stations</a> page.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>We might have blown up that one. The old thermal paste and layers of dust on one of the motherboards started to smoke&hellip; <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 17 October 2020.
</p>
]]>
</description>
</item>
<item>
<title>A journey through the history of webdesign</title>
<link>https://brainbaking.com/post/2020/10/a-personal-journey-through-the-history-of-webdesign/</link>
<comments>https://brainbaking.com/post/2020/10/a-personal-journey-through-the-history-of-webdesign/#commento</comments>
<pubDate>Sun, 04 Oct 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/10/a-personal-journey-through-the-history-of-webdesign/</guid>
<description>
<![CDATA[
<p>While browsing through archives of <em>very</em> old files, I rediscovered backups of websites I once made. It felt a bit like scrolling <a href="https://thehistoryofweb.design/">thehistoryofweb.design</a>, an interactive journey through the history of webdesign. Thanks to the Internet Archive project, revisiting these now-offline websites was not only a very personal and nostalgic ride for me, but also an educational one.</p>
<p>Why not let the websites speak for themselves and follow the history together with me, from 1998 to 2020? I resurrected the static sites that weren&rsquo;t available at archive.org. The point here is not to &ldquo;<a href="https://scryfall.com/card/xln/117/revel-in-riches?utm_source=api">revel in riches</a>&rdquo; (ha!), but to inspect trends from yesteryear and compare them with how websites look like today.</p>
<h3 id="1998museum1998-marquee-bgsound-iframes-applets"><a href="/museum/1998">1998</a>: Marquee, bgsound, iframes, applets</h3>
<p>My first website, created more than 22 years ago, is still full of surprises. I was 13 and had no idea of what I was doing. Still, I managed to scrape together a decent looking webiste, filled with sound advice on how to write Visual Basic 6 code, and of course information on games. As soon as you open the site, you&rsquo;gre greeted with a nice looking background and GIF animation, and a a <code>&lt;bgsound/&gt;</code> tag that should start playing a MIDI file in Internet Explorer 4.</p>
<p><figure>
<a href="../site-1998.jpg" class="lbox">
<img loading="lazy" src="../site-1998.jpg" title="A part of my personal website in 1998.">
</a>
<figcaption>A part of my personal website in 1998.</figcaption>
</figure>
</p>
<p><a href="/museum/1998">View the 1998 website here</a>. It was hosted on <em>uunet.be</em>, an ISP provider in Belgium. If you were not content with that offer, <em>geocities.com</em> offered more disk space.</p>
<p>The following techniques were considered cool back then:</p>
<ul>
<li>Java applets</li>
<li>If using Javascript, remember to use <code>alert()</code></li>
<li><code>&lt;iframe/&gt;</code>s</li>
<li>Make things pop! Use background images, GIFs, add snow flake JS code when appropriate, spam <code>&lt;marquee/&gt;</code>, <code>&lt;bgsound/&gt;</code>, and <code>&lt;font/&gt;</code>.</li>
<li>Pre-process graphics in <em>Corel Draw</em> (remember that?)</li>
</ul>
<h3 id="2000museum2000-macromedia-flash-cookies"><a href="/museum/2000">2000</a>: Macromedia Flash, Cookies</h3>
<p>Since 1998, the popularity of Macromedia Flash exploded. The simplicity involved in creating morphing shapes allowed any website owner to have a classic but fancy &ldquo;intro page&rdquo;, before continuing on to &ldquo;index2.html&rdquo;. Since then, Flash was thé thing to include in any site. That was before 2005 when adobe decided to buy Macromedia. Before Sublime Text, there was another brilliant piece of Macromedia software: <em>DreamWeaver</em>.</p>
<p><figure>
<a href="../site-2000.jpg" class="lbox">
<img loading="lazy" src="../site-2000.jpg" title="&#39;aWhile Soft&#39;, my personal website in 2000.">
</a>
<figcaption>&#39;aWhile Soft&#39;, my personal website in 2000.</figcaption>
</figure>
</p>
<p><a href="/museum/2000">View the 2000 version here</a>. <a href="https://web.archive.org/web/20010705221029/http://www.awhilesoft.f2s.com/">View the revised 2001 version here</a>. Another artifact of webdesign history: <em>visitor counters</em>. Most in 1998 were hosted, but on this page I managed to hack together my own using cookies.</p>
<p>Posting news of course required changes in the HTML source code itself. I can&rsquo;t remember what tools I used back then, and the header code does not reveal that. However, there are two interesting things to see in the source:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#95a5a6">&lt;!--</span> <span style="color:#728e00">Begin</span>
<span style="color:#728e00">function</span> <span style="color:#728e00">right</span>(<span style="color:#728e00">e</span>) {
<span style="color:#728e00">if</span> (<span style="color:#728e00">navigator</span>.<span style="color:#728e00">appName</span> <span style="color:#728e00">==</span> <span style="color:#7f8c8d">&#39;Netscape&#39;</span> <span style="color:#728e00">&amp;&amp;</span>
(<span style="color:#728e00">e</span>.<span style="color:#728e00">which</span> <span style="color:#728e00">==</span> <span style="color:#8a7b52">3</span> <span style="color:#728e00">||</span> <span style="color:#728e00">e</span>.<span style="color:#728e00">which</span> <span style="color:#728e00">==</span> <span style="color:#8a7b52">2</span>))
<span style="color:#728e00">return</span> <span style="color:#00979d">false</span>;
<span style="color:#728e00">else</span> <span style="color:#728e00">if</span> (<span style="color:#728e00">navigator</span>.<span style="color:#728e00">appName</span> <span style="color:#728e00">==</span> <span style="color:#7f8c8d">&#39;Microsoft Internet Explorer&#39;</span> <span style="color:#728e00">&amp;&amp;</span>
(<span style="color:#728e00">event</span>.<span style="color:#728e00">button</span> <span style="color:#728e00">==</span> <span style="color:#8a7b52">2</span> <span style="color:#728e00">||</span> <span style="color:#728e00">event</span>.<span style="color:#728e00">button</span> <span style="color:#728e00">==</span> <span style="color:#8a7b52">3</span>)) {
<span style="color:#728e00">alert</span>(<span style="color:#7f8c8d">&#34;You&#39;re not allowed to use &#39;RightCLick&#39;.&#34;</span>);
<span style="color:#728e00">return</span> <span style="color:#00979d">false</span>;
}
<span style="color:#728e00">return</span> <span style="color:#00979d">true</span>;
}
<span style="color:#728e00">document</span>.<span style="color:#728e00">onmousedown</span><span style="color:#728e00">=</span><span style="color:#728e00">right</span>;
<span style="color:#728e00">document</span>.<span style="color:#728e00">onmouseup</span><span style="color:#728e00">=</span><span style="color:#728e00">right</span>;
<span style="color:#728e00">if</span> (<span style="color:#728e00">document</span>.<span style="color:#728e00">layers</span>) <span style="color:#728e00">window</span>.<span style="color:#728e00">captureEvents</span>(<span style="color:#728e00">Event</span>.<span style="color:#728e00">MOUSEDOWN</span>);
<span style="color:#728e00">if</span> (<span style="color:#728e00">document</span>.<span style="color:#728e00">layers</span>) <span style="color:#728e00">window</span>.<span style="color:#728e00">captureEvents</span>(<span style="color:#728e00">Event</span>.<span style="color:#728e00">MOUSEUP</span>);
<span style="color:#728e00">window</span>.<span style="color:#728e00">onmousedown</span><span style="color:#728e00">=</span><span style="color:#728e00">right</span>;
<span style="color:#728e00">window</span>.<span style="color:#728e00">onmouseup</span><span style="color:#728e00">=</span><span style="color:#728e00">right</span>;
<span style="color:#95a5a6">// End --&gt;
</span></code></pre></div><p>Everyone was very protective of their precious source codes and I somehow thought it would be a good idea to try and disable right clicks. Built-in browser developer tools did not exist yet so pressing <code>F12</code> or <code>CMD</code>+<code>ALT</code>+<code>J</code> would do nothing.</p>
<p>The second interesting thing are the browser-specific stylesheets! The difference between Internet Explorer and Netscape Navigator was already causing trouble in webdesign land. Compatibility issues would only be getting worse as other browsers emerged.</p>
<h3 id="2002httpswebarchiveorgweb20021128122545httpawhilegamingclonescom-php--mysql-banners-navigation-in-tables"><a href="https://web.archive.org/web/20021128122545/http://awhile.gamingclones.com/">2002</a>: PHP &amp; MySQL, banners, navigation in Tables</h3>
<p><figure>
<a href="../site-2002.jpg" class="lbox">
<img loading="lazy" src="../site-2002.jpg" title="&#39;aWhile [D3$!GN]&#39;, of my websites in 2002.">
</a>
<figcaption>&#39;aWhile [D3$!GN]&#39;, of my websites in 2002.</figcaption>
</figure>
</p>
<p><a href="https://web.archive.org/web/20021128122545/http://awhile.gamingclones.com/">View the 2002 version here</a>.</p>
<p>I got rid of the flashy colors - what a relief. The dark scheme nowadays is still attractive to me, even if modern browsers (and websites) include better support for accessibility. The second thing that thankfully disappeared in the early 2000s are frames. Instead, the navigation was usually built with simple <code>&lt;TABLE/&gt;</code> elements - going back to basics with <code>&lt;LI/&gt;</code> and style positioning was not yet that common.</p>
<p>Since then, most of my websites became <em>dynamic</em>: they included some sort of server-side scripting, such as PHP to retrieve comments/newsitems/etc. Most designs were made from scratch, even though PHP frameworks existed. CakePHP saw the light in 2005.</p>
<p>Content-wise, the very first website from 1998 contained three main items (1. code 2. games 3. about me). Since 2002, I started building multiple websites, and <strong>aWhile [D3$!GN]</strong> was my &ldquo;code&rdquo;-page - that&rsquo;s the reason it was hosted on &ldquo;<em>gamingclones.com</em>&rdquo;, the game part that was never really finished. This separation is still visible today. Take a look <a href="https://web.archive.org/web/20040120171650/http://gamingclones.com/">at gamingclones.com here</a>. It also has a nice graphical banner made in Photoshop. Since 2003, I was a big fan of <code>font-family: Verdana, Tahoma, Arial</code>.</p>
<h3 id="2004museum2004-xhtml-validation-clean-design"><a href="/museum/2004">2004</a>: xHTML Validation, Clean design</h3>
<p><figure>
<a href="../site-2004.jpg" class="lbox">
<img loading="lazy" src="../site-2004.jpg" title="&#39;Jefklaks Tux &#39;n&#39; Tips in 2004.">
</a>
<figcaption>&#39;Jefklaks Tux &#39;n&#39; Tips in 2004.</figcaption>
</figure>
</p>
<p><a href="/museum/2004">View the 2004 version here</a>.</p>
<p>Somehow, the green scheme stuck with me for almost twenty years. I guess that&rsquo;s the curse of having a surname like <em>Greenfield</em> (literally translated). During university, I was spoon-fed Linux and it tasted great - so much so that I started compiling my own patchset for the Linux <code>2.4</code> and the &ldquo;new&rdquo; <code>2.6</code> kernels back then. Using cool things like Gentoo <code>2004.1</code> (after dipping my toes in the Linux world using SuSE Linux <code>6.3</code>, just before Novell bought it in 2003) and the Fvwm window manager resulted in a lot of hours fiddling with config files that I wanted to share with the world. This website was the result of that work.</p>
<p>Third-party <code>XHTML</code> and <code>CSS</code> checker sites became popular and you could proudly wear fancy badges to claim you effectively did not forget a single slash in all your tags. Good job! Since I still wanted to include gaming tips next to the Linux trickery, I decided to split the site on entry and let the visitor choose:</p>
<p><figure>
<a href="../site-2004-choice.jpg" class="lbox">
<img loading="lazy" src="../site-2004-choice.jpg" >
</a>
</figure>
</p>
<p>The main colors changed, but the rest of the webdesign stayed the same. It was a simple, clean website with few PHP tricks. I slowly but surely started to care more about the <strong>contents</strong> than the look-and-feel. The background hover effects were done using CSS <code>:hover</code> instead of the usual JavaScript trickery.</p>
<p>Oh, and I replaced Gentoo with FreeBSD 5.3 - although Fvwm was there to stay.</p>
<h3 id="2006httpswebarchiveorgweb20070605081137httpwwwjefklakcom-pmwiki-configuring-before-developing"><a href="https://web.archive.org/web/20070605081137/http://www.jefklak.com/">2006</a>: PmWiki, configuring before developing</h3>
<p>In 2006, I grew tired of having to build websites time and time again from scratch. As <em>content</em> was my prime concern now, I started looking at Wiki solutions and came up with a heavily hacked version of <a href="https://www.pmwiki.org/">PmWiki</a> using custom scripts and themes. It was to be used on &ldquo;jefklak.com&rdquo;, a retro gaming website focused on articles and guides.</p>
<p><figure>
<a href="../site-2006.jpg" class="lbox">
<img loading="lazy" src="../site-2006.jpg" title="&#39;Jefklak&#39;s Codex&#39;, The 2006 PmWiki version.">
</a>
<figcaption>&#39;Jefklak&#39;s Codex&#39;, The 2006 PmWiki version.</figcaption>
</figure>
</p>
<p><a href="https://web.archive.org/web/20070605081137/http://www.jefklak.com/">View the 2006 version here</a>.</p>
<p>PmWik does not rely on MySQL but instead writes content to flat files on the webserver itself, including edit history. This reduced hosting costs significantly and made saving and restoring backups easier. I still fondly remember PmWiki and would gladly recommend it over bloated wiki frameworks such as MediaWiki.</p>
<p>This was actually the first website that attracted quite a lot of visitors, mainly because of my <a href="https://jefklakscodex.com/tags/baldurs-gate-2/">Baldur&rsquo;s Gate 2</a> guides and <em>DOOM</em> DS port project. Every single article written in that period has been ported to <a href="https://jefklakscodex.com/">jefklakscodex.com</a> - a perhaps more appropriate domain name. PmWiki made it easy to expose RSS/Atom feeds that I used for the first time.</p>
<p>Website licensing became a thing: I employed <a href="https://web.archive.org/web/20070623074422/http://www.jefklak.com/Main/AboutLegal">Creative Commons 3</a>. Internet Explorer 7 became the minimum as IE6 behaved like carp with my stylesheets. <a href="https://web.archive.org/web/20070623071942/http://www.jefklak.com/stats">Usage statistics</a> from 2007 are also archived.</p>
<h3 id="2010httpswebarchiveorgweb20110207214638httpwwwjefklakbe-dokuwiki-wordpress-content-migration-issues"><a href="https://web.archive.org/web/20110207214638/http://www.jefklak.be/">2010</a>: DokuWiki, Wordpress, content migration issues</h3>
<p><figure>
<a href="../site-2010.jpg" class="lbox">
<img loading="lazy" src="../site-2010.jpg" title="&#39;Jefklak.be&#39; in 2010, migrated to Wordpress.">
</a>
<figcaption>&#39;Jefklak.be&#39; in 2010, migrated to Wordpress.</figcaption>
</figure>
</p>
<p><a href="https://web.archive.org/web/20110207214638/http://www.jefklak.be/">View the 2010 version here</a>.</p>
<p>For a long time, I stopped caring about my websites because of my work. Since 2004, I did not own a Brain Baking/personal/tech-based website anymore, and PmWiki was giving me trouble. I can&rsquo;t remember why I did switch, but I decided to move everything to Wordpress. And then the site got hacked because I didn&rsquo;t update the Wordpress version regularly.</p>
<p>For my work as a software developer, I was always looking for snippets of certain scripts we often re-used. A colleague at work mentioned he hosted a code-wiki using <a href="https://www.dokuwiki.org/dokuwiki">DokuWiki</a>. That re-sparked my interest in a personal (sub)site. The color scheme changed for the better and I got rid of a lot of unnecessary JavaScript code.</p>
<p>As said before, I cared more about my content and wrote scripts to convert from PmWiki to DokuWiki (and later to Markdown for Hugo). In all honesty, the webdesign of the sites in this area could have done better. Fiddling with a custom Wordpress theme only fueled my frustration with these kinds of tools.</p>
<h3 id="2013httpswebarchiveorgweb20140805175940httpbrainbakingcom-brain-baking-static-site-generation"><a href="https://web.archive.org/web/20140805175940/http://brainbaking.com/">2013</a>: Brain Baking, static site generation</h3>
<p><figure>
<a href="../site-2013.jpg" class="lbox">
<img loading="lazy" src="../site-2013.jpg" title="&#39;Brain Baking&#39; in 2013 with ruhoh.">
</a>
<figcaption>&#39;Brain Baking&#39; in 2013 with ruhoh.</figcaption>
</figure>
</p>
<p><a href="https://web.archive.org/web/20140805175940/http://brainbaking.com/">View the 2010 version here</a>.</p>
<p>In 2013, I finally saw the light with <em>static</em> site generation tools and thankfully kicked out Wordpress and the like, including any ugly PHP script files that were involved. An early version of <a href="https://www.staticgen.com/ruhoh">ruhoh</a> was not that mature compared to Hugo 0.x, but it finally allowed me to write in Markdown. <em>Separation of concerns</em>: content here, layout there.</p>
<p>The <em>Brain Baking</em> name/idea also gave way to more tech blogging, as my work provided me with ample things to write about (unit testing), including my recent interests in self-improvement and journaling.</p>
<p>I hated the themes though.</p>
<h3 id="what-does-the-future-offer">What does the future offer?</h3>
<p>More simplicity and qualitative content, I hope.</p>
<p>All Brain Baking articles since 2013 have been preserved on this very website, and content from jefklak.com/be has been revived and migrated to <a href="https://jefklakscodex.com">jefklakscodex.com</a> since 2018.</p>
<p>I couldn&rsquo;t be happier with Hugo and my custom theme that focuses on <a href="/post/2020/06/designing-with-accessibility-in-mind/">accessibility</a> and <a href="/post/2020/06/tracking-and-privacy-on-websites/">privacy</a>. A lot of good <em>and</em> bad memories come rushing back to me whenever I see <code>$_POST['id']</code>. Of course, fifteen years ago, I didn&rsquo;t know what I was doing and PHP3 did not offer object-oriented programming.</p>
<p>I sometimes have the feeling I still don&rsquo;t know what I&rsquo;m doing&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 4 October 2020.
</p>
]]>
</description>
</item>
<item>
<title>An am486 Performance Analysis</title>
<link>https://brainbaking.com/post/2020/09/486-performance-analysis/</link>
<comments>https://brainbaking.com/post/2020/09/486-performance-analysis/#commento</comments>
<pubDate>Sat, 26 Sep 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/09/486-performance-analysis/</guid>
<category domain="https://brainbaking.com/tags/486">486</category>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/gtacrash.jpg"/>
</p>
<p>After the <a href="/post/2020/09/486-upgrade-sound-blaster">Sound Blaster</a> and <a href="/post/2020/09/486-upgrade-sd-hdd">SD-to-IDE</a> upgrades, it was time to do a decent performance analysis on the vintage DOS computer I now proudly own. The <a href="/post/2020/09/reviving-a-80486">original 80486 blog post</a> mentioned a CPU upgrade from DX40 to DX2-66 MHz, but how big is this performance gain in practice? Let&rsquo;s install Dosbench and find out.</p>
<h3 id="the-benchmarks">The benchmarks</h3>
<p>The system under test specs can be <a href="/post/2020/09/reviving-a-80486/">found here</a>. I included the following CPUs in each result:</p>
<ol>
<li>am486 DX-40 MHz, with Turbo switch ON</li>
<li>am486 DX-40 MHz, with Turbo switch OFF</li>
<li>am486 DX2-66 MHz, with Turbo switch ON</li>
<li><a href="https://docs.google.com/spreadsheets/d/1lvF9nOAMKLeCpHR_SaA48M7sUXItwIi72gHRcw0wpNU/edit#gid=0">Phil&rsquo;s Ultimate VGA Benchmark DB</a> reference data: the only other 486 DX-40 I could find, from user Mau1wurf1977. He runs with a Tseng ET4000 1MB VLB video card, 4MB RAM, and the same amount of motherboard cache.</li>
</ol>
<p>It can indeed be problematic to compare the output of various benchmarks - these might be nothing more than meaningless metrics. However, it&rsquo;s still fun to see bars and numbers appearing on your VGA screen and on the internet, and to try and compare them anyway. Phil&rsquo;s <a href="https://www.philscomputerlab.com/dos-benchmark-pack.html">DOS Benchmark Pack</a> was used to carry out most of these.</p>
<h4 id="3dbench-fps">3DBench FPS</h4>
<p><figure>
<a href="../3dbench.jpg" class="lbox">
<img loading="lazy" src="../3dbench.jpg" alt="3DBench FPS chart" >
</a>
</figure>
</p>
<p>The first thing to note here is the power of the Turbo button! Without these wires jumpered on the motherboard (and the button enabled), the overall power of your PC drops by almost two thirds or <code>66%</code>. Also, the DX2, which has a <code>40%</code> faster CPU in terms of raw power, only speeds up about <code>13.5%</code> for this 3D test. Still, it tops the &ldquo;magic&rdquo; 30 FPS limit!</p>
<p>Back in the day, anyone who was able to run a game at 30 frames per second was a happy gamer. Most games ran at half that rate, and you wouldn&rsquo;t care and play it anyway. In 2020, game critics complain that Mario 64 re-released in Super Mario 3D All Stars for Nintendo Switch was not bumped to 60 FPS. Maybe those guys should also build a DOS PC - and then stop whining. Sure, standards changed, but maybe our expectations are not always realistic&hellip; In the end, who cares about FPS when it plays <em>well</em> and you&rsquo;re having fun?</p>
<h4 id="pcpbench-fps">PCPBench FPS</h4>
<p><figure>
<a href="../pcpbench.jpg" class="lbox">
<img loading="lazy" src="../pcpbench.jpg" alt="PCPBench FPS chart" >
</a>
</figure>
</p>
<p>The small performance gain trend continues. I must admit that I am a bit disappointed, although I do realise that these benchmarks are usually VGA-intensitive. Since older games are software-accelerated, I hoped simply swapping out the CPU would net a bigger speed increase.</p>
<h4 id="topbench-scores">Topbench scores</h4>
<p><figure>
<a href="../topbenchchart.jpg" class="lbox">
<img loading="lazy" src="../topbenchchart.jpg" alt="Topbench chart" >
</a>
</figure>
</p>
<p>Since I&rsquo;m running <code>EMM386.EXE</code> with the extended <code>RAM</code> switch, <code>/p</code> was needed to force execution of the tests. The Topbench marks are missing from Phil&rsquo;s sheet. I had high hopes for this test as it&rsquo;s a general score that totals performance (MemTest, MemEA, Opcodes, VidMem, 3DGames). Sadly, the DX2-66 only gave a boost of about <code>10%</code>. It might again prove that the old motherboard is not up to snuff. Trying to force the motherboard bus speed into a CPU<code>/3</code> rate in the BIOS settings instead of the auto-detected <code>/4</code> does not change anything in various benchmarks I re-ran. Same thing with <code>UNIVBE</code> VESA 2 drivers. The cache writeback wait state is set on <code>2</code>, and a setting of <code>0</code> refuses to boot.</p>
<p>The built-in database shows similar performing PCs:</p>
<p><figure>
<a href="../topbench.jpg" class="lbox">
<img loading="lazy" src="../topbench.jpg" title="The Topbench benchmark system (src: sparcie.wordpress.com)">
</a>
<figcaption>The Topbench benchmark system (src: sparcie.wordpress.com)</figcaption>
</figure>
</p>
<p>The non-turbo DX40 closely matched a 386SX@33MHz, like the one in the screenshot above (score: 61, VS 64). So don&rsquo;t bother building a 80386, just press Turbo.</p>
<h4 id="games-from-doom-1993-to-duke3d-1996">Games: From DOOM (1993) to Duke3D (1996)</h4>
<p>I tried running the Duke3D shareware version but without throwing out Win3.1 drivers in <code>AUTOEXEC.BAT</code>, I couldn&rsquo;t even meet the minimum memory requirements of <code>6MB</code> free space. After that, <code>DNRATE</code> gave me <code>7</code> FPS on average with all settings set to high on the DX2-66. As expected, not very playable - I didn&rsquo;t bother with the DX40.</p>
<p>For the DOOM dosbemch mark, two settings exist: everything on LOW and on HIGH. On LOW, the non-turbo DX-40 struggles to get <code>15</code> FPS (with turbo: <code>36</code>), while on HIGH, it&rsquo;s so bad that I had to stop the test. Phil&rsquo;s data sheet reveals <code>7.5</code> FPS but I suspect it&rsquo;s run on HIGH (one has to divide <code>74690</code> by the amount of realtics). The faster DX2 CPU adds two frames to the DX-40&rsquo;s LOW mode, clocking in <code>16.3</code> FPS on HIGH.</p>
<p>Most games did not come equiped with a built-in frame counter and the Quake timedemos refuse to start for obvious reasons. Oh well, a FPS digit is only a number taken out of its context: I&rsquo;m very content with the performance of the PC in general, it runs the following later nineties DOS games flawlessly:</p>
<ul>
<li><em>Hocus Pocus</em> (1994)</li>
<li><em>Mystic Towers</em> (1994) - although the sound drops off after a minute</li>
<li><em>Wacky Wheels</em> (1994)</li>
<li><em>Raptor</em> (1994)</li>
<li><em>Rise of the Triad</em> (1994)</li>
<li><em>Jazz Jackrabbit</em> (1994)</li>
<li><em>Realms of Chaos</em> (1995)</li>
</ul>
<p>Even my favorite Windows 3.1 game, <em>Lode Runner: The Legend Returns</em>, which is <a href="https://web.archive.org/web/20081014012253/http://www.daggert.net/Folio/Programming/Presage/LodeRunner/Loderunner1.htm">freeware now</a>, works like a charm after installing Cirrus Logic Windows drivers to up the resolution and color grid:</p>
<p><figure>
<a href="../loderunner.jpg" class="lbox">
<img loading="lazy" src="../loderunner.jpg" title="This game is amazing with the Wave Blaster header board!">
</a>
<figcaption>This game is amazing with the Wave Blaster header board!</figcaption>
</figure>
</p>
<p>Any EGA-like games earlier than 1993 (<em>Cosmo&rsquo;s Comic Adventures</em>, <em>Duke 1</em>, <em>Bio Menace</em>, <em>Crystal Caves</em>, <em>Monster Bash</em>, &hellip;) are of course not a problem. The following games run OK, but not great:</p>
<ul>
<li><em>Doom</em> and <em>Doom II</em> (1993/1994)</li>
<li><em>Heretic</em> and <em>Hexen: Beyond Heretic</em> (1995)</li>
</ul>
<p>Unsurprisingly, those games run on the same CPU-hungry engine. It is clear that games up to 1995 are OK but after that (Duke was released in 1996), you&rsquo;d need a faster Pentium (II) and perhaps even a Voodoo card for Quake to get things running. <em>Grand Theft Auto</em> (1997) crashes after a few crawlingly slow frames (see image on top), and <em>Death Rally</em> (1996) is more like <em>Stutter Rally</em>. I was warned: the game advertises my PC rig as the bare minimum.</p>
<p>The year <strong>1995</strong> is indeed a turning point for PC technology: the Intel Pentium P54C with 120 MHz was finally faster than the 80486DX4-100 and Microsoft released Windows 95.</p>
<h3 id="so-whats-next-a-pentium">So, what&rsquo;s next, a Pentium?</h3>
<p>My memory is getting foggy as I do my best to recollect what computers my father and I used to build when I was just a kid. A backup of an old self-made website gave me a hint. This is an excerpt from the news entry on that site, entitled &lsquo;<em>Merry Christmas, 24/12/2000</em>': (translated from Dutch)</p>
<pre><code>Yes yes the christmas holidays are coming so exams are finished! No big failures that's the most important... At least for me because otherwise my dad would install 'the' Athlon Thunderbird processor (1 GHz) into his own PC instead of mine, and I need it that bad :-) Really, becuase that Pentium II 233 is already getting pretty old. Whoever has money is always upgrading!
</code></pre><p>A Thunderbird it is. Windows 98 Second Edition: here I come.</p>
<p><figure>
<a href="../thunderbird.jpg" class="lbox">
<img loading="lazy" src="../thunderbird.jpg" title="An Athlon Thunderbird I salvaged from scraps at work.">
</a>
<figcaption>An Athlon Thunderbird I salvaged from scraps at work.</figcaption>
</figure>
</p>
<p>The year <strong>2000</strong> also is special: it was the year where the one Gig processor speed was broken, and between 2000 and 2005, this speed was increasing at a staggering rate, until the plateau of power usage was reached. <a href="http://www.gotw.ca/publications/concurrency-ddj.htm">The Free Lunch Is Over article</a> explains this in more detail. My 2003 DELL Inspiron laptop used at university came packed with a Pentium 4 with a whopping 3 GHz processor. Three whole gigantic hertz-es! The 2012 MacBook Air I&rsquo;m typing this on uses a more battery-friendly Core i5 1.8 GHz.</p>
<p>People fond of graphs and details on the history of PC performance can eat their harts out in the excellent Maximumpc.com article called &ldquo;<a href="https://web.archive.org/web/20150418074002/http://www.maximumpc.com:80/article/home/history_dream_how_ultimate_pc_has_evolved_15_years">How the Ultimate PC Has Evolved In 15 Years</a>&rdquo;.</p>
<script>
am4core.ready(function() {
am4core.useTheme(am4themes_animated);
function createChart(divid, data) {
var chart = am4core.create(divid, am4charts.XYChart);
chart.data = data;
chart.exporting.menu = new am4core.ExportMenu();
chart.padding(40, 40, 40, 40);
var categoryAxis = chart.yAxes.push(new am4charts.CategoryAxis());
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.dataFields.category = "cpu";
categoryAxis.renderer.inversed = true;
categoryAxis.renderer.grid.template.disabled = true;
//categoryAxis.renderer.minGridDistance = 100;
categoryAxis.renderer.minWidth = 120;
var valueAxis = chart.xAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.categoryY = "cpu";
series.dataFields.valueX = "val";
series.tooltipText = "{valueX.value}"
series.columns.template.strokeOpacity = 0;
series.columns.template.column.cornerRadiusBottomRight = 5;
series.columns.template.column.cornerRadiusTopRight = 5;
var labelBullet = series.bullets.push(new am4charts.LabelBullet())
labelBullet.label.horizontalCenter = "left";
labelBullet.fontSize = 20;
labelBullet.label.dx = 5;
labelBullet.label.fill = am4core.color("white");
labelBullet.label.text = "{values.valueX.workingValue}";
labelBullet.locationX = 1;
categoryAxis.sortBySeries = series;
var columnTemplate = series.columns.template;
columnTemplate.adapter.add("fill", function(fill, target) {
return am4core.color("#018660")
})
}
createChart("3dbenchdiv", [{
"cpu": "am486 DX-40 Non-turbo",
"val": 10.5
}, {
"cpu": "am486 DX-40 Turbo",
"val": 27
}, {
"cpu": "am486 DX2-66",
"val": 31.2
}, {
"cpu": "Phil's Benchmark, am486 DX-40",
"val": 17.1
}]
);
createChart("pcpbenchdiv", [{
"cpu": "am486 DX-40 Turbo",
"val": 5.6
}, {
"cpu": "am486 DX2-66",
"val": 6.2
}, {
"cpu": "Phil's Benchmark, am486 DX-40",
"val": 3.8
}]
);
createChart("topbenchdiv", [{
"cpu": "am486 DX-40 Non-turbo",
"val": 64
}, {
"cpu": "am486 DX-40 Turbo",
"val": 136
}, {
"cpu": "am486 DX2-66",
"val": 149
}]
);
}); // end am4core.ready()
</script>
<p>
By <a href="/about">Wouter Groeneveld</a> on 26 September 2020.
</p>
]]>
</description>
</item>
<item>
<title>486 Upgrade 2: The SD Card HDD</title>
<link>https://brainbaking.com/post/2020/09/486-upgrade-sd-hdd/</link>
<comments>https://brainbaking.com/post/2020/09/486-upgrade-sd-hdd/#commento</comments>
<pubDate>Wed, 23 Sep 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/09/486-upgrade-sd-hdd/</guid>
<category domain="https://brainbaking.com/tags/486">486</category>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>The <a href="/post/2020/09/reviving-a-80486/">revived 486 PC</a> came with a Conner CFS210A <code>213</code> MB hard drive. As mentioned then, I like <em>silent</em> computers, so the first thing I did was flick out the low-end 12V PSU fan. That improved next to nothing thanks to the old HDD that seemed to take of as soon as the power switch was flipped. Next to the noise problem, a more pressing issue appeared: after a week of fiddling with the PC, things started crashing. It got worse: <code>COMMAND.COM</code> and master boot record stuff broke, requiring a boot floppy in order to access files on the hard drive.</p>
<p><code>CHKDISK.EXE</code> ran for hours, fixing broken files and sectors here and there. I was hopeful. Rebooting successfully started DOS but spewed a whole lot of errors: most games and windows refused to work. It turns out that the &ldquo;repaired&rdquo; files were gone missing. The perfect time to throw out the noisemaker and take a closer look at flash alternatives. The popular Compact Flash to IDE adapters come with a metal bracket, making it easy to install. But who uses CF nowadays? SD to IDE adapters with chips that convert the signal are cheap on eBay, and my old MacBook Air has a native SD slot, making the decision easy for me.</p>
<p><figure>
<a href="../sdhdd.jpg" class="lbox">
<img loading="lazy" src="../sdhdd.jpg" title="IDE adapter (left), 12V adapters (down), 8GB SD card (right).">
</a>
<figcaption>IDE adapter (left), 12V adapters (down), 8GB SD card (right).</figcaption>
</figure>
</p>
<p>The aluminum case is custom-made by my father-in-law and allows me to install the &ldquo;drive&rdquo; as any other external device: through the front of the PC case.</p>
<p>Unfortunately, this 486 upgrade was not a simple plug-and-play case&hellip;</p>
<h3 id="problem-1-recognizing-and-formatting">Problem 1: Recognizing and formatting</h3>
<p>How many cylinders, heads and sectors per track does an SD-to-IDE adapter have? The AWARD BIOS of course failed to auto-detect the adapter and I had no idea what to enter. Google ushered me to <a href="https://archive.org/details/whatide">WHATIDE.COM</a>, a small utility that reports the hard drive geometry.</p>
<p><code>FDISK</code> allowed me to create <code>500MB</code> partitions, while in theory, DOS 6.22 can handle up to <code>2GB</code> in <code>FAT16</code>. Apparently, older motherboards - like mine - do not support this. According to VOGONS, <a href="https://www.vogons.org/viewtopic.php?f=61&amp;t=42113">Dynamic Drive Overlay</a> software such as <em>Ontrack Disk Manager</em> (downloadable at <a href="https://www.philscomputerlab.com/ontrack-disk-manager.html">Phils Computer Lab</a>) fixes this by tricking the BIOS into thinking it&rsquo;s a small HDD, while in fact it can contain several partitions of <code>2GB</code> (four times: my SD card is <code>8GB</code>). Other retro PC bloggers experimented with fast SD cards and concluded that you&rsquo;re limited to the bus speed anyway, so don&rsquo;t fret on which SD card to use.</p>
<p><figure>
<a href="../ontrack.jpg" class="lbox">
<img loading="lazy" src="../ontrack.jpg" title="A fancy Disk Manager splash screen greets you on startup.">
</a>
<figcaption>A fancy Disk Manager splash screen greets you on startup.</figcaption>
</figure>
</p>
<p>The Disk Manager creates a special MBR &ldquo;overlay&rdquo; that fools the BIOS. This means that booting from floppy&rsquo;s through the conventional BIOS system will not work as the HDD cannot be mounted without knowledge of this system. If floppy booting is desired, Ontrack gives the user two seconds to jam spacebar on time. So, booting through A: means booting through C: and pressing space. Still following? Good. More problems ahead.</p>
<h3 id="problem-2-reinstalling-dos">Problem 2: Reinstalling DOS</h3>
<p>Advices such as &ldquo;<a href="https://www.cubic.org/docs/configuring.htm">Configuring MS-DOS Properly</a>&rdquo; that dictate what to put in <code>CONFIG.SYS</code> and <code>AUTOEXEC.BAT</code> have to wait: my DOS floppy&rsquo;s refused to be recognized as proper installation disks. <em>Please insert disk 1</em>. It&rsquo;s in there, take a better look! (Presses Enter). <em>Please insert disk 1</em>. Argh!!</p>
<p>It turns out that the label needs to be <em>exactly</em> &ldquo;DISK (SPACEx6) 1&rdquo; (six hard spaces). Renaming did not work, low level disk image writers on *NIX systems such as <code>dd</code> did not work. Only <a href="https://www.winimage.com/winimage.htm">WinImage for Windows</a> successfully revitalized the floppy&rsquo;s and allowed me to finally install an OS.</p>
<h3 id="problem-3-mounting-the-sd-on-modern-systems">Problem 3: Mounting the SD on modern systems</h3>
<p>Sadly, OSX did not recognize the SD card. Only after a few hours of cursing I started realizing the dynamic drive overlay could be the culprit. VOGONs to the rescue (again): user ozzmosis was able to mount his card using the <code>offset</code> parameter, thereby skipping the special MBR and jumping directly to the <code>FAT16</code> partition itself.</p>
<p>I coupled <code>mount</code> with <a href="https://github.com/bcpierce00/unison">unison</a>, a two-way command line synchronization tool that backs up the whole HDD contents to a Dropbox directory. That way, my OSX and Windows machines <strong>can</strong> in fact access the 486 files. My first thought, <code>rsync</code>, is problematic with two-way syncing and file-deletion. I use the following script:</p>
<pre><code>sudo mount -t vfat -o offset=64512,noexec,rw,umask=0000 /dev/sdb /mnt
sudo unison -auto -perms 0 /mnt/ /home/wouter/Dropbox/486/
sudo umount /mnt
</code></pre><p>I ended up deleting the three other partitions on the SD card, as <code>2GB</code> is more than any DOS user would ever want, and I had trouble looking up the exact offsets of the other partitions.</p>
<p>This is what the (open) PC case looks like now:</p>
<p><figure>
<a href="../pccase.jpg" class="lbox">
<img loading="lazy" src="../pccase.jpg" title="The PC Case, after installing the SD-to-IDE front slot.">
</a>
<figcaption>The PC Case, after installing the SD-to-IDE front slot.</figcaption>
</figure>
</p>
<p>I was a bit too quick taking that photograph as things were getting cramped: the IDE cable of the adapter seemed to push against the spinning header of the floppy drive, preventing floppy&rsquo;s to be read. The issue was resolved after flipping both drives.</p>
<p>Now all that is left is adding a nice retro <code>1&quot;</code> <a href="https://www.domingfactory.nl/vierkante-doming-sticker">doming sticker</a> on the case! And I will keep an eye out on garage sales for that eighties <code>5.25&quot;</code> floppy drive&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 23 September 2020.
</p>
]]>
</description>
</item>
<item>
<title>486 Upgrade 1: Sound Blaster 16</title>
<link>https://brainbaking.com/post/2020/09/486-upgrade-sound-blaster/</link>
<comments>https://brainbaking.com/post/2020/09/486-upgrade-sound-blaster/#commento</comments>
<pubDate>Fri, 18 Sep 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/09/486-upgrade-sound-blaster/</guid>
<category domain="https://brainbaking.com/tags/soundblaster">soundblaster</category>
<category domain="https://brainbaking.com/tags/486">486</category>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/sndblaster.jpg"/>
</p>
<p>The first in hopefully many to come <a href="/post/2020/09/reviving-a-80486/">retro 486 PC</a> update posts! As mentioned then, the PC I received did not come with a sound card. For retro gaming, unless you want to be stuck replaying the same levels of Duke Nukum I again and again, a good Creative <em>Sound Blaster</em> card is the best fit - especially since I fondly remember those DOS-era tunes.</p>
<p>So, the hunt for a Sound Blaster ISA card began. A blog post at <a href="https://nerdlypleasures.blogspot.com/2012/07/sound-blaster-16-trials-and-tribulations.html">Nerdly Pleasures</a> made me reconsider my first thought and not buy an AWE32/64 card or a Pro 2.0, but go for a classic 16 variant instead. It seems that one has to pay special attention to the PCB &ldquo;CT&rdquo; version. Most later OEM cards (and the &ldquo;Vibra&rdquo; ones) come with less hardware components equipped (no wave table header, no CD-ROM interface, no PC Speaker JP support, &hellip;), or worse: don&rsquo;t have a genuine Yamaha OPL3 sound chip.</p>
<p>It might indeed be quite a <em>nerdy</em> pleasure, but the difference is profound. Listen to a <a href="https://en.wikipedia.org/wiki/Sound_Blaster_16#OPL-3_FM_and_CQM_Synthesis_options">Wikipedia SB16 Synthesis</a> sound sample that compares the Yamaha OPL-3 FM chip with Creative&rsquo;s own CQM version. The card I ended up buying, a <strong>CT2290</strong>, has the Creative CT1747 chip labeled &ldquo;OPL&rdquo;, which integrated the YMF262 OPL-3 FM synthesizer (located on the middle in the photo below).</p>
<p><figure>
<a href="../sndblaster.jpg" class="lbox">
<img loading="lazy" src="../sndblaster.jpg" title="The Sound Blaster 16 with S2 Wave Blaster daughterboard attached.">
</a>
<figcaption>The Sound Blaster 16 with S2 Wave Blaster daughterboard attached.</figcaption>
</figure>
</p>
<p><code>€53</code> excluding shipping and a few days later, it arrived from a German eBay seller cleverly named &ldquo;Electronics Recycling&rdquo;. I wish there were more actual stores like that. Installing the DOS drivers is quite easy; <code>SBBASIC.EXE</code> from <a href="philscomputerlab.com/creative-labs-drivers.html">Phil&rsquo;s Computer Lab</a> takes care of everything, including modifying <code>AUTOEXEC.BAT</code>. The jumpers were configured to address <code>240</code>, IRQ <code>5</code>, DMA <code>1</code> and HDMA <code>5</code>. I left them there.</p>
<hr>
<p><strong>Edit</strong> 2020-09-29: After having trouble with <a href="https://www.vogons.org/viewtopic.php?f=7&amp;p=897873">sound FX in Mystic Towers</a>, I closed JP12 and JP13 on the card to change the address to <code>220</code> - the most universally accepted <code>BLASTER</code> address. Apparently, parts of the Mystic Towers code hard coded the address. Halloween Harry also refused to work on another address. After the change, Adlib-compatible games stopped playing sound until IRQ was set to <code>7</code> using <code>DIAGNOSE.EXE</code>.</p>
<hr>
<p>Perhaps the most compelling part of the above photograph is the strange petite daughter board on the top right that is attached to the Sound Blaster. It uses the wave table MIDI header port. Since actual retro Creative Wave Blaster boards are very scarce (+€300 on eBay), the internet handed me a Belgian alternative: the <strong>Dream Blaster S2</strong> from <a href="https://www.serdashop.com">Serdaco BVBA</a>. New hardware for old hardware because - why not? The S2 is the cheapest option available (<code>€34</code>). Since I never used external synthesis before and Philq&rsquo;s review on YouTube was laudatory, I got ahead and clicked buy. Belgian money well-spent.</p>
<p>Of course, not every game supports wave tables or even has MIDI music. As a test, I recorded and edited a few samples from Rise of the Triad. Each video contains three parts:</p>
<ol>
<li>A part with the &ldquo;PC Speaker&rdquo; option configured in <code>SNDSETUP.EXE</code>;</li>
<li>A part with the &ldquo;Sound Blaster&rdquo; option;</li>
<li>A part with the &ldquo;Wave Table&rdquo; option.</li>
</ol>
<p>The result: (<em>dial up your volume! I recorded with my smartphone on purpose, I don&rsquo;t have an external VGA capture device and I want you to hear everything, including keystrokes</em>)</p>
<h4 id="the-apogee-intro">The Apogee Intro</h4>
<div class="video-mask">
<video width="100%" controls preload="metadata">
<source src="/vid/rottsnd-apogee.mp4#t=0.5" type="video/mp4">
Your browser does not support HTML video. Here's a link to the MP4-encoded video instead: <a href="/vid/rottsnd-apogee.mp4">/vid/rottsnd-apogee.mp4</a>.
</video>
</div>
<p>The difference is huge, and I couldn&rsquo;t wipe that grin off my face - even with just the Sound Blaster, I just <em>love</em> that intro. This brings back so many fond memories. Notice the subtle differences in the background with the S2! And yes, my VGA card and CPU can barely handle the game. An issue for a future blog post<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>Let&rsquo;s continue to the ROTT main menu and loading screen:</p>
<h4 id="main-menu">Main Menu</h4>
<div class="video-mask">
<video width="100%" controls preload="metadata">
<source src="/vid/rottsnd-menu.mp4#t=0.5" type="video/mp4">
Your browser does not support HTML video. Here's a link to the MP4-encoded video instead: <a href="/vid/rottsnd-menu.mp4">/vid/rottsnd-menu.mp4</a>.
</video>
</div>
<p>The first 30 seconds sure are a bit dull. Who plays ROTT with PC Speakers anyway? The SB&rsquo;s main menu music is not that profound, but the Wave Blaster indeed &ldquo;blasts&rdquo; it out of the park. And as soon as that loading screen music starts, oh my. Trembling knees! There is that grin again!</p>
<p>The music continues on to the gameplay:</p>
<h4 id="gameplay">Gameplay</h4>
<div class="video-mask">
<video width="100%" controls preload="metadata">
<source src="/vid/rottsnd-gameplay.mp4#t=0.5" type="video/mp4">
Your browser does not support HTML video. Here's a link to the MP4-encoded video instead: <a href="/vid/rottsnd-gameplay.mp4">/vid/rottsnd-gameplay.mp4</a>.
</video>
</div>
<p>You can see that the PC clearly is not up to the task and even shows several dips in music and sound FX playback while firing missiles. I did temporarily resocket the motherboard with the DX40 CPU. All options are set to maximum, I do not care for graphics performance just yet<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>I isolated the Rise of the Triad gameplay music tracks by recording using my <a href="/post/2020/11/winxp-upgrade-sound-blaster-xfi">X-Fi WinXP card</a>. With SB16 Sound Blaster music option (daughterboard disabled):</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_sb16.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_sb16.mp3">/audio/ROTT_sb16.mp3</a>.
</video>
</div>
<p>With WaveBlaster music option (daughterboard enabled):</p>
<div class="video-mask">
<audio width="100%" controls preload="metadata">
<source src="/audio/ROTT_waveblaster.mp3#t=0.5" type="audio/mpeg">
Your browser does not support HTML audio. Here's a link to the MP3-encoded audio instead: <a href="/audio/ROTT_waveblaster.mp3">/audio/ROTT_waveblaster.mp3</a>.
</video>
</div>
<p><em>Oh my</em> indeed!</p>
<p>Of course, this is just a sample of a single game. Other DOS MIDI masterpieces include:</p>
<ul>
<li>The Monkey Island games;</li>
<li>Lode Runner: The Legend Returns on Win 3.1</li>
<li>&hellip;</li>
</ul>
<p>This Sound Blaster 16 has made me childishly happy. Now where are all those floppy&rsquo;s?</p>
<p>Right, here:</p>
<p><figure>
<a href="../dosgames.jpg" class="lbox">
<img loading="lazy" src="../dosgames.jpg" title="A photograph of my 2006 desk with retro DOS manuals">
</a>
<figcaption>A photograph of my 2006 desk with retro DOS manuals</figcaption>
</figure>
</p>
<hr>
<p>In case anyone wants to jumper the PC Speaker pins on their Sound Blaster, configure them as follows: (<a href="https://www.vogons.org/viewtopic.php?f=9&amp;t=18283&amp;p=131727&amp;hilit=sound%20blaster%20speaker#p131727">src</a>):</p>
<p>Sound Blaster:</p>
<pre><code>Pin 1 = +5V
Pin 2 = Speaker
</code></pre><p>IBM PC:</p>
<pre><code>Pin 1 = Speaker
Pin 2 = None/Key
Pin 3 = Ground (No need to connect)
Pin 4 = +5V
</code></pre><p>See <a href="https://stason.org/TULARC/pc/sound-cards-multimedia/CREATIVE-LABS-INC-Sound-card-SOUNDBLASTER-16-PRO-C.html">all CT2290 jumper configurations</a>.</p>
<p>Note that some static noise will inevitably make it to your boxes if you do decide to connect the motherboard pins to the Sound Blaster. That&rsquo;s part of the charm!</p>
<p><strong>Addendum</strong>, 6th of November 2020: The VOGONS <a href="https://sites.google.com/site/soundcardcomparison/">Grand OPL3 Comparison</a> website (<a href="https://www.vogons.org/viewtopic.php?f=62&amp;t=32933">original forum post</a>) has this to say about the SB16 CT2290:</p>
<blockquote>
<p>It has one of the best FM sound i have heard so far. Very clean output, wide and clear spectrum range. The FM out of this card will please your ears.</p>
</blockquote>
<p>You can download the <a href="https://dl.dropbox.com/u/43851675/CT2290/CT2290.zip">sample pack</a> and compare it with other CT SB cards on the site.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>It turns out that I forgot that the <em>TURBO</em> pins were jumpered on themotherboard, but the button was not pressed. Without <em>TURBO</em>, the performance is comparable to a 386. Ouch, what a stupid mistake to make! Thanks <a href="https://www.vogons.org/viewtopic.php?f=46&amp;t=76632">VOGONS community</a> for the hints. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 18 September 2020.
</p>
]]>
</description>
</item>
<item>
<title>Reviving an old 80486 PC</title>
<link>https://brainbaking.com/post/2020/09/reviving-a-80486/</link>
<comments>https://brainbaking.com/post/2020/09/reviving-a-80486/#commento</comments>
<pubDate>Thu, 03 Sep 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/09/reviving-a-80486/</guid>
<category domain="https://brainbaking.com/tags/486">486</category>
<category domain="https://brainbaking.com/tags/retro">retro</category>
<description>
<![CDATA[
<p>What better birthday present to wish for as rapidly too old growing nostalgic computer nerd than a too old PC? &ldquo;<em>Here, take this. At least now we don&rsquo;t have to haul it to the container park!</em>&rdquo; And what exactly is <em>this</em>?</p>
<ul>
<li><a href="https://www.elhvb.com/webhq/models/486vlb3/m601.html">M602</a> motherboard with 3 32-bit VLB buses, and 7 ISA slots, supporting CPUs up to 66 MHz. <code>256 k</code> cache installed.</li>
<li><a href="https://en.wikipedia.org/wiki/Intel_80486">AMD 80486DX</a> CPU chip, <code>40 MHz</code>.</li>
<li>Cirrus Logic (837) <a href="http://www.vgamuseum.info/index.php/component/k2/item/135-cirrus-logic-cl-gd5426">CL-542X-VLB-U</a> <code>1 MB</code> VLB VGA card (expandable up to 2 MB)</li>
<li><code>8 MB</code> FPM DRAM fitted in eight SIMM slots</li>
<li><a href="https://www.computerhope.com/hdd/hdd0018.htm">Conner CFS210A</a> <code>213 MB</code> HDD and a 1.4 MB floppy reader</li>
</ul>
<p>When I turned it on, I was greeted with the blue Award BIOS 4.5 screen, and it started calculating the RAM width. Wow, it does still work! <strong>CMOS FAILURE. DEFAULT SETTINGS USED.</strong> Whoops. Luckily, the HDD auto-detect BIOS feature still worked, and Windows 3.1 still booted. The HDD did not lose data, and most floppy&rsquo;s that came with the PC still contain their original data.</p>
<p>Then I started wondering, what if I tried to upgrade the PC, just for the fun of it? DOOM could technically run, the VLB bus is very fast and 8 MB would be more than enough. A piece of junk for one person, a toy to fiddle with and learn from for another.</p>
<h3 id="challenge-1-the-cmos-battery">Challenge 1: The CMOS Battery</h3>
<p><figure>
<a href="../batt.jpg" class="lbox">
<img loading="lazy" src="../batt.jpg" title="The corroded battery replaced with a new one.">
</a>
<figcaption>The corroded battery replaced with a new one.</figcaption>
</figure>
</p>
<p>The old <code>3.6 V</code> battery corroded parts of the motherboard and had to be desoldered. Following a guide form <a href="http://pc-restorer.com/replacing-cmos-batteries-in-old-pcs/">pc-restorer.com</a> was easy enough; creating a replacement was a bit more challenging. I did not want to solder on another one that might leak again after a few years. Instead, I used the 4 external jumper pins, labeled <code>EXT-BAT</code> in the above photo, to connect an external battery.</p>
<p>A lazy do-it-yourself way to solder on plus and minus at pin one and four, respectively. After cleaning the muck, problem one was fixed.</p>
<h3 id="challenge-2-noise">Challenge 2: Noise</h3>
<p><figure>
<a href="../power.jpg" class="lbox">
<img loading="lazy" src="../power.jpg" title="The opened up 200 W power supply.">
</a>
<figcaption>The opened up 200 W power supply.</figcaption>
</figure>
</p>
<p>These tower PCs from yesteryear seemed to produce an awful lot of sound, compared to my passive MacBook Air from 2012. I still had a &ldquo;silent&rdquo; Nexus <code>12 V</code> fan lying around, so I simply decided to open up the power supply and switch fans. The result is astonishing: the Nexus is almost inaudible!</p>
<p>Alas, the major source of noise seems to not come from the voltage supplier, but the hard disk itself: not only the bleeps and bloops from a 24 year old disc, but mostly the spinning headers itself. I might try to look around for a silent model, or even investigate how to <a href="https://dfarq.homeip.net/sd-to-ide-performance/">use flash cards</a> with the 40-pin legacy IDE interface.</p>
<h3 id="challenge-3-the-dx2-upgrade">Challenge 3: The DX2 Upgrade</h3>
<p><figure>
<a href="../cpu.jpg" class="lbox">
<img loading="lazy" src="../cpu.jpg" title="Out with the DX, in with the successor!">
</a>
<figcaption>Out with the DX, in with the successor!</figcaption>
</figure>
</p>
<p>I found an AMD 80486DX2 CPU on eBay for <code>10 EUR</code> - exciting! A <code>40%</code> faster chip, running at <code>66 MHz</code>, the maximum the motherboard can handle. I&rsquo;d love to get the one hundred one, but have no intentions of switching the motherboard itself. It has to keep its retro vibe somehow&hellip;</p>
<p>Four days later, it arrived in a bad condition: to my frustration, it had lots of bent pins. Great. Carefully bending them requires patience and a few particular pins in one corner did not want to comply. I engaged an expert at all things gold-related: my wife.</p>
<p><figure>
<a href="../cputryout.jpg" class="lbox">
<img loading="lazy" src="../cputryout.jpg" title="The expert at work.">
</a>
<figcaption>The expert at work.</figcaption>
</figure>
</p>
<p>After running back and forth, fetching a few small tweezers from her jewelry atelier, the problem was solved and the CPU snuggled up into the prehistoric socket. Somehow, I missed the grand moment. Oh well.</p>
<p>After one more hour of fiddling and cursing with too many jumper wires in order to get everything back into its case, it was time to test things out and power it back on. No luck. Again. Nope. It turned out that the power cord suddenly stopped working.</p>
<p>After connecting another one, I failed to notice &ldquo;<strong>80 MHz</strong>&rdquo; at the BIOS checkup screen. Unaware of the problem at hand, I happily fiddled with the date settings in the BIOS, chuckling that at least the battery worked. It froze a few seconds later. Uh oh. The CPU felt way too hot&hellip; Fortunately, that also caused me to figure out the root cause: I was somehow overclocking the chip without a heatsink and without compatibility of the motherboard!</p>
<p>Ten minutes of fiddling with jumpers, and possibly more cursing - the online M601 jumper manual did not completely match my M602 motherboard layout - this is the result:</p>
<p><figure>
<a href="../done.jpg" class="lbox">
<img loading="lazy" src="../done.jpg" title="DX2 Installed, 66 MHz. 10 EUR well spent!">
</a>
<figcaption>DX2 Installed, 66 MHz. 10 EUR well spent!</figcaption>
</figure>
</p>
<p>We&rsquo;re in business! VGA output on the 20&quot; widescreen also works. The faster response time puts less strain on my eyes than the 12&quot; Compal CRT next to it, although in all fairness you do lose the retro vibe a bit.</p>
<h3 id="challenge-4-sound">Challenge 4: Sound</h3>
<p>As for future work, the PC seems to lack any sound card. The PC speaker bleeps grow old very quickly, and I&rsquo;d love to get to play Bobby Prince&rsquo;s Duke Nukum II soundtrack. I want to get my hands on a Creative Sound Blaster Pro 2 (not the budget 16-bit things), but that will possibly involve more eBay scouring. These cards are still ridiculously expensive: the Cirrus Logic VGA card currently installed costs on average 70 EUR!</p>
<p>Peeking at other retro enthusiast blogs, it seems like <a href="https://dfarq.homeip.net/gotek-floppy-emulator-for-retro-pcs/">USB Floppy emulators</a> exist, HDDs are being replaced with SD/CompactFlash cards, <a href="https://dfarq.homeip.net/using-an-ne2000-network-card-in-dos/">ISA RJ-45 network cards</a> are begin screwed in, <a href="https://www.youtube.com/watch?v=e4rw3d7mu28">more L2 cache is being installed</a>, and so forth. So many more fun things to do!</p>
<p>To be continued&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 3 September 2020.
</p>
]]>
</description>
</item>
<item>
<title>Thoughts on collaboration in education</title>
<link>https://brainbaking.com/post/2020/08/education-and-collaboration/</link>
<comments>https://brainbaking.com/post/2020/08/education-and-collaboration/#commento</comments>
<pubDate>Fri, 14 Aug 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/08/education-and-collaboration/</guid>
<category domain="https://brainbaking.com/tags/collaboration">collaboration</category>
<category domain="https://brainbaking.com/tags/teaching">teaching</category>
<category domain="https://brainbaking.com/tags/agile">agile</category>
<description>
<![CDATA[
<p>While digging through the usual daily stack of academic papers, in pursuit of that one report that might help me understand my own research questions, I stumbled upon the work of Kathleen Ofstedal and Kathryn Dahlberg. In a 2007 paper called &ldquo;<em>Collaboration in Student Teaching: Introducing the Collaboration Self-Assessment Tool</em>&rdquo;, they explain why collaboration in student-teaching environments might prove troublesome.</p>
<p>Two major reasons are brought forward.</p>
<h3 id="1-power">1. Power</h3>
<p>According to them, &ldquo;Respectful, supportive, and collaborative relationships that go both ways are difficult for teachers and their candidates to build when there is a noticeable power differential.&rdquo;</p>
<blockquote>
<p>Evaluation of the teacher candidate by the cooperating teacher is a significant factor in creating the power differential. <span>Smyth (1986)</span></p>
</blockquote>
<p>Then they continue to talk about the <em>hierarchical relationship</em> between the university supervisor (e.g. my PhD supervisors) and the cooperating teacher/teacher candidate (e.g. me?). It struck me as how similar this is to my own experience in re-entering higher education after eleven years of experience in the field. My peers of course respect me, as they do others who are less experienced than me. However, there is indeed a nearly visible <em>hierarchical</em> &ldquo;thing&rdquo; going on.</p>
<p>The ones with the PhD and tenured professorship status, and the ones that work for them. However hard they try to debunk this, it is unfortunately still very present.</p>
<h3 id="2-isolation">2. Isolation</h3>
<p>Lortie&rsquo;s research in 1975 already concluded that teaching is marked by <em>privatism</em>: you do your thing, I do my thing - let&rsquo;s not interfere. You want me to use your tool? I&rsquo;d rather not. Mine is better. I&rsquo;m used to this one. Does this sound familiar?</p>
<p>Cookson described it teaching (in higher education) as:</p>
<blockquote>
<p>&hellip;one of the most social occupations, but also one of the most isolating professions. <span>Cookson (2007)</span></p>
</blockquote>
<p>Although collaboration and sharing is required to help students achieve their maximum potential, it still barely happens. In 2020, thirteen years later, I can scarcely see any improvements.</p>
<p>Attempts of my own to unify things are mostly dismissed - although they were &ldquo;well-evaluated&rdquo;. Everyone uses their own teaching methodology, toolset, way of interacting with students, and so forth. I&rsquo;m not advocating for one tool to rule them all, but feedback from students is clear: they hate that every professor, assistant and researcher requires them to do things differently.</p>
<p>We usually respond by saying the feedback is statistically irrelevant. That&rsquo;ll teach them.</p>
<p>The introduction of the paper ends with this encouraging sentence: &ldquo;Armed with these skills, new teachers will be able to change the traditional culture of isolationism.&rdquo; I think it&rsquo;s planned for release somewhere in 2034.</p>
<p>After reading this, I simply felt very sad. It (again) made me seriously doubt my decision to leave the team-based software development world. We as academics love writing about things, like collaboration, but I have the feeling that we don&rsquo;t really know what we&rsquo;re talking about. It not only confirms what I wrote about <a href="/post/2020/02/agile-academia/">agile and academica</a>, but it generalizes the notion of &ldquo;no fast feedback&rdquo; to &ldquo;no feedback at all&rdquo;.</p>
<h3 id="collaboration">Collaboration?</h3>
<p>I once spoke to <a href="https://www.ductu.be/about">Wim Bollen</a> of Ductu about collaborating. &ldquo;<em>Teamwork</em>&rdquo;, a fancy word that is likely to pop up in any business-related contemporary article, is something we also loved to complain about in the industry, when I worked as a software engineer. Working together is certainly challenging, but Wim identified interesting nuances in &ldquo;collaboration&rdquo;: he called 90% of what everyone thinks is collaborating, <em>co-working</em>. You do this, I do that, and in the end, we&rsquo;ll throw stuff together. Done.</p>
<p>This is exactly the well-employed strategy in the academic world when researchers (including myself) claim to have collaborated with someone. In Elseviers' <a href="https://www.elsevier.com/connect/a-brief-guide-to-research-collaboration-for-the-young-scholar">A brief guide to research collaboration for the young scholar</a> (I wonder if 35 still counts as a young scholar?) presents a few synonyms:</p>
<ul>
<li>research collaboration</li>
<li>co-authorship</li>
<li>research networking (Huh?)</li>
<li>joint research</li>
<li>research partnership</li>
</ul>
<blockquote>
<p>It is widely accepted that collaboration in research across disciplines, between young and more senior researchers and with practitioners is critical to the career of novice researchers.</p>
</blockquote>
<p>I completely agree. However, based on the context of the article, it&rsquo;s clear that they are talking about <em>co-working</em>. You do this, I do that, and in the end, we&rsquo;ll throw stuff together. Done. I&rsquo;m afraid I&rsquo;ve been spoiled too much with pair programming and some exceptional ex-colleagues. Thanks guys.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 14 August 2020.
</p>
]]>
</description>
</item>
<item>
<title>3D Software Rendering on the GBA</title>
<link>https://brainbaking.com/post/2020/07/3d-software-rendering-on-gba/</link>
<comments>https://brainbaking.com/post/2020/07/3d-software-rendering-on-gba/#commento</comments>
<pubDate>Tue, 21 Jul 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/07/3d-software-rendering-on-gba/</guid>
<category domain="https://brainbaking.com/tags/gba">gba</category>
<description>
<![CDATA[
<p>When I started programming the <a href="https://github.com/wgroeneveld/gba-sprite-engine/">gba-sprite-engine</a> two years ago, I knew I would be getting myself into trouble. The Game Boy Advance only has 16Mhz and it&rsquo;s whole software library is written in low-level C using DMA (Direct Memory Access) and memory-mapped IO. Translation: pointers! <code>**</code> - Yay!</p>
<p>In the end, switching to <code>C++11</code> while trying to unit test and stub out BIOS code as much as possible did help soften the pain. I&rsquo;m glad I got my hands dirty again, and it writing &ldquo;closer to the metal&rdquo; was a welcome change from the usual high-level stuff I produce.</p>
<p>But GBA MODE 0-1-2 is not the only possibility to write a GBA game. There&rsquo;s also <em>bitmap mode</em>, 3-4-5, that lets you write pixel colors (or palette indices) yourself. This opens up possibilities of software rendering things yourself. 90% of the GBA library did <strong>not</strong> do that. But a few games did:</p>
<ul>
<li>Doom, Doom II, Duke Nukem Advance (Ray casting engines and/or ports)</li>
<li>007 Nightfire (A more modern 3D engine)</li>
<li>Asterix &amp; Obelix XXL</li>
<li>A few terrible race games</li>
</ul>
<p>How do you render things in 3D without hardware acceleration, and without an FPU on the circuit board that handles <code>float</code> digits, taken into account the (mostly) 16-BIT bus rate and 16Mhz CPU? Well&hellip; It does not exactly produce 30+ FPS:</p>
<p><figure>
<a href="https://github.com/wgroeneveld/gba-bitmap-engine/raw/master/img/monkey.gif?raw=true" class="lbox">
<img loading="lazy" src="https://github.com/wgroeneveld/gba-bitmap-engine/raw/master/img/monkey.gif?raw=true" title="Wireframing 507 vertices and 968 faces">
</a>
<figcaption>Wireframing 507 vertices and 968 faces</figcaption>
</figure>
</p>
<p><figure>
<a href="https://github.com/wgroeneveld/gba-bitmap-engine/raw/master/img/raster.gif?raw=true" class="lbox">
<img loading="lazy" src="https://github.com/wgroeneveld/gba-bitmap-engine/raw/master/img/raster.gif?raw=true" alt="octahedron" title="Trying to rasterize the same thing">
</a>
<figcaption>Trying to rasterize the same thing</figcaption>
</figure>
</p>
<p>Drawing a lot of lines is not exactly something the GBA loves to do. And I did use <a href="https://www.coranac.com/tonc/text/toc.htm">tonclib&rsquo;s optimized routines</a> after a failed attempt to implement Bresenham myself. MODE4 has weird byte-write requirements and you can optimize DMA writing of horizontal lines.</p>
<p>But the worst part was fixed-point math, sine lookup tables, and calling the BIOS just to get a square root of something. <code>Math.sin()</code> takes input in radians, in any common programming language. The above imported <a href="https://sandbox.babylonjs.com">Babylon JS</a> mesh expects the same, but my sine table is filled in <code>[1-512]</code> slices and expects it&rsquo;s input 16-BIT. More needless bit-shifting.</p>
<p>I intended to design the engine again as high-level as possible taking advantage of C++&rsquo;s objects and operator overloading. How about <code>worldMatrix * viewMatrix;</code>? Everything is unit-tested (thank god for that, it took out a lot of bugs). But passing objects around in limited RAM sounds ridiculous - and it probably is, even if it&rsquo;s a <code>const MatrixFx&amp;</code> reference or a <code>std::shared_ptr&lt;Mesh&gt;</code>.</p>
<p>Reverting to a simple box sped up the FPS:</p>
<p><figure>
<a href="https://github.com/wgroeneveld/gba-bitmap-engine/raw/master/img/wired2.gif?raw=true" class="lbox">
<img loading="lazy" src="https://github.com/wgroeneveld/gba-bitmap-engine/raw/master/img/wired2.gif?raw=true" title="A BabylonJS-exported Box. (including a bug)">
</a>
<figcaption>A BabylonJS-exported Box. (including a bug)</figcaption>
</figure>
</p>
<p><figure>
<a href="https://github.com/wgroeneveld/gba-bitmap-engine/raw/master/img/octa.gif?raw=true" class="lbox">
<img loading="lazy" src="https://github.com/wgroeneveld/gba-bitmap-engine/raw/master/img/octa.gif?raw=true" title="A rasterized octahedron, with back-face culling.">
</a>
<figcaption>A rasterized octahedron, with back-face culling.</figcaption>
</figure>
</p>
<p>Even calculating the frames per second is a pain. What&rsquo;s a &ldquo;second&rdquo;? Okay, so we need a hardware timer interrupt. When does this thing overflow? How many cycles does the CPU take before that happens? Are you seriously using the divide operator instead of <code>fxdiv()</code>?</p>
<p>Also, I could not remember most of the math needed to project 3D vertices into a 2D view, so I let myself be guided by David&rsquo;s excellent <a href="https://www.davrous.com/2013/06/13/tutorial-series-learning-how-to-write-a-3d-soft-engine-from-scratch-in-c-typescript-or-javascript/">3D soft engine tutorial</a> in JavaScript. Of course I had to port in all Matrix/Vector operations myself.</p>
<p>Future work: texturizing - I&rsquo;m curious to see at what rate we could get a simple box textured with a mario &ldquo;?&rdquo; block. I won&rsquo;t even try to attempt portal rendering like the 007 Nightfire devs.</p>
<p>Check out the source code here: <a href="https://github.com/wgroeneveld/gba-bitmap-engine/">https://github.com/wgroeneveld/gba-bitmap-engine/</a></p>
<h3 id="unit-testing-gba-bios-functions">Unit testing GBA BIOS functions</h3>
<p>Tonc&rsquo;s library functions, which sometimes act as BIOS wrappers, are forward-declared in header files. A square root function, <code>u32 Sqrt(u32 num16fx)</code>, for instance, does not calculate anything: rather, it executes a BIOS interrupt call.</p>
<p>Since GTest cannot cross-compile, let alone execute BIOS interrupts, I needed a way around this. Simply using my own implementation by defining <code>Sqrt</code> suffices thanks to the linker:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#434f54">namespace</span> <span style="color:#434f54">externMath</span> {
<span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;math.h&gt;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span>
<span style="color:#00979d">float</span> <span style="color:#434f54">root</span>(<span style="color:#00979d">float</span> <span style="color:#434f54">num</span>) {
<span style="color:#728e00">return</span> <span style="color:#434f54">sqrt</span>(<span style="color:#434f54">num</span>);
}
}
<span style="color:#434f54">u32</span> <span style="color:#434f54">Sqrt</span>(<span style="color:#434f54">u32</span> <span style="color:#434f54">num16fx</span>) {
<span style="color:#00979d">float</span> <span style="color:#434f54">numfloat</span> <span style="color:#728e00">=</span> <span style="color:#434f54">num16fx</span> <span style="color:#728e00">/</span> ( (<span style="color:#00979d">float</span>)( <span style="color:#8a7b52">1</span><span style="color:#728e00">&lt;&lt;</span><span style="color:#8a7b52">16</span> ));
<span style="color:#728e00">return</span> <span style="color:#d35400">float2fx</span>(<span style="color:#434f54">externMath</span><span style="color:#728e00">::</span><span style="color:#434f54">root</span>(<span style="color:#434f54">numfloat</span>));
}
</code></pre></div><p>Instead of a BIOS call, I leave it up to the <code>math.h</code> default sqrt implementation.</p>
<p>Sometimes, that does not suffice. In <code>tonc_math.h</code>, some forward-declared functions are also defined, in which case GTest will panick. For that, I resorted to <code>#ifndef</code> statements. The result is a bit of a mess, but it works:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;libgba-bitmap-engine/gba/tonc_types.h&gt;</span><span style="color:#728e00">
</span><span style="color:#728e00">#ifdef CODE_COMPILED_AS_PART_OF_TEST
</span><span style="color:#728e00"></span> <span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;libgba-bitmap-engine/gba/tonc_math_stub.h&gt;</span><span style="color:#728e00">
</span><span style="color:#728e00">#else
</span><span style="color:#728e00"></span> <span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;libgba-bitmap-engine/gba/tonc_math.h&gt;</span><span style="color:#728e00">
</span><span style="color:#728e00">#endif
</span></code></pre></div><p>Since I did not want to change the tonc files itself, constructs like the above sometimes appear in the engine header files when referencing tonc files. Interested readers can always plow through the C++ files in the Github repository.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 21 July 2020.
</p>
]]>
</description>
</item>
<item>
<title>ITiCSE 2020: A Report</title>
<link>https://brainbaking.com/post/2020/06/iticse-2020/</link>
<comments>https://brainbaking.com/post/2020/06/iticse-2020/#commento</comments>
<pubDate>Mon, 22 Jun 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/06/iticse-2020/</guid>
<category domain="https://brainbaking.com/tags/conference">conference</category>
<description>
<![CDATA[
<p>I was supposed to fly out to Norway - and then COVID came along and said &ldquo;nope&rdquo;. Too bad, as the appealing photographs of Trondheim certainly made the <a href="http://iticse.acm.org">ITiCSE</a> (<em>Innovation and Technology in Computer Science Education</em>) conference even more attracting this year. Instead, it took place on-line, using Zoom and Moodle as the tools of choice. I&rsquo;d like to briefly summarize things that caught my attention. I haven&rsquo;t been able to watch all sessions and recorded presentations, but it&rsquo;s an interesting exercise to dump my own thoughts here.</p>
<h3 id="a-selection-of-papers">A selection of papers</h3>
<h4 id="creative-choice-in-fifth-grade-computing-curriculumhttpsdlacmorgdoipdf10114533415253387405"><a href="https://dl.acm.org/doi/pdf/10.1145/3341525.3387405">Creative Choice in Fifth Grade Computing Curriculum</a></h4>
<p><em>How do you engage younger students?</em> The answer seems to be through <em>creativity</em> - interesting, as we found similar things when <a href="/sigcse">letting students program on the GBA</a>. Naturally, as soon as the C-word is dropped, my interest is peaked. The authors talk about P-Creativity (Personal, the focus point) and H-Creativity (novel to humanity, impacting a much broader audience).</p>
<blockquote>
<p>Do creative assignments effect student performance? No statistic relevance was found.</p>
</blockquote>
<p>Even without the statistic significance, and even with the focus on younger students, paper references could be interesting to check out for undergraduates (&quot;<em>effective means of engaging various students</em>&quot;, &ldquo;<em>champions of change</em>&rdquo;, and others)</p>
<h4 id="examining-student-coding-behaviorhttpsdlacmorgdoipdf10114533415253387408"><a href="https://dl.acm.org/doi/pdf/10.1145/3341525.3387408">Examining student coding behavior</a></h4>
<p>This study was conducted in context of a creative computing course, in which expression is the main goal, not efficient coding or syntax knowledge. Lots of work like Abstract Syntax Trees and Vocabulary Analysis has been done in this one, and it got me wondering - we could do something similar (albeit much simpler) using Github commit logs as a base. I do have a few years of commit logs lying around from the GBA C++ course, maybe I already have interesting data.</p>
<p>The question is then, what would I be looking for? This research tried to examine how students' work evolved over time. Maybe it would give us insight on the creative process of creating a game? Given the fact that not all students commit everything in a single hefty push with commit comment &ldquo;<em>Work done! We rule!</em>&rdquo;&hellip;</p>
<h4 id="top-down-design-of-a-curriculum-for-a-computer-games-bahttpsdlacmorgdoipdf10114533415253387378"><a href="https://dl.acm.org/doi/pdf/10.1145/3341525.3387378">Top-down Design of a Curriculum for a Computer Games BA</a></h4>
<p>The paper contains an interesting discussion on the vote for C# instead of C++, as of course Unity always wins in educational contexts over the Unreal engine. However, what I found the most interesting, combined with words in the closing keynote, was perhaps the fact that there are so many distinct Computer Science-related degrees out there.</p>
<p>A Computer Game BA is multi-disciplinary in nature: arts, design, programming, &hellip; Our faculty of Engineering Technology delivers engineers who can specialize in Electronics/ICT. Then there&rsquo;s a more theoretical Computer Science degree, but you can also go for a masters in Software Engineering - or on bachelor level, applied informatics. That begs the question:</p>
<blockquote>
<p>In any CS degree, is there enough space to learn something well?</p>
</blockquote>
<p>If you get to see a bit of game programming, a bit of AI, and a bit of design, are you a jack of all trades, or a jack of no trades at all? The same could be said for our own students, since the first year is shared across all engineering students, and packed with general courses (almost) devoid of computing&hellip;</p>
<p>The more specialized and complex the Computing world gets (according to Matti Tedre, every decade), the more difficult it will be to deliver students capable of doing whatever the industry requires. Instead, I think we should focus on abstract thinking skills, and use Capita Selecta to let them have a taste of the possiblities. In the closing keynote, Matti anecdotally brings up old ACM SIGCSE Bulletins, concluding that the discussions we&rsquo;re having today in the field of CSEd. are still the same discussions from almost 40 years ago:</p>
<ul>
<li><em>What should we teach students?</em></li>
<li><em>Which programming language is better to learn than others?</em></li>
</ul>
<p>That keynote was awesome, not only because of it&rsquo;s contents, but also because of the &lsquo;augmented reality&rsquo;-enabled joke:</p>
<p><figure>
<a href="../augmented.jpg" class="lbox">
<img loading="lazy" src="../augmented.jpg" title="Matti&#39;s Augmented Reality slides">
</a>
<figcaption>Matti&#39;s Augmented Reality slides</figcaption>
</figure>
</p>
<p>At least we got the feeling of looking at slides from an audience.</p>
<h4 id="a-feedback-oriented-platform-for-programming-practicehttpsdlacmorgdoipdf10114533415253393996"><a href="https://dl.acm.org/doi/pdf/10.1145/3341525.3393996">A feedback-oriented platform for programming practice</a></h4>
<p>An interesting tool developed at Los Andes in Colombia to cope with submissions of 900+ students and to deliver a deliberate practice platform that can scale up when needed. I&rsquo;m drawn to this because of the use of Docker and the philosophy of automation. However, I can&rsquo;t help but wonder:</p>
<blockquote>
<p>Why does everybody have to keep on reinventing the wheel?</p>
</blockquote>
<p>There are so many tools out there, including this one, that has not been tailored for usage outside of the context. It&rsquo;s a &ldquo;<em>scratch your own itch</em>&rdquo; project, which is great, but when a paper like this gets accepted, it suddenly stands in the spotlight, potentially becoming of use for other universities. And that ultimately rarely happens. There are exceptions, where it&rsquo;s well-marketed and matured, like BlueJ for instance.</p>
<p>I&rsquo;ve come across papers before that employed a home-brewed piece of technology for their method that I wanted to use too, but was out of luck because I could not find a download link or more info. Simply making these things a bit more visible on the Internet would do wonders. I wonder why more people in the industry are automatically - and intentionally - giving back to the community, compared to people in academia. That might be a bold (and possibly wrong) statement; it&rsquo;s a gut feeling. Let&rsquo;s be honest here, publishing a paper about a tool without <strong>releasing</strong> the tool is not exactly giving back to the community.</p>
<p>Same feeling with the <a href="https://dl.acm.org/doi/pdf/10.1145/3341525.3387369">Postponing the Concept of Class When Introducing OOP</a> paper: why invent a prototype-based language (Wolluk) instead of reusing Javascript? That almost seems ridiculous considering graduates will have to learn JS anyway! Why? Explore <a href="https://stateofjs.com">The State of Javascript 2019</a> - that&rsquo;s why.</p>
<h4 id="twenty-four-years-of-iticse-authorshttpsdlacmorgdoipdf10114533415253387387"><a href="https://dl.acm.org/doi/pdf/10.1145/3341525.3387387">Twenty-Four Years of ITiCSE Authors</a></h4>
<p>A <em>bibliometric</em> paper - another new term I&rsquo;ve learned - concerned the last 24 years of published papers at ITiCSE by Simon. This is interesting Because it&rsquo;s a big <strong>wake-up call for Belgium</strong>! ITiCSE is the highest-rated European conference on Computing Education, and we&rsquo;re one of the worst scoring countries:</p>
<p><figure>
<a href="../countries-iticse.jpg" class="lbox">
<img loading="lazy" src="../countries-iticse.jpg" alt="Number of papers, including fractional contributions, from each country" >
</a>
</figure>
</p>
<p>Belgian universities submitted <strong>two papers</strong> in the last twenty-four years to a highly rated computing education conference. Two. 2. Can you believe that? Looking at our neighbors: Netherlands 21, Germany 55, France 16. <em>Whoops</em>. I could go ahead and look up the data for the SIGCSE Technical Symposium, but I&rsquo;m pretty sure things are even worse there as it&rsquo;s generally regarded as a USA-heavy conference (and they are planning to do something about that).</p>
<p>At least the year <code>2020</code> proved to be an exception: my supervisor Joost and I both published a paper, cranking up the number to a whopping four, thereby leaving Cyrpus and Romania behind - given they did not publish anything this year. The acceptance rate this year was barely <code>27%</code> but that&rsquo;s not an excuse.</p>
<p>It&rsquo;s very sad to see that Computing Education has not been recognized as a true discipline in Belgium. At my university, we have a small research group dedicated to that (OVI), but compared to <a href="https://wms.cs.kuleuven.be/cs/onderzoek">other KU Leuven CS research groups</a>, it could almost be called redundant. That said, if it were not for CSEd, other CS disciplines would not be academic disciplines right now&hellip; It&rsquo;s about time somebody rings the bell!</p>
<p>To again quote Matti Tedre&rsquo;s amazing closing keynote:</p>
<blockquote>
<p>When it comes to pioneers in computing&hellip; most of them are also educators.</p>
</blockquote>
<h3 id="the-transition-from-face-to-face-to-virtual">The transition from face-to-face to virtual</h3>
<p>I&rsquo;ll sum it up with a screenshot:</p>
<p><figure>
<a href="../zoom.jpg" class="lbox">
<img loading="lazy" src="../zoom.jpg" title="That 10x20 white space? That&#39;s the slides.">
</a>
<figcaption>That 10x20 white space? That&#39;s the slides.</figcaption>
</figure>
</p>
<p>Yeah. Zoom connection issues, especially when presenters switched. It wasn&rsquo;t bad but I did experience this multiple times. Having to navigate in-between sessions was especially confusing, hopping back and forth between Moodle and Zoom. There was no central hub available (besides the somewhat clumsy Moodle), meaning these things were not possible:</p>
<ul>
<li>Chatting with a specific person without contacting them via Moodle</li>
<li>Having persistent chat and Q&amp;A text.</li>
<li>Looking around and seeing who&rsquo;s attending in Zoom Webinars. What&rsquo;s up with that? I had the feeling like I was watching alone&hellip;</li>
<li>When a session ended, &lsquo;returning somewhere&rsquo; for a chat.</li>
</ul>
<p>It was okay for a first attempt, but to be honest, using a more community-based hub such as Slack or Discord instead of having to go to Moodle would certainly make it easier to get the &lsquo;conference-vibe&rsquo;. Remember <em>mIRC</em> back in the day? If you joined a channel, you could see stuff happening. Now, I couldn&rsquo;t.</p>
<p>The organization did their best, I think partly participants (like myself) are to blame: 300+ registered, barely anything moving on the forums. How is that possible? Some virtual open sessions and most poster sessions were almost empty: authors waiting for questions that never came. Of course in a digital world it&rsquo;s easier to get distracted or to quietly slip off to do something else.</p>
<h3 id="closing-thoughts">Closing thoughts</h3>
<p>Do not mention &ldquo;<em>computational thinking</em>&rdquo; in ACM conferences. I seemed to unleash quite a chain of reactions in the open discussion talks doing that - it should be called &ldquo;<em>algorithmic thinking</em>&rdquo; now? I don&rsquo;t get why that would make things clear. It&rsquo;s as vague as the first term, you just sidestepped the 30 or so definitions already present in literature, congrats.</p>
<p>Another just as vague concept: using <a href="https://www.felienne.com/archives/6375">notational machines</a> in teaching. I&rsquo;m still trying to wrap my mind on the concept - the paper that tried to clear things up was not particularly helpful&hellip; To be honest, I think a bit of industry-experience I carry around, also called <em>pragmatism</em>, would do wonders here. Insert random <a href="https://tenor.com/view/the-office-steve-carell-michael-scott-too-far-road-trip-problems-gif-4412706">Too Far Gif</a> here:</p>
<p><figure>
<a href="../toofar.gif" class="lbox">
<img loading="lazy" src="../toofar.gif" alt="took it too far" >
</a>
</figure>
</p>
<p>Another interesting discussion on why we should stop teaching low level concepts (programming) compared to other fields took place in the closing keynote. According to Matti Tedre:</p>
<blockquote>
<p>Programming is a really clumsy way to interact with a computer.</p>
</blockquote>
<p>It&rsquo;s apparently something from the eighties. We need that less and less. It&rsquo;s needed more rarely for making the computer do the kinds of jobs you want the computer to do. He doesn&rsquo;t see why we should stick to that clumsy way when we already have different means of controlling it. In the end, &ldquo;<em>we want to teach kids how to control the machines</em>&rdquo;.</p>
<p>As complexity slowly but steadily grows, it will be really interesting to see what the computer science (education) field will look like in a few decades&hellip;</p>
<p>Things I still need to plow through:</p>
<ul>
<li><a href="https://aaltodoc.aalto.fi/handle/123456789/18195">Emergence of computing education as a research discipline</a> - Simon&rsquo;s PhD thesis</li>
<li><a href="https://gist.github.com/amyjko/689837b8eefccb3a8a28ff0aa5300615">What is computing education research?</a> Amy J. Ko&rsquo;s notes</li>
<li><a href="https://www.goodreads.com/book/show/9247209-the-computer-boys-take-over">The Computer Boys Take Over</a> - a book about the computer revolution of the mid-twentieth century</li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 22 June 2020.
</p>
]]>
</description>
</item>
<item>
<title>Project Warlock: About Perseverance</title>
<link>https://brainbaking.com/post/2020/06/about-perseverance/</link>
<comments>https://brainbaking.com/post/2020/06/about-perseverance/#commento</comments>
<pubDate>Tue, 16 Jun 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/06/about-perseverance/</guid>
<category domain="https://brainbaking.com/tags/games">games</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/projectwarlock.jpg"/>
</p>
<p>In November 2016, Polish teen game developer Jakub Cislo, by then migrated to Germany, created a kickstarter project for a retro first person dungeon crawler game called <strong>Exitium</strong>. It is a game dedicated to old skool FPS shooters like Wolfenstein 3D and Doom.</p>
<h3 id="from-idea-to-vision">From idea to vision</h3>
<p>Why is that so spectacular? Because Jakub is born in 1998, and never lived in the era of nineties shooters. Because Jakub should be studying math and geology in high school instead of fiddling with the Unity engine.</p>
<p><figure>
<a href="../exitium.jpg" class="lbox">
<img loading="lazy" src="../exitium.jpg" title="Exitium">
</a>
<figcaption>Exitium</figcaption>
</figure>
</p>
<p>His dad introduced him into the wonderful world of shotguns (Doom) and spellcasters (Hexen). Compared to the lacking level design of modern shooters, it felt like a breath of fresh air. Certainly inspiring enough to start learning how to create your own game - entirely from scratch - with YouTube how-to videos as his only help.</p>
<p>The kickstarter <a href="https://www.kickstarter.com/projects/286837648/exitum-3d-retro-fps-rpg-shooter/description">movie of Exitium</a> is still online. Cislo received <code>€205</code> from 15 backers - double the amount he had hoped to scrape together to get the serious work started.</p>
<p><figure>
<a href="../cataclysm-3d.jpg" class="lbox">
<img loading="lazy" src="../cataclysm-3d.jpg" title="Cataclysm 3D">
</a>
<figcaption>Cataclysm 3D</figcaption>
</figure>
</p>
<p>A few years later, Exitium evolved into <strong>Cataclysm 3D</strong>, a revision he tried to show off to an early crowd using the Steam Greenlight platform. Sadly, he got a lot of hate because of the graphics. Mind you, this was a one-man show, and created by a stubborn teenager that was not about to give up that easily. A <a href="https://kotaku.com/teen-developer-makes-game-inspired-by-90s-shooters-that-1829874126">Kotaku interview</a> revealed how he felt about being rejected by anonymous people:</p>
<blockquote>
<p>At first, he couldnt help but feel discouraged. All I wanted to do was just make a fun game.</p>
</blockquote>
<p>He was determined to show everyone he won&rsquo;t back down that easily. In an effort to bend the bad rep into positive criticism, he hired an artist, level and sound designer, and got to work - again.</p>
<p>A Steam Greenlight <a href="https://www.gameskinny.com/0tfk4/interview-with-jakub-cislo-sole-developer-of-retro-style-fps-cataclysm-3d">movie of Cataclysm 3D</a> is still online. It was expected to release mid 2017. A shareware version did get released - the good old fashioned way! However, fans had to wait 2 more years to actually play the polished product: <strong>Project Warlock</strong>.</p>
<p><figure>
<a href="../project-warlock-1.jpg" class="lbox">
<img loading="lazy" src="../project-warlock-1.jpg" title="Project Warlock 0.1">
</a>
<figcaption>Project Warlock 0.1</figcaption>
</figure>
</p>
<p>The revamped game of the revamped game got a publisher&rsquo;s attention who helped him market the game at <a href="https://www.gog.com/game/project_warlock">GOG.com</a>. But how do you combine your school work with creating a game and having the life of a typical teenager: parties, friends, and such? The answer is you don&rsquo;t:</p>
<blockquote>
<p>Once I come home, I just go straight to my PC and start working on the game. I sleep a lot less.</p>
</blockquote>
<p>His social life took a big hit. Interviews with <a href="https://www.stardewvalley.net/faq/">Eric Barone</a>, the guy (another one-man show) behind <em>Stardew Valley</em>, showcase the same effect. He had to work long hours on his game while trying to maintain his day-job because well, things still have to be paid.</p>
<p><figure>
<a href="../project-warlock-2.jpg" class="lbox">
<img loading="lazy" src="../project-warlock-2.jpg" title="Project Warlock 1.0">
</a>
<figcaption>Project Warlock 1.0</figcaption>
</figure>
</p>
<p>After more UI polishing, the final version of the game could finally be released upon the public. And they <a href="https://www.youtube.com/watch?v=xcknq-wQn3E">love how it turned out</a>. It is a true homage to classic FPS shooters, an amazing feat considering Cislo&rsquo;s background and age. Even the original Doom level designer reached out to Jakub:</p>
<blockquote>
<p>I woke up one morning, and I saw that there was a new comment on my Facebook fan page from John Romero himself!</p>
</blockquote>
<p>What an amazing achievement this must be: getting recognition; getting positive reviews; especially after being gunned down a couple of years before.</p>
<h3 id="a-persistent-mind-is-a-great-mind">A persistent mind is a great mind</h3>
<p>The development story of Project Warlock grabs me by the throat because of a few things. First, it confirms what I found out about creativity: it literally is <em>the brew of different inputs</em>, the games Jakub played with his dad and that inspired him. Next, only people with high levels of <em>persistence</em> will get that far. Others would have given up after the negative feedback, simply reverted to playing basketball on a Friday night. Lastly, <em>Buckshot Software</em>, Cislo&rsquo;s development company, is the anti-team compared to 10 million production studios dishing out Call of Duty iterations yearly.</p>
<p>Prof. Pieter J. van Strien wrote in his book <a href="https://www.goodreads.com/book/show/29483721-het-creatieve-genie">The Creative Genius</a> about the hard labors of love of Faraday, Einstein, Darwin, and Newton. Not a single one of those would have made it without perseverance and a lot of failures. You have to be able to convert failures into learning moments, and eventually success. However, that success might come within a few years, or within ten years, as was the case for German philosopher Kant. Jakub Cislo is cut from the same cloth:</p>
<blockquote>
<p>I have too many ideas to take a break, and I want to improve upon myself. I really want to get the best out of me.</p>
</blockquote>
<p>To me, Project Warlock is a touching example of <strong>perseverance</strong>. I hope I can live up to it when thinking about my own projects. When I sometimes lose interest, ambition, motivation, or everything at once: I just have to pick up the controller and replay Project Warlock.</p>
<p>The next day, I&rsquo;ll get back to work.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 16 June 2020.
</p>
]]>
</description>
</item>
<item>
<title>Combining async with generators in Node 11</title>
<link>https://brainbaking.com/post/2020/06/combining-async-with-generators-in-node/</link>
<comments>https://brainbaking.com/post/2020/06/combining-async-with-generators-in-node/#commento</comments>
<pubDate>Thu, 11 Jun 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/06/combining-async-with-generators-in-node/</guid>
<category domain="https://brainbaking.com/tags/javascript">javascript</category>
<category domain="https://brainbaking.com/tags/node">node</category>
<description>
<![CDATA[
<p>Whizbang time! So, I was in need of a simple resursive Javascript function that iterates over all directories to look for <code>.md</code> Markdown files, to feed it to a search indexer. This is a node script my deploy script utilizes when updating this website. My Hugo content directory looks like this nowadays:</p>
<pre><code>content/
post/
2020/
06/
article1.md
article2.md
05/
article3.md
2019/
12/
article4.md
</code></pre><p>This means that the URL structure of articles on Brain Baking changed (for the better) to <a href="/post/2020/06/combining-async-with-generators-in-node/">/post/2020/06/combining-async-with-generators-in-node/</a>. Instead of simply using <code>fs.readdir()</code> in the <code>content/</code> folder, I had to use a bit of recursion because of the slightly more complex directory structure.</p>
<p>And then I found an interesting <a href="https://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search">Stackoverflow post</a>, explaining how to do it in node 8, 10.10+, and 11+. And my god, things did not stand still, did they. As is usually the case in the JS world.</p>
<h3 id="node-8-using-awaitasync">Node 8: Using await/async</h3>
<p>Since most filesystem related node calls are asynchronous, you use a good amount of <code>await</code> and <code>async</code> when writing the code:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#00979d">const</span> { <span style="color:#728e00">promisify</span> } <span style="color:#728e00">=</span> <span style="color:#728e00">require</span>(<span style="color:#7f8c8d">&#39;util&#39;</span>);
<span style="color:#00979d">const</span> { <span style="color:#728e00">resolve</span> } <span style="color:#728e00">=</span> <span style="color:#728e00">require</span>(<span style="color:#7f8c8d">&#39;path&#39;</span>);
<span style="color:#00979d">const</span> <span style="color:#728e00">fs</span> <span style="color:#728e00">=</span> <span style="color:#728e00">require</span>(<span style="color:#7f8c8d">&#39;fs&#39;</span>);
<span style="color:#00979d">const</span> <span style="color:#728e00">readdir</span> <span style="color:#728e00">=</span> <span style="color:#728e00">promisify</span>(<span style="color:#728e00">fs</span>.<span style="color:#728e00">readdir</span>);
<span style="color:#00979d">const</span> <span style="color:#728e00">stat</span> <span style="color:#728e00">=</span> <span style="color:#728e00">promisify</span>(<span style="color:#728e00">fs</span>.<span style="color:#728e00">stat</span>);
<span style="color:#00979d">async</span> <span style="color:#728e00">function</span> <span style="color:#728e00">getFiles</span>(<span style="color:#728e00">dir</span>) {
<span style="color:#00979d">const</span> <span style="color:#728e00">subdirs</span> <span style="color:#728e00">=</span> <span style="color:#00979d">await</span> <span style="color:#728e00">readdir</span>(<span style="color:#728e00">dir</span>);
<span style="color:#00979d">const</span> <span style="color:#728e00">files</span> <span style="color:#728e00">=</span> <span style="color:#00979d">await</span> <span style="color:#728e00">Promise</span>.<span style="color:#728e00">all</span>(<span style="color:#728e00">subdirs</span>.<span style="color:#728e00">map</span>(<span style="color:#00979d">async</span> (<span style="color:#728e00">subdir</span>) =&gt; {
<span style="color:#00979d">const</span> <span style="color:#728e00">res</span> <span style="color:#728e00">=</span> <span style="color:#728e00">resolve</span>(<span style="color:#728e00">dir</span>, <span style="color:#728e00">subdir</span>);
<span style="color:#728e00">return</span> (<span style="color:#00979d">await</span> <span style="color:#728e00">stat</span>(<span style="color:#728e00">res</span>)).<span style="color:#728e00">isDirectory</span>() <span style="color:#728e00">?</span> <span style="color:#728e00">getFiles</span>(<span style="color:#728e00">res</span>) <span style="color:#728e00">:</span> <span style="color:#728e00">res</span>;
}));
<span style="color:#728e00">return</span> <span style="color:#728e00">files</span>.<span style="color:#728e00">reduce</span>((<span style="color:#728e00">a</span>, <span style="color:#728e00">f</span>) =&gt; <span style="color:#728e00">a</span>.<span style="color:#728e00">concat</span>(<span style="color:#728e00">f</span>), []);
}
</code></pre></div><p>What&rsquo;s happening? Nothing special, once you get the hang of Javascript&rsquo;s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async functions</a>. Usage is also simple: <code>getFiles('post').then(doStuffWithFiles)</code>. In fact, <code>async</code> is just syntactic sugar for <code>Promise.resolve()</code>. According to MDN, this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#00979d">async</span> <span style="color:#728e00">function</span> <span style="color:#728e00">sup</span>() {
<span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;yo&#34;</span>;
}
</code></pre></div><p>is equivalent to:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#728e00">function</span> <span style="color:#728e00">sup</span>() {
<span style="color:#728e00">return</span> <span style="color:#728e00">Promise</span>.<span style="color:#728e00">resolve</span>(<span style="color:#7f8c8d">&#34;yo&#34;</span>);
}
</code></pre></div><p>since nothing asynchronous is happening at all, the <code>Promise</code> object can immediately resolve, and you can carry on with doing whatever it is you plan on doing. Oh, and <code>util.promisify()</code> is a Node 8 trinket that converts callback-based functions into Promise-based ones. The last function of <code>readdir()</code> is a callback function, and otherwise, we would end up nesting functions in functions in functions in &hellip; - the only requirement is that you follow Node&rsquo;s callback style. A function template like <code>const myfn = (delay, callback) =&gt; { };</code> fits.</p>
<p>And yes, there&rsquo;s a <a href="https://github.com/ljharb/util.promisify">polyfill for that</a>.</p>
<h3 id="node-1010-spreading-it-out">Node 10.10: Spreading it out</h3>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#00979d">const</span> { <span style="color:#728e00">resolve</span> } <span style="color:#728e00">=</span> <span style="color:#728e00">require</span>(<span style="color:#7f8c8d">&#39;path&#39;</span>);
<span style="color:#00979d">const</span> { <span style="color:#728e00">readdir</span> } <span style="color:#728e00">=</span> <span style="color:#728e00">require</span>(<span style="color:#7f8c8d">&#39;fs&#39;</span>).<span style="color:#728e00">promises</span>;
<span style="color:#00979d">async</span> <span style="color:#728e00">function</span> <span style="color:#728e00">getFiles</span>(<span style="color:#728e00">dir</span>) {
<span style="color:#00979d">const</span> <span style="color:#728e00">dirents</span> <span style="color:#728e00">=</span> <span style="color:#00979d">await</span> <span style="color:#728e00">readdir</span>(<span style="color:#728e00">dir</span>, { <span style="color:#728e00">withFileTypes</span><span style="color:#728e00">:</span> <span style="color:#00979d">true</span> });
<span style="color:#00979d">const</span> <span style="color:#728e00">files</span> <span style="color:#728e00">=</span> <span style="color:#00979d">await</span> <span style="color:#728e00">Promise</span>.<span style="color:#728e00">all</span>(<span style="color:#728e00">dirents</span>.<span style="color:#728e00">map</span>((<span style="color:#728e00">dirent</span>) =&gt; {
<span style="color:#00979d">const</span> <span style="color:#728e00">res</span> <span style="color:#728e00">=</span> <span style="color:#728e00">resolve</span>(<span style="color:#728e00">dir</span>, <span style="color:#728e00">dirent</span>.<span style="color:#728e00">name</span>);
<span style="color:#728e00">return</span> <span style="color:#728e00">dirent</span>.<span style="color:#728e00">isDirectory</span>() <span style="color:#728e00">?</span> <span style="color:#728e00">getFiles</span>(<span style="color:#728e00">res</span>) <span style="color:#728e00">:</span> <span style="color:#728e00">res</span>;
}));
<span style="color:#728e00">return</span> <span style="color:#728e00">Array</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">concat</span>(...<span style="color:#728e00">files</span>);
}
</code></pre></div><p>The spread operator <code>...</code> makes our <code>reduce()</code> redundant, but the most important change here is <code>requie('fs').promises</code> instead of <code>promisify()</code> and a slightly changed API usage of that. Things are starting to get a bit woozy here.</p>
<p>For instance, did you know that the <a href="http://bluebirdjs.com/docs/why-bluebird.html">Bluebird Promise library</a> claims to be significantly faster than native ES6 Promise implementations? Of course, there are other reasons to resort to Bluebird, such as compatibility and utility functions. It should work even in Netscape! Yay - who still cares about that?</p>
<h3 id="node-11-combining-async-with-generator-functions">Node 11: Combining async with generator functions</h3>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#00979d">const</span> { <span style="color:#728e00">resolve</span> } <span style="color:#728e00">=</span> <span style="color:#728e00">require</span>(<span style="color:#7f8c8d">&#39;path&#39;</span>);
<span style="color:#00979d">const</span> { <span style="color:#728e00">readdir</span> } <span style="color:#728e00">=</span> <span style="color:#728e00">require</span>(<span style="color:#7f8c8d">&#39;fs&#39;</span>).<span style="color:#728e00">promises</span>;
<span style="color:#00979d">async</span> <span style="color:#728e00">function</span><span style="color:#728e00">*</span> <span style="color:#728e00">getFiles</span>(<span style="color:#728e00">dir</span>) {
<span style="color:#00979d">const</span> <span style="color:#728e00">dirents</span> <span style="color:#728e00">=</span> <span style="color:#00979d">await</span> <span style="color:#728e00">readdir</span>(<span style="color:#728e00">dir</span>, { <span style="color:#728e00">withFileTypes</span><span style="color:#728e00">:</span> <span style="color:#00979d">true</span> });
<span style="color:#728e00">for</span> (<span style="color:#00979d">const</span> <span style="color:#728e00">dirent</span> <span style="color:#728e00">of</span> <span style="color:#728e00">dirents</span>) {
<span style="color:#00979d">const</span> <span style="color:#728e00">res</span> <span style="color:#728e00">=</span> <span style="color:#728e00">resolve</span>(<span style="color:#728e00">dir</span>, <span style="color:#728e00">dirent</span>.<span style="color:#728e00">name</span>);
<span style="color:#728e00">if</span> (<span style="color:#728e00">dirent</span>.<span style="color:#728e00">isDirectory</span>()) {
<span style="color:#728e00">yield</span><span style="color:#728e00">*</span> <span style="color:#728e00">getFiles</span>(<span style="color:#728e00">res</span>);
} <span style="color:#728e00">else</span> {
<span style="color:#728e00">yield</span> <span style="color:#728e00">res</span>;
}
}
}
</code></pre></div><p>Head = blown. Don&rsquo;t forget to change it&rsquo;s usage, since we&rsquo;re returning item per item using <code>yield</code>, we should iterate over the results:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js">(<span style="color:#00979d">async</span> () =&gt; {
<span style="color:#728e00">for</span> <span style="color:#00979d">await</span> (<span style="color:#00979d">const</span> <span style="color:#728e00">f</span> <span style="color:#728e00">of</span> <span style="color:#728e00">getFiles</span>(<span style="color:#7f8c8d">&#39;.&#39;</span>)) {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">f</span>);
}
})()
</code></pre></div><p>Let&rsquo;s take a few steps back. What&rsquo;s a <code>function*</code>? A really, <em>really</em> badly chosen syntax for a <em>generator function</em>, that, according to MDN, is:</p>
<blockquote>
<p>Generators are functions that can be exited and later re-entered. Their context will be saved across re-entrances.</p>
</blockquote>
<p>You simply &ldquo;exit&rdquo; the function using <code>yield</code> and get access to the returned object or primitive using <code>fn.next().value</code>. As long as <code>yield</code> has indeed something to yield, it will not return <code>undefined</code>. This is mostly handy to create so-called unlimited functions that seemingly never exit, except that they do. A simple generator, inside an ES6 class (now that we&rsquo;re at it we might as well go all out) could look like this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#00979d">class</span> <span style="color:#728e00">Ids</span> {
<span style="color:#728e00">*</span><span style="color:#728e00">nextId</span> () {
<span style="color:#728e00">let</span> <span style="color:#728e00">index</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>
<span style="color:#728e00">while</span>(<span style="color:#00979d">true</span>) <span style="color:#728e00">yield</span> <span style="color:#728e00">index</span><span style="color:#728e00">++</span>
}
}
<span style="color:#00979d">const</span> <span style="color:#728e00">id</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Ids</span>()
<span style="color:#00979d">const</span> <span style="color:#728e00">gen</span> <span style="color:#728e00">=</span> <span style="color:#728e00">id</span>.<span style="color:#728e00">nextId</span>()
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">gen</span>.<span style="color:#728e00">next</span>().<span style="color:#728e00">value</span>) <span style="color:#95a5a6">// prints 0
</span><span style="color:#95a5a6"></span><span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">gen</span>.<span style="color:#728e00">next</span>().<span style="color:#728e00">value</span>) <span style="color:#95a5a6">// prints 1
</span><span style="color:#95a5a6"></span><span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">gen</span>.<span style="color:#728e00">next</span>().<span style="color:#728e00">value</span>) <span style="color:#95a5a6">// ... you know the drill
</span></code></pre></div><p>(Did you see what I did there with the <code>;</code> semicolons?)</p>
<p>Inside generator functions, you can yield other generator function return values using <code>yield*</code>. Inception! Now what If I want to call some <code>async</code> code in between different <code>yield</code>s? Then it&rsquo;s time for some Asperine and an in-depth blog post qwtel wrote about <a href="https://qwtel.com/posts/software/async-generators-in-the-wild/">async generators and it&rsquo;s usage</a>.</p>
<p>Lastly, what is that strange <code>for await</code> syntax? That&rsquo;s the &ldquo;idiomatic&rdquo; way to consume async generator functions. Do I even want to know? Here&rsquo;s the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of">MDN documentation</a>, it would take me too far to go into detail. Async iterators are part of ECMAScript 2018 (ES9), that is only 100% supported by the <code>V8</code> engine. For those of you who cannot wait, there are always polyfills&hellip;</p>
<p>I have to admit that <a href="https://itnext.io/status-of-javascript-ecmascript-2019-beyond-5efca6a2d233">keeping up with the ECMA-262 standard</a> is getting extremely challenging&hellip;</p>
<h3 id="or-would-you-rather-do-things-in-sync">Or would you rather do things in sync?</h3>
<p>Most IO functions in Node come with a synchronous counterpart:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#728e00">var</span> <span style="color:#728e00">walk</span> <span style="color:#728e00">=</span> (<span style="color:#728e00">dir</span>) =&gt; {
<span style="color:#728e00">var</span> <span style="color:#728e00">results</span> <span style="color:#728e00">=</span> []
<span style="color:#728e00">var</span> <span style="color:#728e00">list</span> <span style="color:#728e00">=</span> <span style="color:#728e00">fs</span>.<span style="color:#728e00">readdirSync</span>(<span style="color:#728e00">dir</span>)
<span style="color:#728e00">list</span>.<span style="color:#728e00">forEach</span>((<span style="color:#728e00">fileInList</span>) =&gt; {
<span style="color:#00979d">const</span> <span style="color:#728e00">file</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">`</span><span style="color:#7f8c8d">${</span><span style="color:#728e00">dir</span><span style="color:#7f8c8d">}</span><span style="color:#7f8c8d">/</span><span style="color:#7f8c8d">${</span><span style="color:#728e00">fileInList</span><span style="color:#7f8c8d">}</span><span style="color:#7f8c8d">`</span>
<span style="color:#00979d">const</span> <span style="color:#728e00">stat</span> <span style="color:#728e00">=</span> <span style="color:#728e00">fs</span>.<span style="color:#728e00">statSync</span>(<span style="color:#728e00">file</span>)
<span style="color:#728e00">if</span> (<span style="color:#728e00">stat</span> <span style="color:#728e00">&amp;&amp;</span> <span style="color:#728e00">stat</span>.<span style="color:#728e00">isDirectory</span>()) {
<span style="color:#728e00">results</span> <span style="color:#728e00">=</span> <span style="color:#728e00">results</span>.<span style="color:#728e00">concat</span>(<span style="color:#728e00">walk</span>(<span style="color:#728e00">file</span>))
} <span style="color:#728e00">else</span> {
<span style="color:#728e00">results</span>.<span style="color:#728e00">push</span>(<span style="color:#728e00">file</span>)
}
})
<span style="color:#728e00">return</span> <span style="color:#728e00">results</span>
}
</code></pre></div><p>The proposed solution above is a bit messy, but the key here is <code>readdirSync()</code>. That begs the question: why would you do serial actions asynchronous anyway? It&rsquo;s not that we&rsquo;re in need of parallelism here, although you could divide dir scanning into chunks if things get too big. For a simple directory structure, this will more than suffice. If it is the functional <em>immutability</em> you&rsquo;re after, the above can easily be rewritten as such using <code>filter()</code>.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 11 June 2020.
</p>
]]>
</description>
</item>
<item>
<title>Designing websites with accessibility in mind</title>
<link>https://brainbaking.com/post/2020/06/designing-with-accessibility-in-mind/</link>
<comments>https://brainbaking.com/post/2020/06/designing-with-accessibility-in-mind/#commento</comments>
<pubDate>Thu, 04 Jun 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/06/designing-with-accessibility-in-mind/</guid>
<category domain="https://brainbaking.com/tags/accessibility">accessibility</category>
<description>
<![CDATA[
<p>In my last post about <a href="/tags/webdesign">webdesign</a> called &ldquo;<a href="post/2020/06/tracking-and-privacy-on-websites/">tracking and privacy on websites</a>&rdquo;, I ended with a list of things you need to take into account when building a website - of which <strong>accessibility</strong> is one that is most often overlooked. Something I&rsquo;m also guilty of. Here&rsquo;s my own howto report and effort to open up Brain Baking for everyone, learning how to design websites with accessibility in mind.</p>
<h3 id="1-use-semantic-html5-tags">1. Use Semantic HTML5 tags</h3>
<p>This might not come as a shocker to anyone, but it&rsquo;s still not that frequently applied, sadly. Most bootstrap-based websites are just a pile of <code>&lt;div/&gt;</code> and <code>&lt;span/&gt;</code> containers chunked together with some CSS styling thrown on top. A template or downloaded theme might be rendered as:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#434f54">div</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#39;topbar&#39;</span>&gt;
&lt;<span style="color:#434f54">span</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#39;link&#39;</span>&gt;
&lt;<span style="color:#434f54">a</span>/&gt;
&lt;/<span style="color:#434f54">span</span>&gt;
&lt;/<span style="color:#434f54">div</span>&gt;
&lt;<span style="color:#434f54">div</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#39;container&#39;</span>&gt;
&lt;<span style="color:#434f54">div</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#39;sect1&#39;</span>&gt;bla at today&lt;/<span style="color:#434f54">div</span>&gt;
&lt;<span style="color:#434f54">div</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#39;txt&#39;</span> <span style="color:#434f54">style</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#39;text-align: justify;&#39;</span>&gt;hello&lt;/<span style="color:#434f54">div</span>&gt;
&lt;<span style="color:#434f54">div</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#39;meta&#39;</span>&gt;more related stuff&lt;/<span style="color:#434f54">div</span>&gt;
&lt;/<span style="color:#434f54">div</span>&gt;
&lt;<span style="color:#434f54">div</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#39;copyright&#39;</span>&gt;Brain baking&lt;/<span style="color:#434f54">div</span>&gt;
</code></pre></div><p>Instead of relying on <code>display: block</code>, write something like this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#434f54">nav</span>&gt;
&lt;<span style="color:#434f54">ol</span>&gt;
&lt;<span style="color:#434f54">li</span>&gt;&lt;<span style="color:#434f54">a</span>/&gt;&lt;/<span style="color:#434f54">li</span>&gt;
&lt;/<span style="color:#434f54">ol</span>&gt;
&lt;/<span style="color:#434f54">nav</span>&gt;
&lt;<span style="color:#434f54">main</span>&gt;
&lt;<span style="color:#434f54">header</span>&gt;bla &lt;<span style="color:#434f54">time</span>&gt;at today&lt;/<span style="color:#434f54">time</span>&gt;&lt;/<span style="color:#434f54">header</span>&gt;
&lt;<span style="color:#434f54">article</span>&gt;hello&lt;/<span style="color:#434f54">article</span>&gt;
&lt;<span style="color:#434f54">article</span>&gt;more related stuff&lt;/<span style="color:#434f54">article</span>&gt;
&lt;/<span style="color:#434f54">main</span>&gt;
&lt;<span style="color:#434f54">footer</span>&gt;Brain baking&lt;/<span style="color:#434f54">footer</span>&gt;
</code></pre></div><p>The structure stays the same, but the elements change. The end result is exactly the same in your conventional browser, but it&rsquo;s easier to crawl by search engines - and especially software for people with disabilities.</p>
<p>Other things to keep in mind:</p>
<ul>
<li>Use <code>&lt;button/&gt;</code> when it&rsquo;s a button, not a link. <code>aria-label</code> is there for hidden labels such as the sandwich nav-button for mobile browsers on this site.</li>
<li>Use labels in forms. Avoid use of placeholder values to label or explain input.</li>
<li>Use descriptive link texts (e.g. not &ldquo;click here&rdquo;)</li>
<li>etc&hellip;</li>
</ul>
<p>Try browsing sites by tabbing. Why don&rsquo;t you try it on this site right here? Did you notice the appearance of the otherwise hidden &ldquo;skip to content&rdquo; link before navigation? Keyboard users will otherwise go mad if they have to tab through your nav links again and again.</p>
<h3 id="2-respect-headings-and-paragraphs">2. Respect headings and paragraphs</h3>
<p>Also easy to achieve! Just like I promised: making your website accessible for everyone is just a matter of keeping a few extra rules in mind. Just like a Word or LaTeX document, when writing an article or paper, you start with your header. That&rsquo;s a <code>&lt;h1/&gt;</code> tag. Subheader? <code>&lt;h2/&gt;</code>, and so on. Do not skip a number! Wrap paragraph text in a simple <code>&lt;p/&gt;</code> tag.</p>
<p>My templates contained a lot of header tags just to get the font size right. Obviously, that is <em>wrong</em>: use the <code>font-size</code> CSS property if you really need to. That meant I regularly jumped from <code>&lt;h2/&gt;</code> to <code>&lt;h4/&gt;</code> just for styling purposes.</p>
<h3 id="3-think-about-contrast">3. Think about contrast</h3>
<p>Style a link as a link: with <code>text-decoration: underline</code>! Remember that it will otherwise be hard to tell the difference between a link and just text, even if the color is (slightly) different or if it&rsquo;s in bold. Not everyone will see the difference. Of course you can make exceptions in the navigation bar.</p>
<p>Chrome Dev Tools makes it very easy to check whether the color you&rsquo;ve employed has enough contrast. It will take background colors, font size, and font weight into account. In the Elements tab, inspect an element and filter the Styles tab to the right on &lsquo;color&rsquo;. Click on the color to inspect the calculated contrast:</p>
<p><figure>
<a href="../contrast.jpg" class="lbox">
<img loading="lazy" src="../contrast.jpg" title="The contrast ratio 4.58 is OK according to the standards.">
</a>
<figcaption>The contrast ratio 4.58 is OK according to the standards.</figcaption>
</figure>
</p>
<p>Furthermore, deliberately think about your font styling and sizing. Fonts should have a <code>font-display: swap</code> CSS attribute to avoid flickering (or not rendering if a <code>.woff2</code> file fails to load). Since monitor resolutions are higher than ever, why should you be stuck with <code>font-size: 12px</code>? Don&rsquo;t use hard-coded <code>px</code> or <code>pt</code> but use relative <code>em</code> and <code>rem</code>, and keep &ldquo;14pt&rdquo; as a reference for desktop browsers. I detest websites that still have this incredibly small hard-to-read font that hurts even my eyes.</p>
<h3 id="4-about-images-use-figure">4. About images&hellip; Use <code>&lt;figure/&gt;</code></h3>
<p>I guess it&rsquo;s unnecessary to emphasize the use of the <code>alt</code> attribute in case anyone cannot see the images or they do not get loaded. This does not have anything to do with accessibility, but is almost never filled in (at least by me, whoops). HTML5 comes with a <code>&lt;figure/&gt;</code> tag that finally makes it easy to include a caption - like we&rsquo;re so used to do in LaTeX - using the <code>&lt;figcaption/&gt;</code> tag.</p>
<p>However, in my article source, which is in Markdown <code>.md</code> files, the standard way of including an image is:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-md" data-lang="md">![<span style="color:#434f54">alt text</span>](<span style="color:#434f54">img.jpg &#34;title&#34;</span>)
</code></pre></div><p>And since I did not want to pollute the files with Hugo shortcodes, I came up with an alternative, thanks to <a href="https://www.godo.dev/tutorials/hugo-image-figure-wrap/">this blog post from godo.dev</a>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#434f54">article</span>&gt;
{{ $reAltIn := &#34;&lt;<span style="color:#434f54">p</span>&gt;&lt;<span style="color:#434f54">img</span> <span style="color:#434f54">src</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;([^\&#34;]+)\&#34;</span> <span style="color:#434f54">alt</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;([^\&#34;]*)\&#34;</span> /&gt;&lt;/<span style="color:#434f54">p</span>&gt;&#34; }}
{{ $reAltOut := &#34;&lt;<span style="color:#434f54">figure</span>&gt;&lt;<span style="color:#434f54">a</span> <span style="color:#434f54">href</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;$1\&#34;</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;lbox\&#34;</span>&gt;&lt;<span style="color:#434f54">img</span> <span style="color:#434f54">src</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;$1\&#34;</span> <span style="color:#434f54">alt</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;$2\&#34;</span>&gt;&lt;/<span style="color:#434f54">a</span>&gt;&lt;/<span style="color:#434f54">figure</span>&gt;&#34; }}
{{ $altContent := .Content | replaceRE $reAltIn $reAltOut | safeHTML }}
{{ $reAltTitleIn := &#34;&lt;<span style="color:#434f54">p</span>&gt;&lt;<span style="color:#434f54">img</span> <span style="color:#434f54">src</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;([^\&#34;]+)\&#34;</span> <span style="color:#434f54">alt</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;([^\&#34;]*)\&#34;</span> <span style="color:#434f54">title</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;([^\&#34;]+)\&#34;</span> /&gt;&lt;/<span style="color:#434f54">p</span>&gt;&#34; }}
{{ $reAltTitleOut := &#34;&lt;<span style="color:#434f54">figure</span>&gt;&lt;<span style="color:#434f54">a</span> <span style="color:#434f54">href</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;$1\&#34;</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;lbox\&#34;</span>&gt;&lt;<span style="color:#434f54">img</span> <span style="color:#434f54">src</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;$1\&#34;</span> <span style="color:#434f54">title</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">\&#34;$3\&#34;</span>&gt;&lt;/<span style="color:#434f54">a</span>&gt;&lt;<span style="color:#434f54">figcaption</span>&gt;$3&lt;/<span style="color:#434f54">figcaption</span>&gt;&lt;/<span style="color:#434f54">figure</span>&gt;&#34; }}
{{ $finalContent := $altContent | replaceRE $reAltTitleIn $reAltTitleOut | safeHTML }}
{{ $finalContent }}
&lt;/<span style="color:#434f54">article</span>&gt;
</code></pre></div><p>It effectively replaces any generated <code>&lt;img/&gt;</code> tags with <code>&lt;figure/&gt;</code> wrappers, also including a link and a class that helps my lightbox script function the way it should. You can see the result for yourself in the image above, with caption. If you use a <code>title</code> attribute, the <code>alt</code> attribute can be skipped.</p>
<h3 id="5-inspect-your-site---without-css-and-js">5. Inspect your site - without CSS and JS.</h3>
<p>The Opera plug-ins &ldquo;.no { CSS }&rdquo; and &ldquo;JavaScript toggle On and Off&rdquo; make it easy to do that with two button clicks. The result - after modifications, of course - is this:</p>
<p><figure>
<a href="../nocss.jpg" class="lbox">
<img loading="lazy" src="../nocss.jpg" title="This article viewed without CSS and JS.">
</a>
<figcaption>This article viewed without CSS and JS.</figcaption>
</figure>
</p>
<p>I&rsquo;m getting this sudden 1995 retro vibe, don&rsquo;t you? Now why on earth would you go back to this look? Because if you don&rsquo;t, you won&rsquo;t know how it looks like for special browsers that help people with disabilities navigating the Internet. For example, my <code>&lt;svg/&gt;</code> icons did not contain native <code>height</code> and <code>width</code> attributes, and their <code>viewBox</code> said &ldquo;make it big!&rdquo; but my CSS said &ldquo;no no, keep things small&rdquo;. Without CSS, things get ugly pretty fast&hellip;</p>
<p>Also, what doesn&rsquo;t get loaded without JavaScript? Cookies broke? Form submission gone to hell? In my case, article comments served from Commento will not load, and for the moment I think that&rsquo;s unavoidable, unless I come up with a form of static caching that is currently not provided.</p>
<h3 id="6-dont-know-what-to-alter-use-analysis-tools">6. Don&rsquo;t know what to alter? Use analysis tools.</h3>
<p>Besides the websites <a href="www.webaccessibility.com">webaccessibility.com</a> and the <a href="https://wave.webaim.org">WAVE web accessibility evaluation tool</a>, there&rsquo;s actually something better, and it&rsquo;s again built-in into DevTools: it&rsquo;s called <strong>Lighthouse</strong>, and can be booted up in the &ldquo;Audits&rdquo; tab. Lighthouse will also tell you what to alter to speed up things, so it&rsquo;s not an &ldquo;accessibility-only&rdquo; tool.</p>
<p><figure>
<a href="../lighthouse.jpg" class="lbox">
<img loading="lazy" src="../lighthouse.jpg" title="A Lighthouse report on a Brain Baking article">
</a>
<figcaption>A Lighthouse report on a Brain Baking article</figcaption>
</figure>
</p>
<p>Sadly, scoring more than <code>65%</code> on accessibility is proving to be difficult, since most issues come from Commento&rsquo;s lack of form labeling and usage of <code>alt</code> in avatar images. At least I&rsquo;m no longer flunked!</p>
<p>If you are interested in trying a screen reader yourself, you can configure <a href="https://www.youtube.com/watch?v=5R-6WvAihms">VoiceOver for Mac</a> to see how it helps you navigate webpages, or <a href="https://www.youtube.com/watch?v=Jao3s_CwdRU">NVDA for Windows</a>. As the videos I&rsquo;ve linked to indicate, navigating by header is extremely important.</p>
<p>Resources:</p>
<ul>
<li><a href="https://accessibility.arl.org/standards-best-practices/">Web Accessibility Toolkit</a> - Standards &amp; Best Practices</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility">MDN Web Docs: What is accessibility?</a></li>
<li><a href="https://developers.google.com/web/fundamentals/accessibility/how-to-review">Google Developers: How To Do an Accessibility Review</a></li>
<li><a href="https://a11y.coffee/">A11y Coffee</a> - a great tool for learning about web accessibility.</li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 4 June 2020.
</p>
]]>
</description>
</item>
<item>
<title>Tracking and privacy concerns on websites</title>
<link>https://brainbaking.com/post/2020/06/tracking-and-privacy-on-websites/</link>
<comments>https://brainbaking.com/post/2020/06/tracking-and-privacy-on-websites/#commento</comments>
<pubDate>Mon, 01 Jun 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/06/tracking-and-privacy-on-websites/</guid>
<category domain="https://brainbaking.com/tags/privacy">privacy</category>
<description>
<![CDATA[
<p>Thanks to another great &ldquo;internet stumble&rdquo;, I came across <a href="https://laurakalbag.com/">Laura Kalbag&rsquo;s blog</a> and her stance on <a href="https://laurakalbag.com/i-dont-track-you/">privacy and tracking</a>. She&rsquo;s been giving talks on the subject and created ad- and track-blocking software. Ever since the European GDPR, cookie banners have annoyed website visitors, but how many of us simply press &ldquo;Accept, now get on with it&rdquo;? I did a few experiments, and the results are downright <strong>scary</strong>.</p>
<p>Take a look at HLN.be, &ldquo;Het Laatste Nieuws&rdquo;, a Belgian newspaper website. Opera informs me the SSL certificate is valid:</p>
<p><figure>
<a href="../cookies-hln.jpg" class="lbox">
<img loading="lazy" src="../cookies-hln.jpg" alt="Cookies on the HLN site" >
</a>
</figure>
</p>
<p>Wait, what? <strong>75 cookies in use</strong>? Did I give my consent for every single one of those? You bet I did not! Luckily, I browse with &ldquo;protection on&rdquo; these days, and my protection of choice is not an Adblocker plugin using Google Chrome but Opera&rsquo;s built-in security systems. Pay special attention to the console errors in the above screenshot: <code>net::ERR_BLOCKED_BY_ADBLOCKER</code>. I do not want to know what happens when I turn it off.</p>
<p>Where do these nasty things come from? Who&rsquo;s keeping an eye on me and should I be tracking the trackers? Good question. Here&rsquo;s another screenshot of the <em>Sources</em> tab, to get an idea of where all the data (and thus, trackers) are coming from at hln.be:</p>
<p><figure>
<a href="../servers-hln.jpg" class="lbox">
<img loading="lazy" src="../servers-hln.jpg" alt="Resources and servers used by the HLN website" >
</a>
</figure>
</p>
<p>These servers are serving data when my adblocking system is turned <em>off</em>. <code>tentacles.smartocto.com</code>? A quick look at that webites says things like &ldquo;make every story count&rdquo; and &ldquo;translate strategy into actionable notifications&rdquo;. Smells like they&rsquo;re shipping off tracking data to one of those analytics companies that feed on the information of others.</p>
<p>Let&rsquo;s try another more authorative news website in Belgium, vrt.be/nws. This time, I let Opera inform me on what was blocked and what was not. It blocks both ads and trackers (image pixels, javascript).</p>
<p><figure>
<a href="../blocks-vrt.jpg" class="lbox">
<img loading="lazy" src="../blocks-vrt.jpg" alt="Opera tracker report of vrt.be" >
</a>
</figure>
</p>
<p>It still contains 12 blocked trackers. Most of those are downright advertisers, but others are more subtle. The most common one is of course <em>Google Analytics</em>.</p>
<blockquote>
<p>Google has it&rsquo;s tentacles across 80% of the entire internet. <span>Laura Kalbag</span></p>
</blockquote>
<h3 id="i-dont-want-that-for-my-visitors">I don&rsquo;t want that for my visitors!</h3>
<p>Enough investigation, time for some introspection. What happens when I expose this website to the above tools? Opera blocked one tracker: Google Analytics. The server tab contains the following servers:</p>
<ul>
<li>Google Fonts</li>
<li>Google CDN: Bootstrap</li>
<li>Google Analytics</li>
<li>Font Awesome Icons</li>
<li>Another CDN: jQuery</li>
<li>Goodreads scripts on the about page</li>
</ul>
<p>It is unavoidable that these endpoints can get access to your visitor&rsquo;s <em>referer</em> URL, and possibly the IP. That means loading a static resource such as a <code>.woff2</code> font or a <code>.css</code> stylesheet actually comes <strong>at a cost</strong> - the cost of giving away your wherabouts. Time for some refactoring.</p>
<p>I threw out Bootstrap, jQuery, and Font Awesome, and refactored my Hugo theme to utilize <a href="/post/2020/05/hugo-extended">Sass</a> (reducing the mean load of an uncached page with more than <code>200kb</code>!). Next, I threw out Google Analytics in favor for <a href="https://usefathom.com">Fathom</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, another small and privacy-focused self-hosted go container (netting me another <code>40kb</code>). Then, I hosted all third-party libraries I used myself. So rest assured, Google does not know you were here! This is how the Fathom dashboard looks like:</p>
<p><figure>
<a href="../fathom.jpg" class="lbox">
<img loading="lazy" src="../fathom.jpg" title="The Fathom dashboard">
</a>
<figcaption>The Fathom dashboard</figcaption>
</figure>
</p>
<p>The commenting system I self-host is Commento<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, a fast, privacy-focused commenting platform. It does come with cookies if you decide to login, but then again: its on my own SSL-verified domain. Disqus, the popular and standard static website commenting system, has been known before to be <a href="https://replyable.com/2017/03/disqus-is-your-data-worth-trading-for-convenience/">coming with hidden costs</a>.</p>
<blockquote>
<p>Is Your Data Worth Trading for Convenience?</p>
</blockquote>
<p>When a YouTube video is embedded into one of these pages, it will run in “no cookie” mode. That means content will be served from youtube-nocookie.com, preventing Google from tracking my visitors. I&rsquo;d rather self-host <code>.webm</code>/<code>.mp4</code> content, but copying over someone else&rsquo;s video raises another concern: copyrights.</p>
<p>I added these privacy measures to the <a href="/no-copyright-no-tracker">no-copyright footer</a>.</p>
<h3 id="but-what-about-my-social-embeds">But what about my Social embeds?</h3>
<p>Good question. Simple answer: <strong>get rid of them</strong>.</p>
<p>For Goodreads on this website, I wrote a node script that acts as an anti-corruption layer to fetch the embedded JS code, thus avoiding any cookies. Book cover images are of course still offloaded - although I could also download those.</p>
<p>For Facebook integraion on my other website <a href="https://redzuurdesem.be">Red Zuurdesem</a>, things were a bit more difficult. The problem is that I rely on Facebook to build a community there. As Laura suggested, &ldquo;<em>Post content to your own website first, then push to third-parties</em>&rdquo;. Facebook page posts are copied into <code>.md</code> files that are searchable using lunr.js.</p>
<p>For the &ldquo;classic&rdquo; Facebook widget - well, I cheated&hellip; by taking a screenshot:</p>
<p><figure>
<a href="../fbwidget.jpg" class="lbox">
<img loading="lazy" src="../fbwidget.jpg" alt="the Facebook Widget" >
</a>
</figure>
</p>
<p>Sometimes, the simplest solutions are the best. I bet nobody notices it&rsquo;s static content. I might even go out on a limb here and retake the screenshot once in a while. This gives me the freedom of throwing out the ugly Facebook JS API and token system that has to be renewed every few months (and comes with tons of &ldquo;free&rdquo; cookies!). Good riddance.</p>
<p>For Twitter integration on another website of mine called <a href="https://jefklakscodex.com">Jefklak&rsquo;s Retro Game Codex</a>, I simply rip images and videos to self-host them. A private Twitter account acts as a bridge between my Nintendo Switch and my website - currently, there&rsquo;s no other way to transfer images and videos (besides Facebook). Hooray for HTML5 <code>&lt;video/&gt;</code> tags!</p>
<h3 id="creating-a-website-does-not-stop-after-writing-html-tags">Creating a website does not stop after writing HTML tags&hellip;</h3>
<p>There are so many things to take into consideration. I&rsquo;ve never given them much thought, until now, and I have to say I&rsquo;m glad I&rsquo;m learning. From what I gather so far, the following things need to be taken into consideration:</p>
<ol>
<li><strong>Speed</strong>. People flee after waiting for more than two seconds (I know I do). Compress images, use interlaced mode and cache headers, &hellip;</li>
<li><strong>Responsiveness</strong>. Everything should be in relative <code>rem</code> and not in absolute <code>px</code>, use <code>srcset</code> image attributes, write <code>@media</code> CSS queries, &hellip;</li>
<li><strong>Design</strong>. People also flee if it&rsquo;s not pleasant to the eyes.</li>
<li><strong>Security</strong>. Use (self-signed) SSL <code>https://</code> certificates. Provide base security levels for your <a href="/post/2020/04/vps">own vps</a>. Use honey pots for form submissions.</li>
<li><strong>Development</strong>. Continuous integration/deployment - setup a node/hugo build chain. Make things easy to commit and revert if neccessary. Have a backup plan?</li>
<li><strong>Content</strong>. The most important piece of the puzzle. But what about tags or categories? Files or databases? What about maintainability? Or editors and logins?</li>
<li><strong>Privacy</strong>. Don&rsquo;t track visitors, track traffic instead!</li>
<li><strong>Licence</strong>s. Which copyright system are you applying? Did you attribute your sources correctly?</li>
<li><strong>SEO</strong>. If your site is not found, tumbleweeds instead of readers start appearing&hellip;</li>
<li><strong><a href="/post/2020/06/designing-with-accessibility-in-mind">Accessibility</a></strong>. Use contrasting colors, write <code>alt</code> tags, &hellip;</li>
</ol>
<p>I haven&rsquo;t looked at that last part yet - <em>accessibility</em>. To be continued! (Edit: <a href="/post/2020/06/designing-with-accessibility-in-mind">continued here</a>)</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>Since 2021, I&rsquo;ve migrated to a self-hosted GoatCounter instance, getting rid of all client-side tracking cookies. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Since 2021, I&rsquo;ve decided to stop using commenting systems. One less thing to worry about. If you like to comment, simply use Mastodon or e-mail instead. <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 June 2020.
</p>
]]>
</description>
</item>
<item>
<title>Page Building with Brizy in Wordpress</title>
<link>https://brainbaking.com/post/2020/05/page-building-with-brizy-in-wordpress/</link>
<comments>https://brainbaking.com/post/2020/05/page-building-with-brizy-in-wordpress/#commento</comments>
<pubDate>Tue, 26 May 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/05/page-building-with-brizy-in-wordpress/</guid>
<category domain="https://brainbaking.com/tags/php">php</category>
<category domain="https://brainbaking.com/tags/wordpress">wordpress</category>
<category domain="https://brainbaking.com/tags/brizy">brizy</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/brizy.jpg"/>
</p>
<p>As you may have read, I&rsquo;m quite the <a href="/post/hugo-extended">Hugo.io fan</a> and I build all my websites using this static website generator. As cool and tech-savvy it is, projects like <a href="https://forestry.io/">forestry.io</a> exist to leverage Hugo&rsquo;s powers into the world of teams an non-technical bloggers. However, it still requires things like <em>committing</em> and does not come with a lot of custom design options.</p>
<p>My wife has been blogging on and off for more than five years now, and she&rsquo;s been using things like Blogspot, Webnode, Wix and Wordpress. Not content with any of those, about a month ago she started creating yet another blog, calling in my help with the code portions. She&rsquo;s never content with the design options the free templates offer, and would like to design things herself, without having a lot of knowledge of CSS/HTML.</p>
<p>That&rsquo;s where things like Webnode and Wix come in: a lot of illustrators and designers create their own website using <strong>blocks</strong>: they are <strong>page builders</strong>, where drag and dropping is possible and (ugly) CSS/HTML is scaffolded. Since both Webnode and Wix are paid solutions, and both do not enable you to host it yourself, we decided to go for the Wordpress option again, more specifically with a page builder plugin: <em><a href="https://brizy.io">Brizy</a></em>.</p>
<blockquote>
<p>The most user-friendly website builder in town <span>According to the Brizy website</span></p>
</blockquote>
<p>See for yourself:</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="https://www.youtube-nocookie.com/embed/KUv-NqDR-8s" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
<p>Amazing, right?</p>
<p>Not quite.</p>
<p>It&rsquo;s all good as long as you are creating <em>pages</em>. Pages are static webpages in Wordpress. But when it comes to designing the layout of your blog posts, or <em>posts</em>, things get ugly. Brizy of course also offers a paid version which comes with premium page blocks and more options, but we contented with the free version. I have to admit that creating pages with the free version was surprisingly easy (and maybe even a bit fun too).</p>
<p>In Brizy, you can create a &lsquo;page&rsquo; that acts as a template for blog detail pages, but it &lsquo;forgets&rsquo; to add the actual blog content. I&rsquo;m sure there&rsquo;s another way in the paid version, but I solved that by using a lot of shortcodes: enter <a href="https://getshortcodes.com">Shortcode Ultimate</a>. Adding <code>[su_post field=&quot;post_content&quot;]</code> in a block does generate an error in Brizy&rsquo;s preview mode, but works outside of that.</p>
<p>Actually, injecting post content using that shortcode comes with a big shortcoming: it does not parse shortcodes inside posts themselves (<code>[caption]</code>, <code>[embed]</code>, ..). Solution? A custom filter:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-php" data-lang="php"><span style="color:#728e00">function</span> <span style="color:#d35400">su_post_content_filter</span>(<span style="color:#434f54">$value</span>) {
<span style="color:#728e00">return</span> <span style="color:#728e00">apply_shortcodes</span>(<span style="color:#434f54">$value</span>);
}
</code></pre></div><p>The <code>apply_shortcodes()</code> <a href="https://make.wordpress.org/core/2020/02/13/wordpress-5-4-introduces-apply-shortcodes-as-an-alias-for-do-shortcode/">function</a> in Wordpress parses the shotcodes in the argument for us. I have found the Wordpress function reference to be quite complete and useful. However, it is quite a mess: there are <code>do_</code> functions, <code>apply_</code> ones, lots of methods <code>echo</code> stuff, resulting in me having to capture <code>stdout</code> to return it:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-php" data-lang="php"><span style="color:#728e00">function</span> <span style="color:#d35400">blog_detail_comments_shortcode</span>() {
<span style="color:#728e00">ob_start</span>();
<span style="color:#728e00">comments_template</span>();
<span style="color:#434f54">$html</span> <span style="color:#728e00">=</span> <span style="color:#728e00">ob_get_contents</span>();
<span style="color:#728e00">ob_end_clean</span>();
<span style="color:#728e00">return</span> <span style="color:#434f54">$html</span>;
}
<span style="color:#728e00">add_shortcode</span>(<span style="color:#7f8c8d">&#39;blog_detail_comments&#39;</span>, <span style="color:#7f8c8d">&#39;blog_detail_comments_shortcode&#39;</span>);
</code></pre></div><p>Yuck. What a mess. But now I can use <code>[blog_detail_comments]</code> inside a Brizy template to render the Wordpress blog comments partial - yay! I had to create the following shortcodes myself to get the job done:</p>
<ul>
<li><code>blog_detail_comments</code> - comments form</li>
<li><code>blog_detail_footer</code> - a span with blog detail date and categories</li>
<li><code>show_categories</code> - a list of all categories, used in the sidebar</li>
<li><code>show_current_category</code> - a list of current categories</li>
</ul>
<h4 id="the-blog-overview-page">The Blog Overview page</h4>
<p>This page usually contains a list of latest blog entries. Shortcodes Ultimate does not support pagination - great. I grew tired of reinventing the wheel and installed yet another plugin to do the work for me:</p>
<pre><code>[display-posts pagination=&quot;true&quot; image_size=&quot;thumbnail&quot; include_excerpt=&quot;true&quot; excerpt_length =&quot;30&quot; include_date=&quot;true&quot; category_display=&quot;true&quot; category_label=&quot;&quot; include_excerpt_dash=&quot;false&quot; image_size=&quot;medium&quot; date_format=&quot;d/m/Y&quot;]
</code></pre><p>The result is not great. Instead of utilizing URLs such as <code>/page/2/</code>, as the default Wordpress templates do, now we&rsquo;re stuck with <code>/blog/?dps_paged=3</code> - that is, unless I intervene and rewrite things. Yet. Again. Yuck.</p>
<h4 id="the-blog-detail-page">The Blog Detail page</h4>
<p><figure>
<a href="../brizy_invalid.png" class="lbox">
<img loading="lazy" src="../brizy_invalid.png" alt="&amp;ldquo;Invalid brizy content&amp;rdquo;" title="Did I do something wrong?">
</a>
<figcaption>Did I do something wrong?</figcaption>
</figure>
</p>
<p>A lot of shortcodes are needed here. Blog title, blog contents, blog metadata (the detail footer), blog comment forms, showing a list of categories, a list of most popular or recent posts in the sidebar, &hellip; The problem for my wife is that while designing this page, there are no placeholders available, so it&rsquo;s a bit of a guess how it will turn out to be.</p>
<p>Oh, did I mention that I had to style these things myself? Since you can&rsquo;t use the Brizy Editor to apply a font? That means duplication. And that means more shit when my wife decides to use another font on all pages: the shortcodes won&rsquo;t budge.</p>
<h4 id="the-category-page">The Category page</h4>
<p>Right, &ldquo;terms&rdquo; in Wordpress. Are you using tags or categories? Or did you create your own taxonomy? What&rsquo;s with all the complexity when I just want a simple way to sort and organize my blog posts? Here, I used another self-made shortcode, <code>[show_current_category]</code>, that is a wrapper around <code>[display-posts]</code> to apply the category filter scraped from the request URL (usually something like <code>/category/blabla</code>):</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-php" data-lang="php"><span style="color:#434f54">$show_current_category_in</span> <span style="color:#728e00">=</span> <span style="color:#728e00">FALSE</span>;
<span style="color:#728e00">function</span> <span style="color:#d35400">show_current_category_shortcode</span>() {
<span style="color:#728e00">global</span> <span style="color:#434f54">$show_current_category_in</span>;
<span style="color:#728e00">if</span>(<span style="color:#434f54">$show_current_category_in</span> <span style="color:#728e00">==</span> <span style="color:#728e00">TRUE</span>) <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#39;&#39;</span>;
<span style="color:#434f54">$show_current_category_in</span> <span style="color:#728e00">=</span> <span style="color:#728e00">TRUE</span>;
<span style="color:#434f54">$cat</span> <span style="color:#728e00">=</span> <span style="color:#728e00">str_replace</span>(<span style="color:#7f8c8d">&#39;/&#39;</span>, <span style="color:#7f8c8d">&#39;&#39;</span>, <span style="color:#728e00">str_replace</span>(<span style="color:#7f8c8d">&#39;category&#39;</span>, <span style="color:#7f8c8d">&#39;&#39;</span>, <span style="color:#434f54">$_SERVER</span>[<span style="color:#7f8c8d">&#39;REQUEST_URI&#39;</span>]));
<span style="color:#728e00">ob_start</span>();
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;&lt;div class=&#39;brz-rich-text&#39;&gt;&lt;h2 style=&#39;font-family: \&#39;Playfair Display\&#39;, serif&#39;&gt;Categorie: </span><span style="color:#7f8c8d">$cat</span><span style="color:#7f8c8d">&lt;/h2&gt;&lt;/div&gt;&lt;hr/&gt;&#34;</span>;
<span style="color:#728e00">echo</span> <span style="color:#728e00">do_shortcode</span>(<span style="color:#7f8c8d">&#39;[display-posts category=&#34;&#39;</span> <span style="color:#728e00">.</span> <span style="color:#434f54">$cat</span> <span style="color:#728e00">.</span> <span style="color:#7f8c8d">&#39;&#34; posts_per_page=&#34;100&#34; image_size=&#34;thumbnail&#34; include_excerpt=&#34;true&#34; excerpt_length=&#34;30&#34; include_date=&#34;true&#34; category_display=&#34;true&#34; category_label=&#34;&#34; include_excerpt_dash=&#34;false&#34; image_size=&#34;medium&#34; date_format=&#34;d/m/Y&#34;]&#39;</span>);
<span style="color:#434f54">$html</span> <span style="color:#728e00">=</span> <span style="color:#728e00">ob_get_contents</span>();
<span style="color:#728e00">ob_end_clean</span>();
<span style="color:#728e00">return</span> <span style="color:#434f54">$html</span>;
}
</code></pre></div><p>I&rsquo;m ashamed to even post this on the internet. One of the finest hacks I&rsquo;ve ever written, I think. The ugly boolean variable is needed because when a Brizy template gets included as part of the results, it triggers the Wordpress function <code>get_the_excerpt()</code> from <code>[display-posts]</code>. And the excerpt of this category template page includes the show current category shortcode - back to square one. I&rsquo;m sure there are better ways to do this, but I lost my patience (and temper) trying to debug this mess, pasting <code>$e = new \Exception; var_dump($e-&gt;getTraceAsString());</code> in random places.</p>
<h3 id="the-wordpress-mess">The Wordpress mess</h3>
<p>I&rsquo;m slowly but surely starting to detest the Wordpress mess we&rsquo;ve made. A few other things that bother me:</p>
<ol>
<li>Sass transpilation? The wordpress admin page offers a nice and easy way to edit inline source files of the themes, but they are CSS-only.</li>
<li>Same problem with ES6. I had to transpile the big <code>preview.js</code> JS file from Brizy myself because somehow inline SVGs did not get replaced in Safari. Turns out there was actually a JS syntax error!</li>
<li>Plugin hell. Which plugin to use for SEO or image optimization? Oh, this one seems cool. Nope, not modified in a year. Oh and this one? Nope, freemium shit. What about&hellip; Hours later: fuck it, pick a random one.</li>
<li>The theme child/parent thing is a mess. In the end, I copied the <code>twentytwenty</code> dir over to do some heavy lifting - being well aware of things possibly breaking in future Wordpress versions.</li>
</ol>
<h3 id="the-brizy-mess">The Brizy mess</h3>
<p>Brizy allows you to save &ldquo;blocks&rdquo; as global blocks so they can be reused on different pages. That&rsquo;s very handy, and my wife easily creates other pages with the same header and footer using a swift drag-and-drop move. However, since the logo is included in the header, and we accidentally uploaded the wrong one, I swapped the image out on the server. Guess what, on most other pages, the wrong version was still there:</p>
<pre><code>user@vps:/var/www/kristienwp/wp-content/uploads/brizy$ find . -name 'testlogokristien.png' | wc -l
389
</code></pre><p>Wait, what?</p>
<p>Yup:</p>
<pre><code>./455/assets/images/iW=652&amp;iH=any/testlogokristien.png
./455/assets/images/iW=151&amp;iH=69&amp;oX=1&amp;oY=0&amp;cW=150&amp;cH=69/testlogokristien.png
./455/assets/images/iW=326&amp;iH=any/testlogokristien.png
./455/assets/images/iW=328&amp;iH=any/testlogokristien.png
./455/assets/images/iW=300&amp;iH=136&amp;oX=0&amp;oY=0&amp;cW=300&amp;cH=136/testlogokristien.png
./3682/assets/images/iW=150&amp;iH=68&amp;oX=0&amp;oY=0&amp;cW=150&amp;cH=68/testlogokristien.png
./3682/assets/images/iW=106&amp;iH=48&amp;oX=0&amp;oY=13&amp;cW=106&amp;cH=23/testlogokristien.png
./3682/assets/images/iW=145&amp;iH=any/testlogokristien.png
./3682/assets/images/iW=246&amp;iH=112&amp;oX=0&amp;oY=0&amp;cW=246&amp;cH=112/testlogokristien.png
./3682/assets/images/iW=212&amp;iH=96&amp;oX=0&amp;oY=26&amp;cW=212&amp;cH=46/testlogokristien.png
./3682/assets/images/iW=310&amp;iH=142&amp;oX=0&amp;oY=0&amp;cW=310&amp;cH=142/testlogokristien.png
</code></pre><p>Brizy duplicates images from global bocks for each page, and for each page, Brizy duplicates images for each (mobile) device used in <code>srcset</code> attributes of <code>img</code> tags. <code>26</code> images for one page ID.</p>
<p>There goes my <a href="/post/vps">nginx caching strategy</a>. What a mess. Should I write a bash script to create symlinks? That does not change anything for the clientside webbrowser. What a mess.</p>
<h3 id="so-trash-brizy-and-use-something-else">So, trash Brizy and use something else?</h3>
<p>Perhaps. But now that we invested a couple of weeks in this Wordpress + Brizy + custom hacks combination, my wife is content. She&rsquo;s even thinking about using the same setup to port one of her websites from Webnode, a paid and hosted service. It&rsquo;s intuitive to use and it works - for the most part. The shortcodes should not change often, and the blog detail and category brizy templates are not that difficult to maintain if you ignore the errors in the editor.</p>
<p>Oh, and don&rsquo;t bother paying for the coupled &ldquo;Optimize Images&rdquo; <a href="https://shortpixel.com/pricing-one-time">shortpixel.com</a> plugin thing - simply execute <code>find . -name &quot;*.jpg&quot; -exec convert {} -sampling-factor 4:2:0 -strip -quality 85 -interlace JPEG -colorspace sRGB {} \;</code>. With complements of Google&rsquo;s <a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/image-optimization">Image Optimization Tips</a>.</p>
<p>As long as you don&rsquo;t try to peek behind the scenes and into the source code, all is well&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 26 May 2020.
</p>
]]>
</description>
</item>
<item>
<title>Hugo Extended: More static site processing power!</title>
<link>https://brainbaking.com/post/2020/05/hugo-extended/</link>
<comments>https://brainbaking.com/post/2020/05/hugo-extended/#commento</comments>
<pubDate>Fri, 15 May 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/05/hugo-extended/</guid>
<category domain="https://brainbaking.com/tags/hugo">hugo</category>
<category domain="https://brainbaking.com/tags/babel">babel</category>
<category domain="https://brainbaking.com/tags/sass">sass</category>
<description>
<![CDATA[
<p>This week, Hugo <code>0.7</code> has been released. And while it&rsquo;s a minor release, it&rsquo;s nonetheless something to be excited about: finally a <code>babel</code> pipeline is available. That means transpiling new ES6+ JS code to older compatible versions is now possible as part of your Hugo buildchain! I took the opportunity to redesign one of my websites, <a href="https://redzuurdesem.be">redzuurdesem.be</a>, and leveraged a few new (at least to me) Hugo features that make designing and developing a (static) website a lot more pleasant. I would like to give an overview of things I&rsquo;ve successfully used - and hopefully will make it into Brain Baking someday!</p>
<h3 id="sass">Sass</h3>
<p>The <a href="https://sass-lang.com/guide">Sass language</a> compiles to CSS and makes building complex websites much easier. That is, a few important tricks make the syntax of Sass more compact and easier to maintain compared to regular CSS. The problem is: browsers parse CSS, not Sass. In typical JS projects, you compile Sass as part of the buildchain. Using <strong>Hugo Pipes</strong> it is ridiculously easy to process these files (<a href="https://gohugo.io/hugo-pipes/scss-sass/">explained here</a>):</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">{{- $options := (dict &#34;targetPath&#34; &#34;css/styles.css&#34; &#34;outputStyle&#34; &#34;compressed&#34; &#34;enableSourceMap&#34; &#34;true&#34;) -}}
{{- $styles := resources.Get &#34;sass/main.sass&#34; | resources.ExecuteAsTemplate &#34;main.sass&#34; . | resources.ToCSS $options | resources.Fingerprint &#34;sha512&#34; }}
&lt;<span style="color:#434f54">link</span> <span style="color:#434f54">rel </span><span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#39;stylesheet&#39;</span> <span style="color:#434f54">href </span><span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#39;{{ $styles.Permalink }}&#39;</span> <span style="color:#434f54">integrity </span><span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#39;{{ $styles.Data.Integrity }}&#39;</span>&gt;
</code></pre></div><p>Done! This does require the &lsquo;Hugo Extended&rsquo; binary release instead of the regular release builds, which include these special build pipeline systems. The above even minifies the CSS (<code>compressed</code>).</p>
<h3 id="transpiling-using-babel">Transpiling using Babel</h3>
<p>I&rsquo;m sure you all see this coming: the transpile step is also a Hugo pipe. It does require a bit more work compared to Sass, though, but the actual usage, including minification, is just as easy:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">{{- $scripts = resources.Get $mainScriptPath | resources.ExecuteAsTemplate $mainScriptPath . | babel | resources.Minify | resources.Fingerprint &#34;sha512&#34; }}
&lt;<span style="color:#434f54">script</span> <span style="color:#434f54">src </span><span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#39;{{ $scripts.Permalink }}&#39;</span>&gt;&lt;/<span style="color:#434f54">script</span>&gt;
</code></pre></div><p>The magic pipe keyword here is <code>babel</code>. However, without installing the necessary node packages, it will not work. You will need the following <code>devDependencies</code> in your <code>package.json</code> file:</p>
<ul>
<li><code>&quot;@babel/cli&quot;: &quot;^7.8.4&quot;</code></li>
<li><code>&quot;@babel/core&quot;: &quot;^7.9.6&quot;</code></li>
<li><code>&quot;@babel/preset-env&quot;: &quot;^7.9.6&quot;</code></li>
</ul>
<p>Without a preset, there is nothing to do, but without the core and the cli components, the babel command will simply fail. I tried globally installing these, but that did not seem to work.</p>
<p>To facilitate easy local debugging in different browsers, I skipped the babel and minify steps using a Hugo directive:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">{{- if (ne hugo.Environment &#34;development&#34;) }}
{{- end }}
</code></pre></div><p>Be warned though! The babel step failed or produced some kind of syntax problem, and I did not see this locally. It was only when it was deployed in production that I found out something was broken. Whoops.</p>
<h3 id="search-functionality-in-a-static-website">Search functionality in a static website</h3>
<p>There are a couple of <a href="https://gohugo.io/tools/search/">search functionality options</a> that gohugo.io lists, of which <a href="lunrjs.com">lunrjs</a> is a minimalistic JS package that indexes and searches. The problem with that is that we need to provide an index JSON file where all our Markdown posts are gathered, including things you want to be searched such as tags.</p>
<p>Thanks to <a href="https://codewithhugo.com/hugo-lunrjs-search-index/">this blog post</a> and the accompanying <a href="https://gist.github.com/HugoDF/aac2e529f79cf90d2050d7183571684b">GitHub Gist</a>, things became rather easy. In essence, we want to execute the following steps:</p>
<ol>
<li>Build an index file that lunrjs can gobble up.</li>
<li>Let lunrjs do the searching.</li>
<li>Display search results with links to relevant articles.</li>
</ol>
<p>Step one is done by parsing all Markdown files and adding everything you want to be searchable - see Gist file. Step two is also not too difficult:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">fetch</span>(<span style="color:#7f8c8d">&#39;/js/indexfile.json&#39;</span>).<span style="color:#728e00">then</span>((<span style="color:#728e00">res</span>) =&gt; {
<span style="color:#728e00">return</span> <span style="color:#728e00">res</span>.<span style="color:#728e00">json</span>();
}).<span style="color:#728e00">then</span>((<span style="color:#728e00">data</span>) =&gt; {
<span style="color:#00979d">const</span> <span style="color:#728e00">index</span> <span style="color:#728e00">=</span> <span style="color:#728e00">lunr</span>.<span style="color:#728e00">Index</span>.<span style="color:#728e00">load</span>(<span style="color:#728e00">data</span>);
<span style="color:#00979d">const</span> <span style="color:#728e00">matches</span> <span style="color:#728e00">=</span> <span style="color:#728e00">index</span>.<span style="color:#728e00">search</span>(<span style="color:#728e00">searchString</span>);
});
</code></pre></div><p>The trouble is that our <code>matches</code> variable only contains a <code>ref</code> property to link back to the document itself. Lunrjs somehow does not return the indexed metadata&hellip; So you have to map the matches array to your indexed articles. I did that in Hugo:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#434f54">script</span> <span style="color:#434f54">src</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;https://unpkg.com/lunr/lunr.js&#34;</span>&gt;&lt;/<span style="color:#434f54">script</span>&gt;
{{ $p := slice }}
{{ range (where .Site.RegularPages &#34;Section&#34; &#34;!=&#34; &#34;&#34;) }}
{{ $post := dict &#34;link&#34; .RelPermalink &#34;title&#34; .Title &#34;content&#34; (substr .Plain 0 200) -}}
{{ $p = $p | append $post -}}
{{ end }}
&lt;<span style="color:#434f54">script</span>&gt;
<span style="color:#728e00">window</span>.<span style="color:#728e00">searchposts</span> <span style="color:#728e00">=</span> <span style="color:#728e00">JSON</span>.<span style="color:#728e00">parse</span>(
{{ <span style="color:#728e00">$p</span> <span style="color:#728e00">|</span> <span style="color:#728e00">jsonify</span> }}
);
&lt;/<span style="color:#434f54">script</span>&gt;
</code></pre></div><p>Now you cam <code>map()</code> the indexed <code>ref</code> property on <code>searchposts.link</code>. I have not yet found a better way of doing this. It seems a bit redundant to have Hugo generate another &lsquo;index&rsquo; - these can get out of sync, resulting in search results not being displayed.</p>
<p>You can try out the result <a href="https://redzuurdesem.be/zoeken/">here</a>. It is nothing fancy, and although you can build a dynamic search-as-you-type searchbox, I simply used a HTTP form:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#434f54">form</span> <span style="color:#434f54">method</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;GET&#34;</span> <span style="color:#434f54">action</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;&#34;</span>&gt;
&lt;<span style="color:#434f54">input</span> <span style="color:#434f54">id</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;searchtxt&#34;</span> <span style="color:#434f54">placeholder</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;search!&#34;</span> <span style="color:#434f54">name</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;q&#34;</span> <span style="color:#434f54">type</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;text&#34;</span> /&gt;
&lt;<span style="color:#434f54">button</span> <span style="color:#434f54">type</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;submit&#34;</span> <span style="color:#434f54">class</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;button&#34;</span>&gt;Search&lt;/<span style="color:#434f54">button</span>&gt;
&lt;<span style="color:#434f54">a</span> <span style="color:#434f54">href</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;/search&#34;</span>&gt;Empty&lt;/<span style="color:#434f54">a</span>&gt;
&lt;/<span style="color:#434f54">form</span>&gt;
</code></pre></div><p>The <code>GET</code> is on purpose: the URL can be bookmarked, and the query string can be plucked from the URL in JS using:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#00979d">const</span> <span style="color:#728e00">query</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">URLSearchParams</span>(<span style="color:#728e00">window</span>.<span style="color:#728e00">location</span>.<span style="color:#728e00">search</span>);
<span style="color:#00979d">const</span> <span style="color:#728e00">searchString</span> <span style="color:#728e00">=</span> <span style="color:#728e00">query</span>.<span style="color:#728e00">get</span>(<span style="color:#7f8c8d">&#39;q&#39;</span>) <span style="color:#728e00">||</span> <span style="color:#7f8c8d">&#34;&#34;</span>;
</code></pre></div><p>To conclude, when building your site using Hugo, you should not forget to run the index creation script. It might be a good idea to link Hugo to node in the <code>packages.json</code> <code>scripts</code> properties: <code>npm run index &amp;&amp; npm run build</code>.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 15 May 2020.
</p>
]]>
</description>
</item>
<item>
<title>Using Pandoc to publish a book</title>
<link>https://brainbaking.com/post/2020/05/using-pandoc/</link>
<comments>https://brainbaking.com/post/2020/05/using-pandoc/#commento</comments>
<pubDate>Fri, 01 May 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/05/using-pandoc/</guid>
<category domain="https://brainbaking.com/tags/publishing">publishing</category>
<category domain="https://brainbaking.com/tags/book">book</category>
<category domain="https://brainbaking.com/tags/pandoc">pandoc</category>
<category domain="https://brainbaking.com/tags/markdown">markdown</category>
<category domain="https://brainbaking.com/tags/latex">latex</category>
<description>
<![CDATA[
<p>So, <a href="https://redzuurdesem.be/het-boek/">I wrote a book</a> about bread baking.</p>
<p>And it did not happen overnight. I started working on the idea in 2017, but was using Google Docs at that time, which frustrated more than it was a joy to work with. GDocs and Word-like processors harass me too much with menu bars, toolbars, collaboration tools, backup capabilities, and so forth - while all I want to do is simply write. In 2018, I rebooted my writing attempt and resorted to my favorite text-editor: Sublime Text.</p>
<p>To focus on the writing itself, and not the layout and whatnot, I decided to write in Markdown. In a non-fiction book, such as the one I was planning to write, it is important not to overburden readers with flashy layouting - so Markdown&rsquo;s minimalistic approach helped a lot here: underscores to <em>emphasize</em> things is mostly enough.</p>
<p><figure>
<a href="../makingof-schrijven.png" class="lbox">
<img loading="lazy" src="../makingof-schrijven.png" alt="subl" >
</a>
</figure>
</p>
<h3 id="the-toolchain">The toolchain</h3>
<p>My aim was to publish a physical version of a book, similar to my favorite opinionated books about cooking and baking such as David Pollan&rsquo;s and Michael Booth&rsquo;s work. My publisher expects a <code>.pdf</code> file, so naturally compiling from simple text (<code>.md</code>) to <code>.pdf</code> is in order - and something Pandoc is really good at. I wanted to minimize the amount of LaTex I had to write myself, but for layouting purposes, a big preamble file would probably be unavoidable.</p>
<p>The setup:</p>
<script defer src="/mermaid/mermaid.min.js">
mermaid.initialize({
startOnLoad: true,
flowchart: {
useMaxWidth: true
}
});
</script>
<div class="mermaid" align="center" >
graph LR;
md[Plaintext, md =]
tex[LaTeX, tex =]
pdf[Postscript, pdf =]
md --> tex
tex --> pdf
</div>
<p>For LaTeX compilation, <code>xetex</code> instead of <code>pdflatex</code> was employed, as my experience taught me the first one is more flexible when it comes to typesetting and such. My Makefile jumpstart command looks like this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-make" data-lang="make"> pandoc -f markdown <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> -V <span style="color:#434f54">documentclass</span><span style="color:#728e00">=</span>memoir -V <span style="color:#434f54">lang</span><span style="color:#728e00">=</span>nl-BE -M lang:nl <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> --include-in-header<span style="color:#728e00">=</span>preamble.tex <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> --include-before-body<span style="color:#728e00">=</span>coversheet.tex <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> --include-after-body<span style="color:#728e00">=</span>afterbody.tex <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> --pdf-engine<span style="color:#728e00">=</span>xelatex <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> --filter pandoc-citeproc <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> --filter filters/fancybreak.py <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> --top-level-division<span style="color:#728e00">=</span>part <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> --metadata-file<span style="color:#728e00">=</span>metadata.yml <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> --highlight-style<span style="color:#728e00">=</span>haddock <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> -t latex+smart &gt; book.tex <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> chap1.pd.md chap2.pd.md chap3.pd.md ... <span style="color:#7f8c8d">\
</span><span style="color:#7f8c8d"></span> xelatex book.tex
</code></pre></div><p>As you can see from the above command, <code>memoir</code> was used, and the 500+ pages manual was thoroughly read to learn about obscure layouting commands that eventually allowed me to position everything exactly as I wanted it to be. However, it took a week of trail and error before reaching that point of satisfaction&hellip;</p>
<p>Memoir is an extremely flexible and complete package: it comes with chapter styles, header and footer styles, special stuff for your table/figure/&hellip; lists, and so forth. Most packages you&rsquo;d use in conjunction with the <code>article</code> document class become obsolete - as long as you adhere to memoir&rsquo;s rules!</p>
<h3 id="the-cover-sheet-pages">The &lsquo;cover sheet&rsquo; pages</h3>
<p>The first three pages of the book are the cover pages, and they are set:</p>
<ol>
<li>Title only (plain)</li>
<li>Empty page</li>
<li>Title, author, and publisher (fancier)</li>
</ol>
<p>An optional fourth page, which I included, contains the copyright, edition information, and so forth. Everything is part of <code>\frontmatter</code>, and written in LaTex itself. I got inspired by some examples provided by the memoir fellows:</p>
<p><figure>
<a href="../book-coversheet.png" class="lbox">
<img loading="lazy" src="../book-coversheet.png" alt="subl" >
</a>
</figure>
</p>
<p>The style is called &lsquo;Gentle Madness&rsquo;. I had no intention of pouring hours into making my own original version of something that was already good enough: it&rsquo;s part of the cover pages&hellip; You know, the things you flip through, in search for the actual content?</p>
<h3 id="chapter-style-and-font">Chapter style and font</h3>
<p>As said before, memoir comes with &lsquo;batteries included&rsquo; - and that is definitely the case for chapter styles. I opted for a minimalistic chapter number and a title - that&rsquo;s it:</p>
<p><figure>
<a href="../book-chapter.png" class="lbox">
<img loading="lazy" src="../book-chapter.png" alt="subl" >
</a>
</figure>
</p>
<p>The tex needed to do that:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\makeatletter</span>
<span style="color:#728e00">\providecommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\subtitle</span><span style="color:#728e00">}</span>[1]<span style="color:#728e00">{</span>
<span style="color:#728e00">\apptocmd</span><span style="color:#728e00">{</span><span style="color:#728e00">\@</span>title<span style="color:#728e00">}{</span><span style="color:#728e00">\par</span> <span style="color:#728e00">{</span><span style="color:#728e00">\large</span> #1 <span style="color:#728e00">\par</span><span style="color:#728e00">}}{}{}</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">\makeatother</span>
<span style="color:#728e00">\chapterstyle</span><span style="color:#728e00">{</span>dash<span style="color:#728e00">}</span><span style="color:#728e00">\renewcommand*</span><span style="color:#728e00">{</span><span style="color:#728e00">\chaptitlefont</span><span style="color:#728e00">}{</span><span style="color:#728e00">\normalfont\itshape\LARGE</span><span style="color:#728e00">}</span>
<span style="color:#728e00">\setlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\beforechapskip</span><span style="color:#728e00">}{</span>2<span style="color:#728e00">\onelineskip</span><span style="color:#728e00">}</span>
<span style="color:#728e00">\setsecheadstyle</span><span style="color:#728e00">{</span><span style="color:#728e00">\normalfont\Large\raggedright</span><span style="color:#728e00">}</span>
</code></pre></div><p>The quote below the chapter title is a Markdown quote, using simply &lsquo;&gt;&rsquo; to start the sentence. It did bug me that I had to write a bit of latex to align it properly, though. I&rsquo;m sure this could be fixed with another Python filter, but by then most of my chapter files were already created. The above screenshot is the result of the following piece of Markdown:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-md" data-lang="md">## Het begint allemaal met een kabouter
\label{kabouter}
<span style="color:#728e00">
</span><span style="color:#728e00">&gt; </span>&#39;_Eat (good) food. Mostly plants. Not too much._&#39; - \mbox{Michael} Pollan, In Defense of Food
### Dagelijks brood met een druk op de knop
\begin{flushright}
Augustus 2010
\end{flushright}
&#39;Het kaboutertje is weer bezig&#39; glimlachte mijn vrouw, toen ze opkeek van haar boek. Dat leek haar wel een gepaste manier om het plotse achtergrondlawaai te identificeren. Deze mini-mens wordt verkocht inclusief huisje: een
</code></pre></div><p>I tried to separate content from latex as much as possible, but failed when it came to labeling, quote alignment, and some mbox instances. Now that I look back, these can be left out with extra <code>\hyphenation{}</code> rules in the preamble.</p>
<h3 id="footnotes-footers-and-citing-work">Footnotes, footers, and citing work</h3>
<p>Inspired by other books, I really wanted to go for extensive use of footnotes throughout the book - and not have a silly numbering style that will mess with my idea of superscript numbering to cite other work. That said, footnote symbols usually <strong>do not</strong> reset each page, but each chapter, resulting in a lot of compile errors because I reached the end of the line fairly quickly.</p>
<p>Enter the <code>perpage</code> package, where footnote numbering can be tampered with, without clashing with the memoir class:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\usepackage</span><span style="color:#728e00">{</span>perpage<span style="color:#728e00">}</span>
<span style="color:#728e00">\MakePerPage</span><span style="color:#728e00">{</span>footnote<span style="color:#728e00">}</span>
<span style="color:#728e00">\renewcommand*</span><span style="color:#728e00">{</span><span style="color:#728e00">\thefootnote</span><span style="color:#728e00">}{</span><span style="color:#728e00">\fnsymbol</span><span style="color:#728e00">{</span>footnote<span style="color:#728e00">}}</span>
</code></pre></div><p>The end result looks like this:</p>
<p><figure>
<a href="../book-footnotes.png" class="lbox">
<img loading="lazy" src="../book-footnotes.png" alt="footnotes" >
</a>
</figure>
</p>
<p>For the header and footer, I wanted to maximize the available space on a page. That means only one of both, so no header. It is important to distinguish footer text from chapter text, so I opted to reduce the harshness of the text by using gray and another font type. It can be configured as a separate chapter style, that should distinctively <strong>not</strong> be applied to &lsquo;part x&rsquo; pages:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\makepagestyle</span><span style="color:#728e00">{</span>desem<span style="color:#728e00">}</span>
<span style="color:#728e00">\createmark</span><span style="color:#728e00">{</span>chapter<span style="color:#728e00">}{</span>left<span style="color:#728e00">}{</span>nonumber<span style="color:#728e00">}{}{}</span> <span style="color:#95a5a6">% remove &#39;chapter x:&#39; from \leftmark
</span><span style="color:#95a5a6"></span><span style="color:#728e00">\makeevenfoot</span><span style="color:#728e00">{</span>desem<span style="color:#728e00">}{</span><span style="color:#728e00">\textsf</span><span style="color:#728e00">{</span><span style="color:#728e00">\textcolor</span><span style="color:#728e00">{</span>lightgray<span style="color:#728e00">}{</span><span style="color:#728e00">\footnotesize</span> <span style="color:#728e00">\textbf</span><span style="color:#728e00">{</span><span style="color:#728e00">\thepage</span><span style="color:#728e00">}</span> <span style="color:#728e00">\:</span> | <span style="color:#728e00">\:</span> RED ZUURDESEM<span style="color:#728e00">}}}{}{}</span>
<span style="color:#728e00">\makeoddfoot</span><span style="color:#728e00">{</span>desem<span style="color:#728e00">}{}{}{</span><span style="color:#728e00">\textsf</span><span style="color:#728e00">{</span><span style="color:#728e00">\textcolor</span><span style="color:#728e00">{</span>lightgray<span style="color:#728e00">}{</span><span style="color:#728e00">\footnotesize</span> <span style="color:#728e00">\leftmark</span> <span style="color:#728e00">\:</span> | <span style="color:#728e00">\:</span> <span style="color:#728e00">\textbf</span><span style="color:#728e00">{</span><span style="color:#728e00">\thepage</span><span style="color:#728e00">}}}}</span>
<span style="color:#728e00">\copypagestyle</span><span style="color:#728e00">{</span>plain<span style="color:#728e00">}{</span>desem<span style="color:#728e00">}</span>
<span style="color:#728e00">\copypagestyle</span><span style="color:#728e00">{</span>part<span style="color:#728e00">}{</span>empty<span style="color:#728e00">}</span>
<span style="color:#728e00">\AtBeginDocument</span><span style="color:#728e00">{</span><span style="color:#728e00">\addtocontents</span><span style="color:#728e00">{</span>toc<span style="color:#728e00">}{</span><span style="color:#728e00">\protect\thispagestyle</span><span style="color:#728e00">{</span>empty<span style="color:#728e00">}}}</span>
</code></pre></div><p>For citing work, the rough draft employed a dusty academic way (the default way) of doing that: author and year between brackets: &lsquo;in research blabla bla (Surname, 2019).&rsquo; It gave me a headache: it does <em>not</em> read fluently at all. the &lsquo;[10]&rsquo; thing at the end of a sentence was not that great either. It is non-fiction, but it should not be a boring piece of academic work! In the end, I opted for superscript with a reduced font size:</p>
<p><figure>
<a href="../book-cite.png" class="lbox">
<img loading="lazy" src="../book-cite.png" alt="cite" >
</a>
</figure>
</p>
<p>I found that citation style in <a href="https://www.zotero.org/styles">zotero.org/styles</a> and <a href="https://citationstyles.org/authors/">https://citationstyles.org/authors/</a>, it&rsquo;s called <code>the-open-university-numeric-superscript.csl</code> and added as a parameter in the metadata YML file for pandoc to parse. As you can see from the pandoc command, the <code>pandoc-citeproc</code> filter was used - it worked well enough and meant not manually fiddling with bibliography tools.</p>
<h3 id="figures-and-lists">Figures and lists</h3>
<p>The problem with using LaTeX and the memoir style is that most of the default settings feel a bit too rigid - too academic. I tried shaving off that word &lsquo;academic&rsquo; as much as possible. For lists, this meant reducing it&rsquo;s complexity to simply a pointer to the page instead of numbering them individually:</p>
<p><figure>
<a href="../book-figures.png" class="lbox">
<img loading="lazy" src="../book-figures.png" alt="figure" >
</a>
</figure>
</p>
<p>After a lot of stackoverflow hints, I managed to nail it down to:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\makeatletter</span>
<span style="color:#728e00">\renewcommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\cftfigurepresnum</span><span style="color:#728e00">}{</span><span style="color:#728e00">\begin</span><span style="color:#728e00">{</span>lrbox<span style="color:#728e00">}{</span><span style="color:#728e00">\@</span>tempboxa<span style="color:#728e00">}}</span>
<span style="color:#728e00">\renewcommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\cftfigureaftersnum</span><span style="color:#728e00">}{</span><span style="color:#728e00">\end</span><span style="color:#728e00">{</span>lrbox<span style="color:#728e00">}}</span>
<span style="color:#728e00">\renewcommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\cfttablepresnum</span><span style="color:#728e00">}{</span><span style="color:#728e00">\begin</span><span style="color:#728e00">{</span>lrbox<span style="color:#728e00">}{</span><span style="color:#728e00">\@</span>tempboxa<span style="color:#728e00">}}</span>
<span style="color:#728e00">\renewcommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\cfttableaftersnum</span><span style="color:#728e00">}{</span><span style="color:#728e00">\end</span><span style="color:#728e00">{</span>lrbox<span style="color:#728e00">}}</span>
<span style="color:#728e00">\makeatother</span>
<span style="color:#728e00">\setlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\cftfigurenumwidth</span><span style="color:#728e00">}{</span>0pt<span style="color:#728e00">}</span>
<span style="color:#728e00">\setlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\cfttablenumwidth</span><span style="color:#728e00">}{</span>0pt<span style="color:#728e00">}</span>
</code></pre></div><p>Of course, for figures themselves, more work was needed: I was not particularly keen on having something like &lsquo;Figure x.y: caption&rsquo;. Let&rsquo;s get rid of that figure caption (thanks to <a href="http://www.peteryu.ca/tutorials/publishing/latex_captions">http://www.peteryu.ca/tutorials/publishing/latex_captions</a>):</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\usepackage</span><span style="color:#434f54">[skip=4pt,font=small]</span><span style="color:#728e00">{</span>caption<span style="color:#728e00">}</span>
<span style="color:#728e00">\captionsetup</span><span style="color:#434f54">[figure]</span><span style="color:#728e00">{</span>labelformat=empty, labelsep=colon, labelfont=bf, textfont=<span style="color:#728e00">{</span>it<span style="color:#728e00">}}</span>
<span style="color:#728e00">\captionsetup</span><span style="color:#434f54">[table]</span><span style="color:#728e00">{</span>labelformat=empty, labelsep=colon, labelfont=bf, textfont=<span style="color:#728e00">{</span>it<span style="color:#728e00">}}</span>
<span style="color:#728e00">\renewcommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\thefigure</span><span style="color:#728e00">}{</span><span style="color:#728e00">\thechapter</span>.<span style="color:#728e00">\Alph</span><span style="color:#728e00">{</span>figure<span style="color:#728e00">}}</span>
<span style="color:#728e00">\renewcommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\thetable</span><span style="color:#728e00">}{</span><span style="color:#728e00">\thechapter</span>.<span style="color:#728e00">\Alph</span><span style="color:#728e00">{</span>figure<span style="color:#728e00">}}</span>
</code></pre></div><p>For &lsquo;default&rsquo; inline figures, that works. However, some figures I wanted spread out onto the page extending beyond the typical type block width. A custom LaTeX command, that takes into account different odd and even page widths, called <code>\centerimg</code> did the trick:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\usepackage</span><span style="color:#728e00">{</span>wrapfig<span style="color:#728e00">}</span> <span style="color:#95a5a6">% inline l/r
</span><span style="color:#95a5a6"></span><span style="color:#728e00">\usepackage</span><span style="color:#728e00">{</span>calc<span style="color:#728e00">}</span> <span style="color:#95a5a6">% for adjustimg cmd calculations
</span><span style="color:#95a5a6"></span><span style="color:#728e00">\usepackage</span><span style="color:#728e00">{</span>changepage<span style="color:#728e00">}</span> <span style="color:#95a5a6">% full-page
</span><span style="color:#95a5a6"></span><span style="color:#728e00">\newcommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\adjustimg</span><span style="color:#728e00">}{</span><span style="color:#95a5a6">% Horizontal adjustment of image
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">\checkoddpage</span><span style="color:#95a5a6">%
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">\ifoddpage\hspace*</span><span style="color:#728e00">{</span><span style="color:#728e00">\dimexpr\evensidemargin</span>-<span style="color:#728e00">\oddsidemargin</span><span style="color:#728e00">}</span><span style="color:#728e00">\else\hspace*</span><span style="color:#728e00">{</span>-<span style="color:#728e00">\dimexpr\evensidemargin</span>-<span style="color:#728e00">\oddsidemargin</span><span style="color:#728e00">}</span><span style="color:#728e00">\fi</span><span style="color:#95a5a6">%
</span><span style="color:#95a5a6"></span><span style="color:#728e00">}</span>
<span style="color:#728e00">\newcommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\centerimg</span><span style="color:#728e00">}</span>[2][width=<span style="color:#728e00">\textwidth</span>]<span style="color:#728e00">{</span><span style="color:#95a5a6">% Center an image
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">\makebox</span><span style="color:#434f54">[\textwidth]</span><span style="color:#728e00">{</span><span style="color:#728e00">\adjustimg\includegraphics</span><span style="color:#434f54">[#1]</span><span style="color:#728e00">{</span>#2<span style="color:#728e00">}}</span><span style="color:#95a5a6">%
</span><span style="color:#95a5a6"></span><span style="color:#728e00">}</span>
</code></pre></div><p>The end result:</p>
<p><figure>
<a href="../book-image.png" class="lbox">
<img loading="lazy" src="../book-image.png" alt="img" >
</a>
</figure>
</p>
<p>Sadly, to make use of the new LaTeX command, I had to interleave it with the rest of the text in my Markdown chapter file. The above screenshot is the result of this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-md" data-lang="md">deeld als voorbereiding op de bulkrijs. Een professionele bakker kan zich de langdurige bezetting van een machine meestal niet veroorloven.
\begin{figure}
\mbox{} \par
\noindent\centerimg[width=\paperwidth]{img/bw/deeg.jpg}
\caption[Gerezen brooddeeg op een linnen doek.]{Stilte! Hier slaapt - euh, rijst - brood.}
\end{figure}
Het is een mythe dat bakken exacte hoeveelheden vereist, ook al is patisserie hier uiteraard gevoeliger aan dan brood.
</code></pre></div><p>I never found a way around this - even for inline figures - as the default image include for Markdown does not give me the opportunity to provide two captions: one for the image, and one shorter version for the text in the table of figures.</p>
<h3 id="page-layout">Page Layout</h3>
<p>This is where most of the swearing happened. My book format is <code>135x215mm</code> - and getting that right was a bit of a pain, especially since my publisher required a few millimeters of spacing as the printing and cutting process of pages needs that. I ended up increasing the stock size to take this extra spacing into account (3 and 6mm, respectively):</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\setstocksize</span><span style="color:#728e00">{</span>221mm<span style="color:#728e00">}{</span>138mm<span style="color:#728e00">}</span>
<span style="color:#728e00">\settrimmedsize</span><span style="color:#728e00">{</span>215mm<span style="color:#728e00">}{</span>135mm<span style="color:#728e00">}{</span>*<span style="color:#728e00">}</span>
<span style="color:#728e00">\settrims</span><span style="color:#728e00">{</span>0mm<span style="color:#728e00">}{</span>0mm<span style="color:#728e00">}</span>
<span style="color:#728e00">\settypeblocksize</span><span style="color:#728e00">{</span>180mm<span style="color:#728e00">}{</span>100mm<span style="color:#728e00">}{</span>*<span style="color:#728e00">}</span>
<span style="color:#728e00">\setlrmargins</span><span style="color:#728e00">{</span>*<span style="color:#728e00">}{</span>17mm<span style="color:#728e00">}{</span>*<span style="color:#728e00">}</span>
<span style="color:#728e00">\setulmargins</span><span style="color:#728e00">{</span>*<span style="color:#728e00">}{</span>20mm<span style="color:#728e00">}{</span>*<span style="color:#728e00">}</span>
<span style="color:#728e00">\setheadfoot</span><span style="color:#728e00">{</span><span style="color:#728e00">\baselineskip</span><span style="color:#728e00">}{</span>2<span style="color:#728e00">\baselineskip</span><span style="color:#728e00">}</span>
<span style="color:#728e00">\setheaderspaces</span><span style="color:#728e00">{</span>0.5in<span style="color:#728e00">}{</span>*<span style="color:#728e00">}{</span>*<span style="color:#728e00">}</span>
<span style="color:#728e00">\checkandfixthelayout</span>
</code></pre></div><p>The trimmed size is set to zero, as it&rsquo;s included in the stock size. I wanted <code>18mm</code> of text height: the header is gone so we could increase this a little bit, compared to other books of similar size. For the margins, the spine gets the most, and it&rsquo;s auto-calculated (<code>{*}</code>).</p>
<h3 id="other-encountered-problems">Other encountered problems</h3>
<h4 id="hyphenation-rules-for-dutch">Hyphenation rules for Dutch</h4>
<p>In the Dutch language, when a word is split because of hyphenation rules in LaTeX (that is handled by setting the Pandoc language, by the way), the diaeresis is removed from words such as &lsquo;industriële&rsquo;. This <a href="https://tex.stackexchange.com/questions/106737/how-to-remove-diaeresis-after-hyphen">stackoverflow link</a> provided the solution, but I had to use the complicated one for Xetex to work nicely. Some words, I &lsquo;hyphened&rsquo; manually in the preamble, by adding <code>\hyphenation{korst-rand}</code>.</p>
<h4 id="spacing-between-paragraphs">Spacing between paragraphs</h4>
<p>Spaces between big sections of text, which are still part of the same chapter, can be achieved with <code>* * *</code> in Markdown using a simple Python filter. However, when that spacing hits the end of the page, readers have no idea whether or not a section was finished. You can use <code>\fancybreak{}</code> for that, but then the whole text would be filled with fancy symbols that take away the reading experience. It only should be displayed at the top or bottom of the page, if spacing is not possible.</p>
<p>I found the solution to the problem on another blog and can&rsquo;t remember which one, but this piece of tex fixes it:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-tex" data-lang="tex"><span style="color:#728e00">\newcommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\starbreak</span><span style="color:#728e00">}{</span><span style="color:#95a5a6">%
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">\fancybreak</span><span style="color:#728e00">{</span>* * *<span style="color:#728e00">}</span><span style="color:#95a5a6">%
</span><span style="color:#95a5a6"></span><span style="color:#728e00">}</span>
<span style="color:#728e00">\DeclareRobustCommand</span><span style="color:#728e00">{</span><span style="color:#728e00">\cs</span><span style="color:#728e00">}</span>[1]<span style="color:#728e00">{</span><span style="color:#728e00">\texttt</span><span style="color:#728e00">{</span><span style="color:#728e00">\char</span>`<span style="color:#728e00">\\</span>#1<span style="color:#728e00">}}</span>
<span style="color:#728e00">\newlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\tpheight</span><span style="color:#728e00">}</span><span style="color:#728e00">\setlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\tpheight</span><span style="color:#728e00">}{</span>0.9<span style="color:#728e00">\textheight</span><span style="color:#728e00">}</span>
<span style="color:#728e00">\newlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\txtheight</span><span style="color:#728e00">}</span><span style="color:#728e00">\setlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\txtheight</span><span style="color:#728e00">}{</span>0.9<span style="color:#728e00">\tpheight</span><span style="color:#728e00">}</span>
<span style="color:#728e00">\newlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\tpwidth</span><span style="color:#728e00">}</span><span style="color:#728e00">\setlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\tpwidth</span><span style="color:#728e00">}{</span>0.9<span style="color:#728e00">\textwidth</span><span style="color:#728e00">}</span>
<span style="color:#728e00">\newlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\txtwidth</span><span style="color:#728e00">}</span><span style="color:#728e00">\setlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\txtwidth</span><span style="color:#728e00">}{</span>0.9<span style="color:#728e00">\tpwidth</span><span style="color:#728e00">}</span>
<span style="color:#728e00">\newlength</span><span style="color:#728e00">{</span><span style="color:#728e00">\drop</span><span style="color:#728e00">}</span>
</code></pre></div><p>The end result, at the bottom of the page:</p>
<p><figure>
<a href="../book-starbreak.png" class="lbox">
<img loading="lazy" src="../book-starbreak.png" alt="starbreak" >
</a>
</figure>
</p>
<h3 id="the-verdict">The verdict</h3>
<p>Would I employ this toolchain again when writing the next book? Without a doubt. I am very happy with the end result and managed to guide Pandoc and memoir to render it just the way I want, something that would be difficult to achieve in Word without resorting to a shotgun (to either shoot at the Word devs, or at myself). It was a very good learning experience, which included the necessary swearing.</p>
<p>At least I won&rsquo;t have to start from scratch next time!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 May 2020.
</p>
]]>
</description>
</item>
<item>
<title>DIY: Hosting stuff on your own VPS</title>
<link>https://brainbaking.com/post/2020/04/vps/</link>
<comments>https://brainbaking.com/post/2020/04/vps/#commento</comments>
<pubDate>Mon, 13 Apr 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/04/vps/</guid>
<category domain="https://brainbaking.com/tags/server">server</category>
<category domain="https://brainbaking.com/tags/linux">linux</category>
<category domain="https://brainbaking.com/tags/vps">vps</category>
<category domain="https://brainbaking.com/tags/security">security</category>
<description>
<![CDATA[
<p>Hosting static websites on Github Pages is not a chore - on the contrary, it&rsquo;s free and very easy to set up: you only need a <code>CNAME</code> file with your domain in, and some plan to serve files from a branch or the <code>/docs</code> dir. However, as soon as you want something <em>more</em> than only static HTML files, you&rsquo;re stuck. My wife built her site in <a href="https://webnode.com">Webnode</a> and has looked countless times at migrating to (or from) Wordpress. I could cut costs and host these myself, with the added bonus to host just about anything! MySQL, Postgres, Node, Java, Go, &hellip; - whatever the need, I&rsquo;ll deploy it. I was looking at <a href="https://commento.io">Commento</a> myself to finally enable comments on my <a href="https://gohugo.io">Hugo</a>-enabled static sites.</p>
<h3 id="1-renting-private-server-space">1. Renting private server space</h3>
<p>Requirements:</p>
<ol>
<li>Hosted nearby - preferably in Belgium.</li>
<li>Cheap! Not more than 10 EUR/month</li>
<li>Fast - meaning 4GB of RAM at minimum.</li>
<li>Some bandwidth/HDD breathing space.</li>
</ol>
<p>I ticked all boxes except the first one - <a href="https://ovh.net">ovh.net</a> costs 7 EUR/month for a 4Gig VPS with 40GB SSD space, but it&rsquo;s hosted in Strasbourg. Still, our nameservers from <a href="https://antagonist.nl">Antagonist.nl</a> are in Netherlands anyway, so that&rsquo;s halfway there! I am sure there are cheaper options available but my experience tells me hosting various things requires at least 4GB RAM.</p>
<p>Yes, I could create my own nameserver. No, I don&rsquo;t want to over-complicate things.</p>
<h3 id="2-installing-and-configuring-your-vps">2. Installing and configuring your VPS</h3>
<p>Okay, we have SSH access to a brand new OpenStack-based Ubuntu server. What to do next?</p>
<h4 id="a-secure-the-ssh-channel">A. Secure the SSH channel</h4>
<p>The first thing to do - beside changing the root password - is to change <code>sshd_config</code> to listen to another port than the default <code>22</code>. Also, reject root login (<code>PermitRootLogin no</code>). Create a new user that can login and add him/her to the <code>sudo</code> group. Restart the service with <code>/etc/init.d/ssh restart</code>.</p>
<p>Next, to counter simple DoS attacks, install the fail2ban service. I left default config alone, it only checks SSH and seemed OK for me. <code>service fail2ban restart</code>.</p>
<h4 id="b-configure-a-firewall">B. Configure a firewall</h4>
<p>I&rsquo;m getting suspicious: now I have the responsibility of securing my own server, and I&rsquo;m far from a Linux Network expert&hellip; After scrolling through a few articles on the &lsquo;Net, it seemed like a good idea to configure <code>iptables</code> to block unwanted traffic.</p>
<ul>
<li>Accept loopback and established traffic</li>
<li>Accept input at ports <code>80</code> (HTTP), <code>443</code> (HTTPS), your custom SSH port</li>
<li>If you must, whitelist certain IP ranges, such as <a href="https://www.cloudflare.com/ips/">Cloudflare&rsquo;s IP list</a></li>
<li>Drop all the rest.</li>
</ul>
<p>You can back up and restore tables using <code>iptables-save &gt; file</code> and <code>iptables-restore &lt; file</code>. Remove rules using <code>-X</code>, <code>-F</code> and <code>-P INPUT/OUTPUT/FORWARD ACCEPT</code>. Check using <code>sudo iptables -L</code>.</p>
<p>Install package <code>iptables-persistent</code> to not lose the configuration after a server reboot. If something goes wrong, check <code>/var/log/kern.log</code> if you enabled logging using <code>iptables -A INPUT -j LOG</code>.</p>
<h4 id="c-configuring-the-mailserver">C. Configuring the mailserver</h4>
<p>If the shit hits the fan&hellip; I&rsquo;d like to know about it. So, a local mail-only server is not a bad idea. It will also be used by Commento when approving or rejecting comments. However, installing <code>postfix</code> proved to be <em>very</em> painful. After a few hours, I managed to get it to work, but Google still thinks the mail is spam. To fix that, I&rsquo;ll have to setup DKIM someday.</p>
<p>First, make sure you get a wildcard certificate (see below) to enable SSL. Add this to the <code>/etc/postfix/main.cf</code> config:</p>
<pre><code>smtpd_tls_cert_file=/etc/letsencrypt/live/brainbaking.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/brainbaking.com/privkey.pem
smtp_use_tls=yes
smtp_tls_loglevel=1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
</code></pre><p>Next, add a TXT DNS record with value <code>&quot;v=spf1 include:_spf.google.com ~all&quot;</code>, that makes Google less suspicious of your outgoing e-mail.</p>
<p>In case you missed something in the initial pkg configuration wizard, use <code>dpkg-reconfigure postfix</code>. Configure postfix to only use localhost outbound mail via IPv4/v6:</p>
<pre><code>myhostname = brainbaking.com
myorigin = $myhostname
mydestination = $myhostname, localhost.$myhostname, localhost
relayhost =
mynetworks = 127.0.0.1/32 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = loopback-only
inet_protocols = all
home_mailbox = mail/
</code></pre><p>One last - very annoying - thing is that I did not want outgoing mail to have the From address &lsquo;<a href="mailto:user@vps12345.ovh.net">user@vps12345.ovh.net</a>&rsquo;. I wanted it to be &lsquo;<a href="mailto:user@brainbaking.com">user@brainbaking.com</a>&rsquo;. Even with the <code>myorigin</code> and <code>myhostname</code> properties set, this would not work if you don&rsquo;t provide the <code>mail</code> command with a From address. Add this to your config: <code>smtp_generic_maps = hash:/etc/postfix/generic</code>. That file contains only one line that maps my unwanted address to the real one: <code>user@vps12345.ovh.net user@brainbaking.com</code>. Restart the service after that: <code>sudo systemctl restart postfix</code>.</p>
<h3 id="3-hosting-static-sites-on-your-vps">3. Hosting static sites on your VPS</h3>
<p>Now that the VPS is (somewhat) secure, let&rsquo;s install <code>nginx</code> and configure our websites. I followed a few tutorials, listed in the resources below. After that, I felt comfortable enough to dabble in the config files myself.</p>
<p>You first need to know that the previous setup was like this:</p>
<script defer src="/mermaid/mermaid.min.js">
mermaid.initialize({
startOnLoad: true,
flowchart: {
useMaxWidth: true
}
});
</script>
<div class="mermaid" align="center" >
graph LR;
Browser[Browser]
NS[DNS Nameserver]
Cloud[Cloudflare NS/SSL]
Github[Github Pages]
Browser --> NS
NS --> Cloud
Cloud --> Github
</div>
<p>I leveraged Cloudflare&rsquo;s free SSL certificates to secure my static websites. Now that we have our own VPS, we&rsquo;d like to alter the schematic like so:</p>
<script defer src="/mermaid/mermaid.min.js">
mermaid.initialize({
startOnLoad: true,
flowchart: {
useMaxWidth: true
}
});
</script>
<div class="mermaid" align="center" >
graph LR;
Browser[Browser]
NS[DNS/NS Nameserver]
VPS[Own VPS + SSL]
Browser --> NS
NS --> VPS
</div>
<p>That would involve modifying <code>NS</code> records at my domain host, resulting in a downtime of several hours until the new DNS records are correctly propagated. Bigger companies resolve this by installing their own nameservers.</p>
<p>It would also involve <code>certbot</code> to generate SSL certificates using Let&rsquo;s Encrypt. I was pleasantly surprised at the ease of configuration - certbot also gets auto-installed in the root&rsquo;s <code>crontab</code> to auto-renew certificates.</p>
<h4 id="a-configuring-nginx">A. Configuring nginx</h4>
<p>I first tried to configure the webserver to serve files using HTTP, and disabled Cloudflare&rsquo;s SSL settings. Only then I could let certbot fetch a new certificate and configure my HTTPS settings. After that, the VPS was in charge of SSL, and I could safely modify the NS records. To check whether the NS changes have been propagated successfully, use <code>dig A +short domain.com</code> or <code>dig NS</code>.</p>
<p>Setting up HTTPS for the root and www subdomain:</p>
<pre><code>server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /var/www/brainbaking;
index index.html;
server_name brainbaking.com www.brainbaking.com;
location / {
try_files $uri $uri/ =404;
}
# SSL
ssl on;
ssl_certificate /etc/letsencrypt/live/brainbaking.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/brainbaking.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# security
include nginxconfig.io/security.conf;
# additional config
include nginxconfig.io/general.conf;
}
</code></pre><p><a href="https://nginxconfig.io">nginxconfig.io</a> provides bread and butter config partials, such as security headers:</p>
<pre><code># security headers
add_header X-Frame-Options &quot;SAMEORIGIN&quot; always;
add_header X-XSS-Protection &quot;1; mode=block&quot; always;
add_header X-Content-Type-Options &quot;nosniff&quot; always;
add_header Referrer-Policy &quot;no-referrer-when-downgrade&quot; always;
add_header Content-Security-Policy &quot;default-src 'self' http: https: data: blob: 'unsafe-inline'&quot; always;
# . files
location ~ /\.(?!well-known) {
deny all;
}
</code></pre><p>and general caching config:</p>
<pre><code># favicon.ico
location = /favicon.ico {
log_not_found off;
access_log off;
}
# robots.txt
location = /robots.txt {
log_not_found off;
access_log off;
}
# assets, media
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
expires 30d;
access_log off;
}
# svg, fonts
location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
add_header Access-Control-Allow-Origin &quot;*&quot;;
expires 7d;
access_log off;
}
# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
</code></pre><p>If you are interested at redirecting HTTP traffic to HTTPS, you can do that too:</p>
<pre><code>server {
listen 80;
listen [::]:80;
server_name .brainbaking.com;
location / {
return 301 https://$host$request_uri;
}
}
</code></pre><h4 id="b-configuring-subdomains">B. Configuring subdomains</h4>
<p>Since I wanted to add subdomains to host other websites, including Commento, I needed a wildcard certificate. That was much trickier to get to work, but after some digging, this command worked for me:</p>
<p><code>certbot certonly --manual --preferred-challenge=dns --email [yourmail] --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d brainbaking.com -d *.brainbaking.com</code></p>
<p>It is <em>crucial</em> that you provide two <code>-d</code> flags: one for the root domain and one for the wildcard subdomain. I forgot the first one, resulting in browsers denying requests to the website and a headache. Certbot verifies if you own the domain using a <code>TXT</code> record in the DNS entry. After that, the SSL certificate can be used in any config for that domain.</p>
<p>For instance, hosting Commento and setting up a reverse proxy to redirect to the local Commento server running at port <code>8080</code>:</p>
<pre><code>server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name commento.brainbaking.com;
location / {
proxy_pass http://localhost:8080/;
proxy_set_header X-Real-IP $remote_addr;
}
# SSL (same as above)
</code></pre><p>I had to disable the Content-Security-Policy security header for the dashboard to work correctly.</p>
<h4 id="c-setting-up-auto-builds">C. Setting up auto-builds</h4>
<p>Using source control and Hugo, building static pages is easy: <code>hugo</code> - done. Before, I did that myself and checked in the <code>/docs</code> directory - which is stupid, considering something like Travis could do that for me. I deleted all generated files from the source repo.</p>
<p>On the server, I cloned repositories in <code>/var/dev/[repo]</code>. The sites get served in <code>/var/www/[repo]</code>. A simple script auto-builds these things, and <code>cron</code> runs it hourly: <code>0 * * * * /var/dev/build.sh &gt;&gt; /var/dev/build-output.log 2&gt;&amp;1</code>. Check the crontab using <code>crontab -e</code>, and check logs using <code>sudo grep CRON /var/log/syslog</code>. The buildfile is very simple:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#728e00">#!/bin/bash
</span><span style="color:#728e00"></span>
<span style="color:#434f54">sites</span><span style="color:#728e00">=(</span> site1 site2 site3 <span style="color:#728e00">)</span>
<span style="color:#728e00">for</span> site in <span style="color:#7f8c8d">&#34;</span><span style="color:#7f8c8d">${</span><span style="color:#434f54">sites</span>[@]<span style="color:#7f8c8d">}</span><span style="color:#7f8c8d">&#34;</span>
<span style="color:#728e00">do</span>
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;building site </span><span style="color:#434f54">$site</span><span style="color:#7f8c8d">&#34;</span>
<span style="color:#728e00">cd</span> /var/dev/<span style="color:#434f54">$site</span>
<span style="color:#434f54">RESULT</span><span style="color:#728e00">=</span><span style="color:#728e00">$(</span>git pull | grep <span style="color:#7f8c8d">&#39;Already up to date&#39;</span><span style="color:#728e00">)</span>
<span style="color:#728e00">if</span> <span style="color:#728e00">[</span> -z <span style="color:#7f8c8d">&#34;</span><span style="color:#434f54">$RESULT</span><span style="color:#7f8c8d">&#34;</span> <span style="color:#728e00">]</span>
<span style="color:#728e00">then</span>
/usr/local/bin/hugo --cleanDestinationDir --destination /var/www/<span style="color:#434f54">$site</span>/
<span style="color:#728e00">else</span>
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;nothing to do for </span><span style="color:#434f54">$site</span><span style="color:#7f8c8d">&#34;</span>
<span style="color:#728e00">fi</span>
<span style="color:#728e00">done</span>
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;done building.&#34;</span>
</code></pre></div><p>I considered other options:</p>
<ol>
<li>Host Jenkins. It&rsquo;s a fairly heavy Java process that should be kept on a separate CI server. Overkill.</li>
<li>Use Travis and SSH tunnel built artifacts. That would mean extra security exposures, and a pain to configure using public/private keys. Did that before, and was not keen on doing it again.</li>
<li>Use a simple script. Check.</li>
</ol>
<h3 id="4-hosting-dynamic-sites-on-your-vps">4. Hosting dynamic sites on your VPS</h3>
<p>Now that we have nginx up and running, I wanted to install the Wodpress chain to see how easy it would be to serve PHP content. It turned out to be quite easy. Install the required php and mariadb packages (don&rsquo;t use <code>apt install php</code> - it comes with a bunch of crap). Change what you need in <code>/etc/php/7.2/fpm/php.ini</code> and restart the <code>php7.2-fpm</code> service. Create a user and database in MariaDB and <code>wget</code> the latest Wordpress release. (I followed along a nice tutorial, linked below) That&rsquo;s it, it works! Oh wait, nginx config:</p>
<pre><code>server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /var/www/wordpress;
index index.php index.html index.htm;
server_name wordpress.brainbaking.com;
location / {
try_files $uri $uri/ /index.php?$args;
}
access_log /var/log/nginx/wordpress_access.log;
error_log /var/log/nginx/wordpress_error.log;
client_max_body_size 64M;
location ~ \.php$ {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_read_timeout 3600s;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 128k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
}
# SSL (same as above)
}
</code></pre><p>Same problem with the Content-Security-Policy security header.</p>
<p>Do not forget to &lsquo;harden&rsquo; your Wordpress install after configuring things in <code>wp-config.php</code>. Use <code>chown :www-data</code> for the wp-content dir. <code>chmod</code> dirs at 755, your config at 640, and the rest at 660.</p>
<h4 id="c-setting-up-auto-backups">C. Setting up auto-backups</h4>
<p>Since there&rsquo;s nothing to build, but databases do introduce the problem of backups, I again resorted to a simply DIY method as a &lsquo;good-enough&rsquo; means to handle the problem. Instead of downloading (<code>git clone/pull</code>) and building, like the static sites, I would periodically upload (<code>git push</code>) database backups and www files:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh"><span style="color:#728e00">#!/bin/bash
</span><span style="color:#728e00"></span><span style="color:#434f54">NOW</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">`</span>perl -e <span style="color:#7f8c8d">&#39;print time;&#39;</span><span style="color:#7f8c8d">`</span>
<span style="color:#95a5a6"># sync www files</span>
rsync --update -raz /var/www/wordpress ./www/
rm -rf ./www/wordpress/wp-config.php
<span style="color:#95a5a6"># backup mysql</span>
rm -rf ./www/wordpress/wpdb.*
mysqldump --defaults-file<span style="color:#728e00">=</span>/etc/mysqldump.cnf --add-drop-table --databases wpdb &gt; ./www/wordpress/wpdb.sql
bzip2 ./www/wordpress/wpdb.sql
rm -rf ./www/wordpress/wpdb.sql
<span style="color:#95a5a6"># auto-commit to github</span>
git add .
git commit -am <span style="color:#7f8c8d">&#34;autocommit server sync at </span><span style="color:#434f54">$NOW</span><span style="color:#7f8c8d">&#34;</span>
git push
</code></pre></div><p>Since the private Github repository keeps track of changes for me, I do not need to worry about frequency of backups and taking backups of already hacked sites. Alternatives I considered:</p>
<ol>
<li>Get a decent backup service on the VPS provider. Costs too much extra. Not worth it.</li>
<li>Zip everything in /var/www and SSH tunnel it to somewhere.</li>
<li>Zip everything and upload it to the private Git repo. Files too big, no incremental changes.</li>
<li>Serve everything in Docker containers and back these up &lsquo;somewhere&rsquo;. Overkill and difficult to configure.</li>
</ol>
<p>To reduce the security risk of adding my git credentials to the VPS server that would cause damage to other repositories, I created another Github user that&rsquo;s only allowed to push to that one repo.</p>
<p>I ended up extending this script to also sync crucial config files (nginx, postfix, crontab and iptable exports, &hellip;). In case I had to start over from scratch, I at least had something. I know it&rsquo;s a very poor solution to &lsquo;backup the server&rsquo;, but hey, it&rsquo;s something. SSL certificate backups are not required, just generate a new pair.</p>
<h3 id="5-monitoring-your-vps">5. Monitoring your VPS</h3>
<p>There are so many ways to actively or passively monitor a Linux server! I tried to pick the right option for me but almost drowned in the possibilities:</p>
<ol>
<li>Host the whole Elastic Stack yourself. Java processes, and way too much services for my humble sites with low traffic.</li>
<li>Use Nginx Plus. Costing.</li>
<li>Use what your VPS provides. Okay but not expandable.</li>
<li>Host the <a href="https://cockpit-project.org">Cockpit-Project</a> yourself.</li>
</ol>
<p>Option 4 looked very appealing once I learned it&rsquo;s built using node/modern JS frameworks such as React. It&rsquo;s also very easy to write your own modules. I enabled nginx&rsquo; stub_status module that once will hopefully integrate with Cockpit. For the moment, only <code>curl http://127.0.0.1/nginx_status</code> works. This, together with mailing when something is on fire, is still on the TODO list.</p>
<p>Also, I wonder whether or not Cockpit introduces more security problems: someone with bad intentions that knows the endpoint and login/password will wreck everything. Then again, the same applies for SSH.</p>
<h3 id="6-wrapping-it-up">6. Wrapping it up</h3>
<p>I had a lot of fun (re-)learning Linux Sysadmin skills and setting up things the way I want them to be. I know linux config files can be messy and all-over-the-place, so treating them as code and checking them in is one step. Auto-testing and using things like Docker containers is the next big thing, but I am not sure if I am willing to push it that far for simple websites like these.</p>
<p>There are still big holes in my security plan. You are welcome to drop a line in the comments below to suggest improvements. Right now, the biggest problem is probably the login/password of the VPS host provider, Cockpit, SSH, Github and DNS domain provider - they all can potentially break everything.</p>
<h3 id="resources">Resources</h3>
<ul>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-18-04">https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-18-04</a></li>
<li><a href="https://www.nginx.com/blog/monitoring-nginx/">https://www.nginx.com/blog/monitoring-nginx/</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-as-a-send-only-smtp-server-on-ubuntu-16-04">https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-as-a-send-only-smtp-server-on-ubuntu-16-04</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-dkim-with-postfix-on-debian-wheezy">https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-dkim-with-postfix-on-debian-wheezy</a></li>
<li><a href="https://www.rosehosting.com/blog/how-to-install-wordpress-with-nginx-on-debian-10/">https://www.rosehosting.com/blog/how-to-install-wordpress-with-nginx-on-debian-10/</a></li>
<li><a href="https://medium.com/@jgefroh/a-guide-to-using-nginx-for-static-websites-d96a9d034940">https://medium.com/@jgefroh/a-guide-to-using-nginx-for-static-websites-d96a9d034940</a></li>
<li><a href="https://docs.ovh.com/nl/vps/tips-beveiliging-vps/">https://docs.ovh.com/nl/vps/tips-beveiliging-vps/</a></li>
<li><a href="https://www.rosehosting.com/blog/how-to-set-up-a-firewall-with-iptables-on-ubuntu-and-centos/">https://www.rosehosting.com/blog/how-to-set-up-a-firewall-with-iptables-on-ubuntu-and-centos/</a></li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 13 April 2020.
</p>
]]>
</description>
</item>
<item>
<title>Five reasons why agile and academia don&#39;t go together</title>
<link>https://brainbaking.com/post/2020/02/agile-academia/</link>
<comments>https://brainbaking.com/post/2020/02/agile-academia/#commento</comments>
<pubDate>Tue, 25 Feb 2020 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/02/agile-academia/</guid>
<category domain="https://brainbaking.com/tags/agile">agile</category>
<category domain="https://brainbaking.com/tags/academia">academia</category>
<category domain="https://brainbaking.com/tags/development">development</category>
<description>
<![CDATA[
<p>I wish the word <em>&ldquo;don&rsquo;t&rdquo;</em> in the title of this post could go away, but after years of trying, I have to say it cannot. There are so many aspects of the academic world that speak against agility that I had to make the conscious choice to reduce the list to five big reasons why I think both do not converge well. Remember that this is my own subjective opinion, and perhaps also meant to utter some well-meant critique, but by no means a one-sided rant: I have spent rather large parts of my career on both sides.</p>
<p>The word <em>&ldquo;agile&rdquo;</em> can also be understood as <strong>fast feedback</strong>. That is my sole indicator for success in an agile world: the <em>demo or die</em> principle, iterative development, a possible fast changing scope, &hellip; - these concepts all have one thing in common: the principle of fast feedback. The following reasons all lack this, each with it&rsquo;s own reason, therefore each contributing to why agile and academia do not work together.</p>
<h2 id="1-the-paper-peer-review-process">1. The Paper Peer Review Process</h2>
<h3 id="code-reviews-should-not-exist">Code Reviews should not exist</h3>
<p>Peer reviewing is a great concept that in theory should eliminate too much bias and variance, and in practice mostly manages to do just that. The better part of software development is the code (peer) review system, where colleague developers carefully review code written by their peers. The intention is to:</p>
<ol>
<li>Provide useful feedback for the developer to <em>learn</em> from</li>
<li>Increase the (code) quality of the developed product in general</li>
<li>Provide useful feedback for the reviewer him-herself</li>
</ol>
<p>Code reviews should happen as soon as a single piece of functionality (or even a sub-part of that) is finished, in practice when a post-it note moves on the Kanban/Scrumboard to the column &lsquo;toreview&rsquo;. This happens between 1 and 5 days, depending on the depth of the functional part.</p>
<p>The problem is, that is <em>too late</em>. Yes, you&rsquo;ve read that right: code reviews mostly happen too late! Frequent code reviews with lots of changes are usually red lights, indicating a major problem in the team: too little people are up-to-date on an API, conventions, standards, and so on. Remember that x days have passed, and you should go back to square one. In reality, that never happens.</p>
<p><em>Great</em> teams tackle this issue by:</p>
<ol>
<li>Pair programming.</li>
<li>Frequent (ad-hoc) &lsquo;sparring&rsquo; sessions, asking feedback earlier.</li>
</ol>
<p>If everybody is pairing, code reviews are obsolete. As soon as someone writes a line of code, it&rsquo;s reviewed. No more eyes are needed, since the team is usually on the same line anyway - and if that is not the case, you should switch pairs more often. Hence, <strong>Code reviews should not exist</strong>.</p>
<h3 id="what-about-paper-reviews">What about Paper Reviews?</h3>
<p>Writing a paper takes between 8 weeks and more than a year, including gathering ideas, the collection of the data, and so forth. A paper is the result of a project, let&rsquo;s call it the <strong>product</strong> to be placed in production while we&rsquo;re at a software development comparison anyway. So no code reviews (well, barely, from internal colleagues) of small parts happened.</p>
<p>After paper submission, you usually have to wait one to three months for the conference/journal to hear a verdict. Meanwhile, a small task-force of reviewers has been assembled to read 4 to 20 papers for a given conference, and of course to provide that valued feedback. What happens? Reviewers give feedback on all sorts of things:</p>
<ul>
<li>On the syntax and layout of the paper</li>
<li>On the study setup and results</li>
<li>On the lack of references</li>
</ul>
<p>Most of that feedback is (1) <em>useless</em>, and (2) happens way <em>too late</em>. The last conference I reviewed for, another (anonymous, luckily) reviewer commented on a certain paper that the study is done all wrong and that he or she would have liked it seen like this or like that. Let&rsquo;s try to link that back to software development: that&rsquo;s like saying the program does not fulfill the needs of the client, the database structure is set up all wrong and a critical part of the interface is missing.</p>
<p>I am not saying that reviewer acted too harsh or it was stupid to give that kind of feedback. I am saying it happened way too late: for the researchers, the research setup has been done possibly more than a year ago. Where were they then? That kind of one-time feedback at the end of the cycle is usually not taken into account at all: instead, most researchers simply submit their work somewhere else. There, done.</p>
<p>In the current paper acceptance system, there is simply no room for <em>fast feedback</em>. Everybody is very busy working on their own studies, I am sure, but that does not mean in-between feedback cycles are simply impossible to do. As a concerned researcher, you can try to counter this weakness by asking feedback from your research group. Good idea, but with very little reaction: they&rsquo;re all &lsquo;too busy&rsquo; doing what they are doing. Why is this not a problem in software development? Because the review system is <strong>built into the very culture</strong>.</p>
<h2 id="2-the-phd-system">2. The PhD System</h2>
<p>By now you might have guessed where I am going with this. A PhD usually takes four years, and of course there is plenty of room for feedback before the final PhD defense. However, in practice, these moments happen infrequent and again, still too late.</p>
<h3 id="demo-or-do-not-die">Demo (or do not die)</h3>
<p>Professors, as supervisors, hopefully, arrange frequent meetings with their PhD students to track the progress and to allow for a feedback moment. However, this is still not considered a standard practice and greatly varies depending on your supervisor. I know people who see and talk to their supervisor at most four times a year. Luckily, for me, we try (and sometimes fail) to keep on a steady cadence of once-a-month meetings for both supervisors.</p>
<p>The problem is, again, that this is way <em>too late</em>. In one month, in a software development world, you should have passed a whole iteration, getting daily feedback from the &lsquo;development cycle&rsquo; (provided all goes according to plan). So, you could compare these gatherings with the demo&rsquo;s that are usually organized after each iteration. Indeed a valuable way to get some feedback.</p>
<p>But that feedback moment is short, and a lot of things should be done by then, sometimes putting research back to square one, while earlier feedback would have prevented that. I would love to see a solution similar to the one applied in the industry: pair PhDs, like pair programming. It would certainly also fix the loneliness problem.</p>
<h3 id="overburdening">Overburdening</h3>
<p>Trying to pin down monthly meetings is a pain though: supervisors are usually extremely busy. Professors are burdened with education assignments, they need to search and hopefully find enough funding for research, and in-between they also need to translate knowledge into socially relevant and digestible material. Since there is usually a (big) shortage on academic staff, student groups are too big to adequately handle, assignments take longer to grade, meetings on financial reports and other necessary evil things need to be planned in, and so forth.</p>
<p>I tried at times to simply hijack my co-supervisors' time when I saw him, and that works, up to a certain extend: he is usually nowhere to be found, either teaching, or in meetings, or when focus sessions are really needed, grading/preparing at home.</p>
<h2 id="3-the-email-world">3. The Email World</h2>
<p><em>Well, can&rsquo;t you simply ask for feedback via email, in between your monthly meetings?</em> you ask. Yes of course we can, but it&rsquo;s usefulness is very much limited due to problem number three: the Email World.</p>
<p>The academic world is run by email. It eats mails for breakfast, breathes inbox all day long, and probably cooks up crumbled email for dessert.</p>
<p>And it is horrible. I <em>hate</em> every aspect of it. But there is simply no other way to reach out to someone. As a software developer, reaching out to others is as simple as moving your butt a few meters to your left or right. If you need someone from another team, fine, maybe you even need to go up or down a floor. Yes I have worked with nearshoring teams, but then Skype works, and these teams never did great anyway. Even if you are an employee in a big consultancy firm, you usually only need tings from your &lsquo;daily colleagues&rsquo;.</p>
<h3 id="working-remote">Working Remote</h3>
<p>At my University, we are remotely located on another Campus, and my supervisor works 91km further away. Even if you regularly see your supervisor(s), chances are still very high that you need things from others working at remote locations, possibly even other Universities and other countries. One of the things I really like about the academic world is working together with different people from different universities. Guess what our preferred way of communicating is? Right.</p>
<p>Some PhD students dare to introduce things like Slack, but without the proper critical mass (and support), these things will never be put into the spotlight, to be ultimately shoved aside in favor for&hellip; You guessed right again!</p>
<p>The problem with email is not email itself. It is the asynchronous process of mailing a request and receiving a response. I am not saying we should introduce a system where everybody checks their mail every five minutes, as obviously email is not meant to be a communication system where everybody drowns in. But in reality, I have never seen it as bad as in academia. I receive ten mails on average each day, and I&rsquo;m just a simple PhD student. Nine of those mails are mailing groups, research group news, Faculty news, or the election of the new Dean: things the delete button is made for.</p>
<p>The overburdening principle of faculty members, as explained above, combined with the email system as the default way of communicating, rapidly generates a huge overhead. It is not uncommon that I receive mails from a professor <em>three months after my initial mail</em>, containing something in the lines of &lsquo;sorry it got lost in the heap&rsquo;. That is just sad.</p>
<p>My email life as a software developer was non-existing. I never opened GMail or a mail client more than twice each day, now I aim for checking at least once an hour. I became addicted, craving those highly anticipated responses, almost screaming <em>GIMME THAT FEEDBACK</em>. It of course never comes.</p>
<h2 id="4-the-academic-year">4. The Academic Year</h2>
<p>Working in an academic context of course also means coming in contact with students. Students who study in a steady pace, neatly divided into 2 semesters. This also requires the academic staff to adjust to that time frame, as they are the one teaching the students. Software developers are also locked in a certain time frame: the cadence of the iteration.</p>
<p>See what I did there? A semester, compared to a typical iteration, is more than 12 weeks, not just two or three. Students get assignments, need to finish reading their manuals by the end of the semester, before proving what they are worth during the exam period. That usually means <em>late feedback</em>, also for a student. While there are many promising initiatives taken to expedite these feedback moments (for instance by the introduction of multiple smaller assignments during the semester), the baseline has not moved yet, and I doubt it ever will.</p>
<p>That said, the impact of this semester system is bigger than you might think: it also impacts all other reasons we talked about so far. The academic staff is used to working within semesters, and will usually reserve the bulk of their research work in free moments in-between, or in the summer holiday period. Most conferences also take place from June to September because of that. This phenomenon makes sure that professors' time is further compressed during the academic year, further reducing the chance of getting frequent feedback. Remember that in case of curriculum renewals, a lot of preparation before the start of the year also has to be carried out.</p>
<p>Instead of the <strong>steady pace</strong> we preach for in the software development world, the Academic Year is a frantic way of dividing time and work into two huge unmanageable blocks each year. This makes trying to introduce recurring meetings even more difficult.</p>
<h2 id="5-stigma">5. Stigma</h2>
<p>The psychology of work has a big influence on the way you work in a particular environment. Different stigma&rsquo;s attached to that environment strengthen a pre-defined way of thinking about how to work. If the agile philosophy in a company penetrates every single thing they do there, it will become a part of the company culture. The current academic culture, unfortunately, makes things more difficult to quickly adapt.</p>
<h3 id="things-go-slower-here">&lsquo;Things go slower here&rsquo;</h3>
<p>Everybody knows about the semester system, and everybody knows that academic staff is very busy. These well-known &lsquo;truths&rsquo;/&lsquo;rumors&rsquo; further magnify what&rsquo;s already there. In the end, you almost expect no reply the first week when sending out an email. This stigma does not help at all, and possibly makes things even worse. The expectation that everything is simply slower also puts an abrupt halt to people who still think things can be done a bit quicker.</p>
<p>Of course, one of the celebrated reasons why things need to go slower, is the lengthy time to think, tinker, and possibly invent stuff, aiming for high-impact published work that can only be the result of a good long session of reading, thinking, and re-reading. The lack of this kind of freedom in the industry is indeed visible in the general lack of quality of a lot of end products. Pragmatism is clearly a word invented in the industry as an excuse to declare things done. Things need to be rolled out, clients need to be served, and the quicker we can do that, the more money we can make. However, academia has been spying on the private world and sadly also evolving towards this model of lower-quality high-output: the classic <em>publish or perish</em> system.</p>
<p>Extreme dogmatism is not much better than extreme pragmatism, but the first does require more time. A cumbersome machine that is more difficult to turn does not exactly yell <em>agility</em>.</p>
<h3 id="you-work-alone-here">&lsquo;You work alone here&rsquo;</h3>
<p>The second stigma starts to take shape when working on a PhD, and is further strengthened during the years. As said before, I would love to see a &lsquo;pair PhD&rsquo; system like pair programming. I could generalize this into a proposal for &lsquo;pair researching&rsquo; kind of work since the way you work does not change after obtaining your degree. Everybody knows (and shows) that <em>the</em> way to work is to work alone. That is just the way it has to be.</p>
<p>And that could not be more wrong. Yes, academics regularly work together, and yes, collaboration happens across the globe, more so than in the industry. However, there is a very big difference between <em>collaborating</em> on a project, and intimately <em>working together</em>, side by side, on a project. In the end, a collaborative project is just a project where the work is divided and you sync now and then using meetings. The stigma that you are &lsquo;supposed&rsquo; to do it all by yourself is still present, and that only makes things worse.</p>
<p>Even in the industry, HR experts declare that research work is mostly carried out alone, depicting the lone researcher in a white coat, tucked away in his lab, experimenting with perhaps chemical flasks? The stereotype of the programmer sitting in a basement typing like a maniac, all by himself, has been replaced by the lone researcher. Nowadays, programmers program in teams. Sure, researchers are part of a research group, and sure, they proudly self-declare they&rsquo;re part of a team. But that team does not know what effectively working together is, they merely collaborate now and then. This claim will no doubt upset people, unable to understand the difference, until also worked for a few years in the industry.</p>
<h2 id="so-what-do-i-do-about-it">So, what do I do about it?</h2>
<p>Not much, honestly. With enough critical mass, a company culture can be turned around. But given the sheer size of something like a University, do not get your hopes up. Instead, try do work with what you&rsquo;ve got/can find. That does not mean you should blindly accept all reasons why agile and academia don&rsquo;t go together. Here are a few tips for each reason:</p>
<ol>
<li>Ask for feedback on your abstract, your setup, and every single semi-finished section if you can. Don&rsquo;t limit this to supervisors. Remember to expect feedback on layout that is not relevant yet. Do not give up if there&rsquo;s no response. When peer reviewing for conferences or journals, try to accept that this indeed is late feedback - and that probably is better than none at all. When receiving peer-reviewed feedback, be ready to put it into perspective.</li>
<li>Do not skip on the demo&rsquo;s - instead, do these for yourself every &lsquo;iteration&rsquo;. It is still possible to work in chunks for yourself. Try to find like-minded people, possibly outside of your daily working environment, maybe even outside of University. Talk to these people regularly, and not only about your work itself.</li>
<li>I would love to say &lsquo;stop emailing people&rsquo;. Effective advice would be &lsquo;start spamming reminders&rsquo; but that only makes things worse. I honestly still do not have a better idea on how to reach people you don&rsquo;t know that well.</li>
<li>Accepting the semester system and adapting yourself to it is the only way you will survive it, especially if you&rsquo;re also a teaching assistant like me.</li>
<li>Never, ever, blindly accept that culture. Put your own culture and way of working before the University&rsquo;s way of working where possible: at least that&rsquo;s an advantage of working alone.</li>
</ol>
<p>These tips honestly still don&rsquo;t do much. In the end, it it still frustrating to receive late feedback instead of early, especially when you&rsquo;re used otherwise. Luckily we humans are very adaptive. Before you know it, you won&rsquo;t even remember what it was like to work in an agile environment&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 25 February 2020.
</p>
]]>
</description>
</item>
<item>
<title>Over Onmiddellijke Voldoening</title>
<link>https://brainbaking.com/post/2019/12/over-onmiddellijke-voldoening/</link>
<comments>https://brainbaking.com/post/2019/12/over-onmiddellijke-voldoening/#commento</comments>
<pubDate>Mon, 02 Dec 2019 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2019/12/over-onmiddellijke-voldoening/</guid>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/beren_winkel.jpg"/>
</p>
<p>Spring jij onmiddellijk in je wagen als die plotse zin in tomatensoep op komt en je zelf niets in huis hebt? &lsquo;Snel even een blikje lenen, ik ben zo terug schat!&rsquo; Het lijkt als een onschuldige actie, maar er schuilt heel wat meer achter deze dorst naar huiselijke soep: alles wat ik niet heb, wil ik, en wel nu dadelijk.</p>
<p>Het probleem is dat het vandaag ook allemaal <em>kan</em>.</p>
<p>Je <em>kan</em> via Ali Express eender wat bestellen. Dat wordt dan wel drie weken wachten op de boot. Je <em>kan</em> via Bol.com héél veel bestellen. De volgende dag ligt het pakketje aan de deur. Webshops zijn niet meer weg te denken in ons leven. Het probleem is niet de shop, maar de ingesteldheid, en de &lsquo;zwakheid van het vlees&rsquo; om onmiddellijk in te geven. Roy Baumeister noemt het (een gebrek aan) <strong>wilskracht</strong> (<a href="https://www.goodreads.com/book/show/11104933-willpower?ac=1&amp;from_search=true&amp;qid=H6540Z2fZQ&amp;rank=1">Willpower</a>). Het interessante aan Baumeister zijn werk is de vaststelling dat wilskracht een <em>uitputbare bron</em> is. Laat dat nu net hét probleem zijn van de hedendaagse vluchtige kapitalistische (post-moderne?) cultuur: we worden langs alle kanten gebombardeerd met vanalles-en-nog-wat, die deze wilskracht zéér snel uitput.</p>
<p>Ik kijk met de ogen van een vijfendertigjarige naar achtjarige kinderen die schreeuwend van hun ouders eisen dat LEGO doos z onmiddellijk MOET worden aangekocht. Betekent dat dat ik als achtjarige nooit schreeuwde en iets graag wilde hebben? Natuurlijk niet, maar mijn ouders gaven me nooit zo snel mijn zin - en maar goed ook. Ik herinner me nog dat ik een of andere plastieken Turtle zelf mocht kiezen, maar dat ik er eerst voldoende over diende na te denken. Na de keuze is er immers geen weg terug: ik kreeg maar één exemplaar. Ik koos uiteindelijk na, volgens mij voldoende, te hebben nagedacht. Twee uur later had ik er al enorme spijt van, en wilde ik dolgraag het andere exemplaar. Ik was oprecht verdrietig, en als ik nu terugdenk aan dat nog glashelder moment, krijg ik het terug warm. Maar ik begreep ook dat ik een keuze had gemaakt, en dat ik onmogelijk beiden kon bezitten. Ik was als kind natuurlijk afhankelijk van het geld en de toestemming van mijn ouders. Die manier van verantwoordelijkheid implementeren lijkt te ontbreken bij velen. Ze willen alles. <em>Whatever it takes</em>, zoals de popliedjes zo vrolijk beschrijven. Of, <em>because you&rsquo;re worth it</em>. Of we er nu voor moeten schreuwen, dreigen, of twee keer op een webshop voor moeten klikken: ontvangen zullen we - en hoe.</p>
<figure>
<img src="/img/tnmt.jpg"/> <figcaption>
<h4>Nostalgie in de vorm van goede of slechte herinneringen?</h4>
</figcaption>
</figure>
<p>Een speeltje dat niet in de lokale winkels lag kon men vroeger bestellen bij diezelfde handelaar. Dat betekende een week of twee wachten, tot de groothandelaar de juiste zaken terug aanleverde. Ondertussen kon je genieten van iets magisch: <em>uitkijken naar iets</em>. Kennen we dat eigenlijk nog? Het enige wat wij momenteel kunnen doen is uitkijken naar bepaalde dagen, want die zijn nog niet beschikbaar op bestelling. Zelfs dat klopt niet helemaal: de feestdagen beginnen elk jaar vroeger dankzij de commerciële mallemolen die ons nog meer opjut om op de &lsquo;koop nu&rsquo; knop te drukken.</p>
<p>De iPhones die tweejaarlijks worden vernieuwd vormen in zekere zin ook een verslaving. Ik word uitgelachen met mijn voorkeur voor een (te oude) kleine smartphone, dat een belachelijk moeilijke zoektocht bleek te zijn. Updaten blijkt heel weinig te maken hebben met het dichten van veiligheidslekken en het oplossen van kleine en grote probleempjes, maar meer met dat voldoeningsgevoel. Misschien toch maar wachten tot er een afprijzing verschijnt&hellip; Black Friday, Purple Thursday, Sunny Holidays, noem maar op: zelfs daar moeten we ook niet bepaald op wachten, het is elke dag wel een koopjesdag.</p>
<p>Na een zware werkdag, die ook nog eens eiste dat je de frustrerende files moest trotseren, is het niet meer dan logisch dat onze wilskracht op negatief staat. Een snelle hap in plaats van een uitgebreide (en fatsoenlijke), en een <em>instant-film</em> in plaats van een goed boek. Als dan die laptop op de schoot wordt genomen en onze Paypal account automatisch inlogt is het belachelijk eenvoudig om drie kartonnen dozen vol rotzooi te bestellen die enkele dagen later door ook een gefrustreerde postbode worden geleverd. Ondertussen kunnen we lekker <em>binge-watchen</em>, zo een beetje het gruwelijkste woord (inclusief betekenis) van de afgelopen jaren. Want waarom wachten op volgende week als je het vervolg van die serie vandaag al kan kijken?</p>
<p>Onmiddellijke voldoening heeft ook te maken met de onmiddellijke aanwezigheid van alles, dankzij de hyper verbonden wereld en de 150gr zware apparaatjes die precies een extensie van onze hand geworden zijn. Als we nu op vakantie zijn, kunnen we onmiddellijk de familie kiekjes opsturen, waarvan we uiteraard verwachten dat ze onmiddellijk bekeken worden. Wanneer mijn ouders op vakantie zijn, word ik gebombardeerd met foto&rsquo;s van idyllische landschappen, goedkoop bier, en veel te veel &lsquo;selfies&rsquo;. Daar wordt dan onmiddellijk op gereageerd, liefst met zaken als &lsquo;leuk! (hartje) (hartje)&rsquo;, of &lsquo;amuseer u, hier is het nog steeds kak!&rsquo;.
Vijfentwintig jaar geleden reden mijn ouders mijn zussen en mij voorbij de Spaanse grens, om een dag later het dorpscentrum in te rijden en peseta&rsquo;s in een telefooncel te steken, hopend op een verbonden lijn die de grootouders geruststellen dat we allemaal nog leven. Vakantiefoto&rsquo;s werden uiteraard pas ontwikkeld na de terugreis.</p>
<figure>
<img src="/img/mediamarkt.jpg" width="60%"/> <figcaption>
<h4>Meer wachten dan nodig? Ik ben toch niet gek!</h4>
</figcaption>
</figure>
<p>Dat klinkt allemaal redelijk pessimistisch, verlangend naar een vervlogen tijdperk van telefoonkaarten in een pre-Euro zone. In feite wil ik dit zeggen: waarom is het nodig om nutteloze foto&rsquo;s van nietszeggende dingen door te sturen op het moment zelf, in plaats van ter plekke te genieten en het verhaal achteraf te vertellen? Want wat valt er de familie te vertellen bij de thuiskomst, als we heel de rit al veel te intens hebben meegemaakt? &lsquo;Oh ja, dat wist ik al, ik zag het op foto x&rsquo;. Iedereen is al op de hoogte van elkaars reilen en zeilen voordat we mekaar effectief zien. Dat betekent dat er op het moment van weerzien maar bitter weinig te vertellen valt. En dan zijn we verwonderd dat sociale capaciteiten toch niet de grote sterktes van tegenwoordig zijn.</p>
<ul>
<li>Game nodig? Open Steam. Klik &lsquo;koop.&rsquo; Wacht 5 minuten.</li>
<li>Film nodig? Open Netflix. Selecteer iets. Wacht niet.</li>
<li>Boek nodig? Open Amazon. Klik &lsquo;koop&rsquo; op een eBook. Wacht niet.</li>
<li>Tomatensoep nodig? Open supermarkt websites. Klik op &lsquo;koop&rsquo;. Wacht een dag voor de levering of haal onmiddellijk af.</li>
<li>Tomatensoep in het midden van de nacht nodig? Rijd naar Nachtwinkel Meheb.</li>
<li>Brood/fruit/aardappels/&hellip; nodig? Rijd naar een brood/fruit/aardappelautomaat.</li>
<li>Verse lychee nodig? Vlieg toch gewoon zelf even naar China?</li>
</ul>
<p>Waarop wachten we tegenwoordig nog? Op de wifi verbinding? Op de Windows updates? Op het groen licht, en de klote chauffeur die niet snel genoeg gezien heeft dat het licht daadwerkelijk op groen is gesprongen? Op een Master diploma, dat tot vervelends toe toch wel eens vijf jaar of langer kan duren, afhankelijk van de goesting van de student (en dus de wilskracht)?</p>
<p>Onmiddellijke beschikbaarheid is volgens velen geen luxe, maar eerder een vereiste. Niet dadelijk reageren op een e-mail bericht resulteert in een nieuw, ditmaal geagiteerd heb-je-dit-gelezen-dringend-antwoord-nodig bericht, vaak de dag nadien. Dan heb ik het nog niet over werk-werk e-mail verkeer, maar over privé afspraken, waar we evenzeer verwachten dat iedereen constant kan en wil antwoorden. Snailmail (d.w.z. de klassieke post) is voor geitenwollen sokken liefhebbers, voor zotten die de pen ter hand durven nemen en over het magisch iets genaamd <em>geduld</em> beschikken.</p>
<p>Dat het een schone deugd is, weten we al langer. Maar er zijn zoveel deugden, en een mens moet nu eenmaal kiezen. Ongeduld past beter bij de huidige maatschappij anno 2019. Geduld is voor mensen die eigen groenten telen in een moestuin. Of zelfs dan niet: dan ga je toch gewoon naar de handelaar om reeds uit de kluiten gewassen planten te kopen in plaats van vanaf nul alles zelf te zaaien?</p>
<p>Er zijn wel degelijk veel dingen waarbij traagheid een overbodige vorm van tijdverkwisting is. Een bestand downloaden van het Internet, bijvoorbeeld: of dat nu een uur duurt, of slechts één minuut: het resultaat en de handeling is exact hetzelfde. Dat kan niet gezegd worden over brood bakken in één uur of in een dag of langer. De samenstelling van het deeg is anders, evenals de smaak die meer ontwikkeld zal zijn als je er wat langer op wacht. Je bestand zal niet lekkerder smaken met een trage telefoonlijn. Een snellere transactie zal evenmin ongevallen veroorzaken op een snelweg. Over CO2 uitstoot valt nog te discussiëren. Wachten op een triviaal bestand dat je nodig hebt voor je werk schept niet bepaald hoopvolle verwachtingen, dus het heeft ook om emotionele redenen weinig zin om dit uit te stellen. Uitkijken naar iets kan ook op andere manieren.</p>
<p>Leven in <em>traagheid</em> in plaats van snelheid geeft ons meer ademruimte om banale dingen te kunnen appreciëren, zoals het wachten op een veelbetekenend antwoord van een (analoge) brief. Kent iemand dat gevoel nog dat je krijgt als je elke dag naar de brievenbus holt, in de hoop dat er iets je kan verrassen? Drie keer per dag op <code>F5</code> drukken in de e-mail client is alles behalve hetzelfde. Naar een moment toe leven is minstens even belangrijk als het moment zelf, hoe melig het ook linkt, en hoe vaak ikzelf dit niet besef op het moment dat ik de weg aan het bewandelen ben. Het eerste wat je zegt als je op de top staat is: &lsquo;<em>Fijn! Op naar de volgende!</em>&rsquo; Plots is het leven gereduceerd tot een flauwe aaneenschakeling van opwindende momenten, in plaats van een bochtig en kronkelend pad dat inderdaad opwindende open plekken kent, maar ook ruige en dicht beboste gebieden.</p>
<p>Het alles-nu-hebben vuurtje wordt nog verder opgestookt door geweldige self-help boeken die zeggen &lsquo;stop met uitstellen, NU is het moment! Doen doen doen! Hup, broek aan, en vooruit!&rsquo; Ik probeer niet te spreken over uitstelgedrag, maar over niet-nadenken gedrag. Is iets uitstellen hetzelfde als uitkijken naar iets? Nee, want als je uitkijkt naar iets, heb je al een actie ondernomen, waarbij je simpelweg wacht op de actie van iets of iemand anders. <em>Don&rsquo;t just stand there, do something!</em> zou moeten worden vervangen door <em>Don&rsquo;t just do something, stand there!</em>, een leuke suggestie die ik ooit las in een van de <a href="https://pragprog.com/">Pragmatic Programmers</a> boeken, die stelt dat bij problemen in code je éérst dient te verifiëren vooraleer te (her-)werken.</p>
<p>Terwijl ik dit schrijf, vraag ik me af in hoeverre ik hier zelf rekening mee houd. Ik vrees dat ik er zelf niet bijster veel van bak. De theorie is nu eenmaal altijd makkelijker dan de praktijk, wat academici je ook durven wijsmaken. Maar ik ben me er (bij momenten zoals deze) wel van bewust, en dat is reeds een belangrijke stap. Een van de moeilijkheden is namelijk dat de rest van de wereld wél in onmiddellijkheid leeft, en je in veel gevallen je daar naar dient te schikken. Een schouderophalen is de enige manier om hier mee om te gaan:</p>
<blockquote>
<p>Shikata ga nai (<code>仕方がない</code>)</p>
</blockquote>
<p>De Japanse manier om hier mee om te gaan is &lsquo;<em>Shō ga nai</em>&rsquo; zeggen: &lsquo;niets aan te doen&rsquo;. <a href="https://en.wikipedia.org/wiki/Shikata_ga_nai">Wiki</a>: <em>The ability of the Japanese people to maintain dignity in the face of an unavoidable tragedy or injustice, particularly when the circumstances are beyond their control</em>. C&rsquo;est la vie!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 2 December 2019.
</p>
]]>
</description>
</item>
<item>
<title>Programming: a Creative Cognitive Process</title>
<link>https://brainbaking.com/post/2019/10/creative-cognitive-processes/</link>
<comments>https://brainbaking.com/post/2019/10/creative-cognitive-processes/#commento</comments>
<pubDate>Tue, 08 Oct 2019 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2019/10/creative-cognitive-processes/</guid>
<category domain="https://brainbaking.com/tags/creativity">creativity</category>
<category domain="https://brainbaking.com/tags/phd">phd</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/glasses.jpg"/>
</p>
<p>My <a href="https://people.cs.kuleuven.be/~wouter.groeneveld/slr/">previous</a> <a href="https://people.cs.kuleuven.be/~wouter.groeneveld/delphi/">studies</a> investigated which non-technical skills are currently being taught in software engineering education, and which are perceived as needed to excel in the industry. We found creativity to be one of the key skills that still seemed to be mostly ignored in higher education (at least in Computing). The term &lsquo;creativity&rsquo; is highly subjective, contextual, and vaguely defined (or not at all), so connecting the dots proves to be quite a challenge.</p>
<p>Software development <em>is</em> creating a software product, line by line. Therefore, software development is seen as one of the most creative endeavors people can embark in. There are no restrictions on physical laws, only the boundaries of your own imagination. And of course processing speed, Amazon Cloud costs, the willingness of others to collaborate, and so forth. But the given flexibility of software engineering is unique compared to other engineering disciplines. In civil engineering, you do not refactor a bridge in a few days, or adjust the angle of suspension hooks in mere seconds after a failing test. Of course, the heavy emphasis on theory and prototyping should help in avoiding these kinds of mistakes, but the point is: we software developers love making them.</p>
<p>In fact, I think we are in love with failure.</p>
<p>If you cannot fail, you cannot learn. And since failure is so easy (and hopefully fixing mistakes is also easy!), developers should love learning. The fact that the software world is ever-evolving does not make things easier. Since we are ever-creating, even in operation modus, the question is: how does creating, or rather <em>creativity</em>, work - applied to the field of software engineering? There is a lot of research on creativity in the field of (cognitive) psychology, resulting in a plethora of theoretical models, of which a few are easily transferable across domains.</p>
<p>One of those models is Amabile&rsquo;s Componential Model of Creativity<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> (<a href="https://www.slideshare.net/medikawy_2005/how-to-kill-creativity-in-your-organization/14-knowledgeexibility_imaginationintrinsic_extrinsicThe_threecomponentsof_Creativityexpertisemotivationcreativethinkingskillswhere">img src</a>):</p>
<p><figure>
<a href="../creativitymodel.jpg" class="lbox">
<img loading="lazy" src="../creativitymodel.jpg" alt="creativit model" >
</a>
</figure>
</p>
<p>As deceptively simple as this looks, let us zoom in on each component and try to map these to the field of software development.</p>
<h3 id="the-three-components-of-creativity">The Three Components of Creativity</h3>
<h4 id="a-expertise-component">a. Expertise Component</h4>
<p>An &lsquo;expert&rsquo; knows things a junior does not. By knowing, we are talking about several major parts:</p>
<ol>
<li><strong>Technical knowledge</strong>, (<code>33%</code>) such as:</li>
</ol>
<ul>
<li>Programming Languages</li>
<li>(Enterprise) Patterns</li>
<li>Principles such as Unit Testing</li>
<li>Tooling, IDEs, shortcuts, &hellip;</li>
</ul>
<ol start="2">
<li><strong>Domain knowledge</strong>, such as:</li>
</ol>
<ul>
<li>Product-specific functional information</li>
<li>Diverse experience (combined with tech. knowledge, <code>18%</code>)</li>
</ul>
<ol start="3">
<li><strong>Brilliance</strong>: general intelligence (<code>13%</code>)</li>
<li><strong>Naivety</strong>: &lsquo;fresh&rsquo;/new to the problem at hand (<code>13%</code>)</li>
</ol>
<p>Knowing what an Observer pattern is also implies you have the capability to apply it to a given problem. These expertise parts reside in the yellow image, typically not overlapping other components. To be able to speak the language, one has first to learn the language. To learn anything, a certain degree of intelligence is required.</p>
<h4 id="b-motivational-component">b. Motivational Component</h4>
<p>A lack of motivation can be devastating to your mood and your willingness to solve things in the first place. The motivational component contains several layers of philosophical and psychological roots, not limited to simply intrinsic VS extrinsic motivation. This component is not specific too software development and very hard to foster within others (typically it is not sufficient to waive with green paper containing dollar sings&hellip;). <code>40%</code> is related to self-motivation.</p>
<p>Motivation (and to a certain extend, the other components as well) is also influenced by an invisible component, namely <strong>environment</strong>. This could be the company culture you&rsquo;re working in, the mood of your colleagues, or family and friends. <code>30%</code> is related to the qualities of the group you are in, while <code>17%</code> is related to social skills.</p>
<h4 id="c-creative-thinking-skills-component">c. Creative Thinking Skills Component</h4>
<p>This is the most interesting component in my opinion, and also the most severely lacking for a lot of developers. Even if your expertise component is full of technical information, it is not worth anything if you do not know how to combine these using techniques called &lsquo;<em>creative thinking skills</em>&rsquo;. These skills allow you to successfully combine your expertise to hopefully create something new and novel (the classic definition of creativity).</p>
<p>Typical creative skills are idea generation techniques such as <em>brainstorming</em>. However, according to Amabile<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, this component contains <code>41%</code> personality (persistence, curiosity, energy), and <code>38%</code> special cognitive abilities (described as &lsquo;special talents in problem solving&rsquo;). Changing your personality is more challenging than learning &lsquo;special talents&rsquo;. A. Miller identified cognitive processes associated with creativity, of which these six are the most interesting to look at from our perspective <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>:</p>
<blockquote>
<h5 id="1-_perspective-taking_-looking-at-a-problem-from-different-angles">1. <em>Perspective Taking</em>: Looking at a problem from different angles</h5>
</blockquote>
<p>A classic theoretical example is applying the first step in the computational thinking process by reducing concrete problems (e.g. four colors) into it&rsquo;s abstract counterpart (bintrees, graphs).</p>
<p>A more concrete example could be the following. You are responsible for implementing the generation of certain documents, which employees need to sign (interact with). Since you are used to think in terms of employers, you create a &lsquo;generate&rsquo; button for employers to click on, which will then send the documents to the employee. However, halfway through a colleague stops you and says &lsquo;wait, let us <em>look at the bigger picture</em> here. Is this the right location for the button? Why not let employees pull the documents instead of pushing? We already have such a system, let us find out.&rsquo; You both get up and walk to the domain model poster to re-evaluate what should be done.</p>
<blockquote>
<h5 id="2-_imagery_-imagining-potential-solutions-to-explore-the-potential">2. <em>Imagery</em>: Imagining potential solutions to explore the potential</h5>
</blockquote>
<p>For example, you are creating an API that will be used by other pieces of software within the company. You imagine it could be a simple HTTP POST. But as soon as you do that, you remember that hosting it will prove to be a challenge, and blocking unwanted calls or an overload of them will also cause problems. Then you imagine a service bus could work. Other endpoints could also hook into that. It would be easier to maintain.</p>
<blockquote>
<h5 id="3-_idea-generation_-generate-multiple-solutions-for-a-given-problem">3. <em>Idea generation</em>: Generate multiple solutions for a given problem</h5>
</blockquote>
<p>This one is quite straightforward. &lsquo;Okay, we need to query the customer DB for unknown addresses, but the table is huge. What options do we have?&rsquo; Take out a pencil and write down everything you can come up with. Cache the results after a first run? Create an index? Or cache customer related info at bootstrap? Create a cleanup script to run nightly? &hellip; Of course you are drawing on your expertise component here!</p>
<p>The &lsquo;<em>five why&rsquo;s</em>&rsquo; could also fall within this category, generating different ideas and drilling down until you find the &lsquo;root cause&rsquo; of the problem. It could also be part of no. 4.</p>
<blockquote>
<h5 id="4-_metaphoricalanalogical-thinking_">4. <em>Metaphorical/Analogical Thinking</em></h5>
</blockquote>
<p><strong>Connecting the current problem with related ones</strong>:</p>
<p>&lsquo;So we need to create yet another GET service that queries our DB. Wait, <em>haven&rsquo;t we done this before?</em>&rsquo; Taking a look at previous problems and trying to relate it to your current one can yield interesting results, such as reworking the previous one to better fit your current one, or simply using methods/services/&hellip; from another problem that you could not come up with on your own.</p>
<p>Over-familiarization is a well-known trap here. The adept you are at something, the less likely you will look at it differently and the more you will connect your problem with previously solved ones. In the end, everything will be done the same way, without experimenting with different approaches.</p>
<p><strong>Use previously used solutions in a new way</strong>:</p>
<p>Suppose you&rsquo;re really good at Java and you take on a new job as a C# developer. Congrats. Let&rsquo;s create an <code>enum</code>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C#" data-lang="C#"><span style="color:#728e00">enum</span> <span style="color:#434f54">EmployeeDocumentState</span> {
<span style="color:#434f54">GENERATING</span>,
<span style="color:#434f54">GENERATED</span>,
<span style="color:#434f54">UPLOADED</span>,
<span style="color:#434f54">SIGNED</span>,
<span style="color:#434f54">REJECTED</span>
}
</code></pre></div><p>Now let us write some domain-driven code. We need a <code>CanEmployeeInteractWith()</code> method that, depending on certain states, decides if an employee can do things with the document. Whoops. No can do: an <code>enum</code> in C# is essentially an <code>int</code>, inherited from C. In Java, you can write methods on them. Static extensions to the rescue:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C#" data-lang="C#"><span style="color:#728e00">static</span> <span style="color:#728e00">class</span> <span style="color:#434f54">EmployeeDocumentStateExtensions</span> {
<span style="color:#728e00">public</span> <span style="color:#728e00">static</span> <span style="color:#00979d">bool</span> <span style="color:#434f54">CanEmployeeInteractWith</span>(<span style="color:#728e00">this</span> <span style="color:#434f54">EmployeeDocumentState</span> <span style="color:#434f54">state</span>) {
<span style="color:#95a5a6">// ...
</span><span style="color:#95a5a6"></span> }
}
<span style="color:#00979d">var</span> <span style="color:#434f54">state</span> = <span style="color:#434f54">EmployeeDocumentState</span>.<span style="color:#434f54">SIGNED</span>;
<span style="color:#728e00">if</span>(<span style="color:#434f54">state</span>.<span style="color:#434f54">CanEmployeeInteractWith</span>()) { <span style="color:#95a5a6">// yes!
</span><span style="color:#95a5a6"></span> <span style="color:#434f54">button</span>.<span style="color:#434f54">enable</span>();
}
</code></pre></div><p>In essence, you are drawing on your Java knowledge to enhance your C# code. I wrote <a href="/post/faking-domain-logic/">an article about this</a> a few years ago. You could also enhance C <code>struct</code>s with function pointers to emulate objects, as <a href="/post/domain-driven-design-in-c/">explained in this blog post</a>.</p>
<p><strong>Combining dissimilar concepts into a new idea</strong>:</p>
<p>Drawing from information from outside your own domain could also be useful and generate inventive solutions. In fact that is how Velcro got invented: by studying the abilities of insects to climb walls and &lsquo;stick&rsquo; to material.</p>
<p>In Linguistic Creativity, creative patterns are hypothesized to be part of two categories: pattern-forming (following the rules of the language, creating interactions/repetitions) and pattern-reforming (breaking the rules and reshaping it into something new).</p>
<p><figure>
<a href="../creativepatterns.jpg" class="lbox">
<img loading="lazy" src="../creativepatterns.jpg" title="Creative Patterns?">
</a>
<figcaption>Creative Patterns?</figcaption>
</figure>
</p>
<blockquote>
<h5 id="5-_incubation_-letting-the-idea-ripen-for-a-while">5. <em>Incubation</em> (letting &lsquo;the idea ripen&rsquo; for a while)</h5>
</blockquote>
<p>Cognitive processes could be grouped into <strong>intuitive</strong> and <strong>deliberate</strong> processes. Intuitive processes will be very familiar with you. Taking a break from deciphering the problem, for instance, and going for a walk, or implicitly holding off on evaluating your own ideas. Good ideas are like good wine: the longer they ripe, the better they become.</p>
<p>But in the end, your boss expects you to implement that piece of functionality, not to wait for ages until it &lsquo;gets better&rsquo;&hellip;</p>
<blockquote>
<h5 id="6-_flow_-automatic-effortless-state-of-mind">6. <em>Flow</em> (automatic, effortless, state-of-mind)</h5>
</blockquote>
<p>During interviews conducted by A. Miller, people frequently mentioned that they &lsquo;get ideas when relaxed&rsquo;. What they are referring to is the state of <em>flow</em> in which everything seemingly is done without any effort. A lot of psychological research has been dedicated to this topic, and it is a bit less interesting compared to other cognitive processes because it is very hard to pinpoint - and because it&rsquo;s a bit too far from my core research.</p>
<h3 id="but-what-about-creative-problem-solving">But what about Creative Problem Solving?</h3>
<p>There is some confusion in literature regarding terms such as creative thinking, creative problem solving, and creative coding. To be honest, none of these fit well within the &lsquo;creative thinking skills&rsquo; component, at least in my mind.</p>
<p><strong><em>Creative Coding</em></strong> is an unfortunate term that has nothing to do with problem solving. What? Indeed. Creative coding is a recent phenomenon in which the emphasis is on <em>artful</em> creating, where expression is more relevant than solving things. You use code to express yourself, generating digital graphical &lsquo;art&rsquo;, using programming languages and tools such as <a href="https://processing.org">ProcessingJS</a>. Students following a creative coding course are encouraged to talk to people outside of their faculty and to experiment with different digital &lsquo;materials&rsquo; (code, languages, visualizations). Creativity is also not assessed as such. It&rsquo;s what would happen if Van Gogh would have access to the V8 engine. \<br>
It has yet to be investigated whether the teaching of artful creative coding will actually enhance practical creative skills.</p>
<p><strong><em>Creative Computing</em></strong> (or <em>Computational Creativity</em>) aims to simulate creativity using Artificial Intelligence, rather than stimulating it within the humans that are doing all the programming work. It could require creativity to write algorithms that show &lsquo;creative&rsquo; skills, but the emphasis is on the mechanical part of creativity. AI that creates music or art falls within this category.</p>
<p><strong><em>Creative Problem Solving</em></strong> on the other hand does put emphasis on problem solving, but in an inventive way. That is, it uses a model to help you overcome a problem or invent a new product. It&rsquo;s steps are Clarify (1), Ideate (2), Develop (3), and Implement (4). During each of these steps you will be needing different components of Amabile&rsquo;s model. <strong>CDIO</strong> (Conceive, Develop, Implement, Operate) has the same approach. CDIO was invented at MIT to make engineering students more like real-life engineers.</p>
<p><strong><em>Theory of Inventive Problem Solving</em></strong> (TRIZ) is a Russian problem-solving, analysis and forecasting framework derived from studying inventions. In my opinion, it has little to do with creativity, as you are instructed to follow a complex matrix based on previous inventions and patents, and it is very much geared towards physical engineering.</p>
<h3 id="to-conclude">To Conclude&hellip;</h3>
<p>People are not born creative. It takes a lot of hard work, on both the knowledge (expertise in area/domain, creativity skills) and personal skills (self-motivation, brilliance, personality) sides. But this does prove that <em>creativity</em>, however it is defined, is <strong>learnable</strong> (and thus hopefully also teachable). However, it is only relevant to teach/learn creativity within the context of the domain: <em>creativity is domain-specific</em><sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. This is true for each part of the Componential model:</p>
<ol>
<li><strong>Expertise</strong> is domain-specific by nature. Knowledge about bread baking and fermentation does not really help me solve problems in source code, and knowledge about design patterns does not help me bake a better bread. Baer even postulated that the question should not be <em>&ldquo;are you creative?&quot;</em> but rather <em>&ldquo;are you an expert?&quot;</em><sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. I wonder whether this might mean that the expertise component has a bigger influence on creativity than the others.</li>
<li><strong>Motivation</strong> is domain-specific. My enthousiasm for weeding the garden and planting and harvesting onions does not really help me when my motivation for fixing a bug in software is low. Motivation is not transferrable.</li>
<li><strong>Creative Thinking Skills</strong> are domain-specific. Even if <em>perspective-taking</em> or <em>imagery</em> could be applied to all kinds of problems, some domains prefer some creative skills more than others. You also cannot learn &lsquo;analogical thinking&rsquo; without giving domain-specific examples. When applying <em>perspective-taking</em> in bread baking, I might compare rye and wheat bread recipes, or try to combine those. The actions I take are entirely different than when looking at code in another way.</li>
</ol>
<p>Yes, everything can be abstracted and generalised - but not without paying a price. And yes, polymaths can be <em>experts</em> (or creative? Is this suddenly the same thing?) in multiple domains, but that does not mean they are reusing the same motivation/expertise/skill.</p>
<p>Our ultimate intention is to enhance higher education with the teaching of concrete creativity skills while using programming to tackle a problem. For that the identification of these cognitive processes need to be fleshed out. It also begs the question: how can we evaluate these? I&rsquo;ll have to let this idea mature for a while&hellip;</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>Amabile, Teresa M. &ldquo;Componential theory of creativity.&rdquo; Harvard Business School 12.96 (2012): 1-10. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Miller, Angie L. &ldquo;A self-report measure of cognitive processes associated with creativity.&rdquo; Creativity Research Journal 26.2 (2014): 203-218. <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Baer, John. &ldquo;Is creativity domain specific.&rdquo; The Cambridge handbook of creativity 321 (2010). <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 8 October 2019.
</p>
]]>
</description>
</item>
<item>
<title>De zin en onzin van conferenties</title>
<link>https://brainbaking.com/post/2019/09/de-zin-en-onzin-van-conferenties/</link>
<comments>https://brainbaking.com/post/2019/09/de-zin-en-onzin-van-conferenties/#commento</comments>
<pubDate>Mon, 23 Sep 2019 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2019/09/de-zin-en-onzin-van-conferenties/</guid>
<category domain="https://brainbaking.com/tags/conference">conference</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/conferenties.jpg"/>
</p>
<p>Bedrijven zien conferenties vaak als een onnodige kost waar hun werknemers nauwelijks worden naar toe gestuurd. Meestal gaat dit keurig af van het jaarlijks opleidingsbudget, ook weer keurig verrekend en verdeeld per persoon. Als Piet graag drie dagen wenst te gaan, en Jan in hetzelfde team ook, ontstaat er al een probleem: wie gaat dan die grote hoeveelheid dagelijkse problemen opkuisen? Er wordt een compromis gesloten: Piet en Jan mogen elk slechts één dag gaan, en elk op één aparte dag van het evenement. Misschien is Piet blij, omdat het thema hem dit jaar toch niet lag en hij gewoon een dag niet wou werken. De kans is even groot dat hij niet blij is, omdat hij terecht wou bijleren van experten in zijn vakgebied die binnen het bedrijf nog nauwelijks te vinden zijn.</p>
<p>Technische conferenties in de IT-wereld zijn best groot, bestaan uit verschillende dagen, behelzen verschillende maar allemaal even relevante thema&rsquo;s, en trekken internationale sprekers en luisteraars aan. In tegenstelling tot grote <em>get-togethers</em> in de privéwereld, trekken academische conferenties voornamelijk diezelfde academici aan. Om beide werelden beter te kunnen begrijpen, moeten we kijken naar wat hun drijft. Dat is in beide gevallen geld. De industrie beperkt het budget, zodat de <em>lucky few</em> wat know-how kan meenemen, liefst voorgekauwd, om onmiddellijk te kunnen opleveren in een of ander product. De nadruk ligt op het <em>ontvangen</em> van informatie (en uiteraard reclame maken).</p>
<p>Bij academici ligt dat een beetje anders. Daar staan het aantal publicaties gelijk aan geld. Publiceren kan in een &lsquo;boekje&rsquo;: ofwel een tijdschrift dat streng wordt gereguleerd (<em>journal</em>), ofwel een bundel van papers gerelateerd aan een thema van een bijeenkomst (<em>conference proceeding</em>). Dat betekent in de praktijk dat het leeuwendeel van de gasten op een academische conferentie zelf ook auteurs zijn. Als je niet presenteert, verschijnt het niet in de bundel, en is er geen publicatie - en dus geen geld. De nadruk ligt op het <em>versturen</em> van informatie.</p>
<p>Beide werelden hebben zo hun problemen. In het eerste geval komen veel werknemers opdagen omdat ze gewoon geen zin hebben om een dag op kantoor te spenderen, en omdat er nog wat budget te spenderen was - dit jaar niet opgebruikt is geen potje voor volgend jaar. Er wordt goed gegeten en gelachen, en omdat de baas dat vraagt, een verslagje geschreven. Presentaties worden over het algemeen gehouden door echte consultants die weten wat ze moeten vertellen, en hoe. Een aantal slots zijn simpelweg gekocht door bedrijven, en zijn verdoken reclame om mensen die hun werk beu zijn te overhalen elders een contract te tekenen. Presentaties zijn vaak technisch, diepgaand, en vooral praktisch.</p>
<p>In het tweede geval komen academici opdagen omdat ze moeten presenteren. Dat gebeurt in paralelle sessies waarbij iedereen een kwartier tot twintig minuten de tijd krijgt om een paper van tien pagina&rsquo;s samen te vatten. Dat klinkt als een goed idee, op voorwaarde dat geen alinea&rsquo;s domweg gekopieerd worden op de slides, om ze vervolgens voor te lezen. Presentaties zijn vaak theoretisch, en vooral droog. Het aantal aanwezigen per sessie varieert sterk, waarbij het aantal oplettende personen jammer genoeg aan de lage kant is. Jaak is zijn presentatie mentaal aan het voorbereiden terwijl Lowie de zijne aframmelt. Jozef weet na de derde slide met 100 woorden niet meer over wat het gaat en grijpt naar zijn GSM om te kijken hoe het met de wereld gesteld is. Dit fenomeen heeft tegenwoordig zijn eigen term, &lsquo;<strong><a href="https://en.wikipedia.org/wiki/Phubbing">phubbing</a></strong>&rsquo;, gekregen. Yannick is al een halfuur als een gek zijn inbox aan het opkuisen, want niemand heeft eigenlijk de tijd om op de conferentie aanwezig te zijn. Zenuwachtige doctoraatsstudenten, buitenlandse sprekers met een te zwaar accent, en oude rectoren die graag nog een onnodig woordje uitleg geven over hun universiteit - ze zijn allemaal aanwezig.</p>
<p>Dat brengt ons bij de vraag: <em>waarom?</em> Sommigen zullen ongetwijfeld antwoorden &lsquo;<em>omdat ik mensen leer kennen waar ik mee kan samen werken</em>&rsquo;. Anderen met &lsquo;<em>omdat het lekker eten inbegrepen is, en ik naar het buitenland mag!</em>&rsquo; Het verschil in type en sfeer op een conferentie van de industrie en de academische wereld is erg treffend. Terwijl de privé wereld graag een stukje direct inzetbare kennis mee naar huis neemt, hoop de academicus op een potentiële toekomstige vruchtbare samenwerking. In beide gevallen viel het me op hoe oneerbiedig een publiek kan zijn naar de spreker toe, op het moment dat die GSM&rsquo;s uit de broekzak worden gehaald, en de laptops opengeklapt. Ik hoorde op de laatste conferentie bij het vraag- en antwoordmoment iemand zeggen:</p>
<blockquote>
<p>Thank you, that was a good presentation. You forced me to close my laptop and listen.</p>
</blockquote>
<p>Alsof er gewoon wordt verondersteld dat dit bijna nooit <em>hoort</em> te gebeuren. Werken kan, tussendoor - nee: het moet. Ik zit hier gewoon omwille van mijn eigen presentatie. Op die momenten krijgt de onzin de overhand, om nog maar te zwijgen van de ecologische gevolgen van een vliegtripje van enkele dagen. Het is trouwens schrijnend om te zien hoe weinig mensen effectief kunnen presenteren in de academische wereld - en dat zijn dan professoren die dit elke dag doen. Dit probleem ervaar ik om een of andere reden als veel minder erg in de privéwereld. Het doet me wat denken aan <a href="https://arnoutvandenbossche.be">Arnout Van den Bossche</a> zijn show &lsquo;burn-out voor beginners&rsquo;, waarin hij terecht de draak steekt met de gemiddelde PowerPoint gebruiker.</p>
<p>Uiteraard pleit ook ik schuldig. Ik heb presentaties gegeven voor volle filmzalen als software ontwikkelaar bij <a href="https://devoxx.be">Devoxx</a>, en ik heb korte presentaties gegeven als doctoraatsstudent bij lokale universiteiten. In beide gevallen waren er andere interessante en minder interessante sessies, in beide gevallen durfde ik al eens eentje overslaan, en in beide gevallen geloof ik dat het op een of andere manier wel nuttig was. Maar misschien wordt het tijd om eens kritisch te kijken naar het concept. Misschien kunnen er wat onnodige ruwe kantjes glad geveild worden. Minder nadruk op publicaties en meer op presentaties, bijvoorbeeld, of de GSM en laptop in het hotel laten als je niet zelf moet presenteren. Notities nemen kan nog steeds met iets dat &lsquo;pen en papier&rsquo; heet, hoe voorhistorisch dit ook klinkt. Sprekers die nog nooit een <a href="https://www.ted.com/#/">TED</a> <em>talk</em> gezien hebben of nog nooit <a href="https://www.presentationzen.com">Presentation Zen</a> gelezen hebben worden automatisch geweigerd.</p>
<p>Verhaaltjes vertellen trekt niet alleen kinderen aan, maar doet ook je publiek <em>opletten</em>:</p>
<blockquote>
<p>Time after time, when faced with the task of persuading a group of managers&hellip; to get enthusiastic about a major change, storytelling was the only thing that worked. <span>Stephen Denning, The Leader&rsquo;s Guide to Storytelling</span></p>
</blockquote>
<p>Het &lsquo;<em>presenteren voor publiceren</em>&rsquo; motto slaat op niets en werkt bovenstaande punten volledig in de hand. Nog niet de helft van de aanvaarde papers zijn interessant genoeg om iets over te vertellen, en dat geldt ook voor mijn eigen werk. Zonder praktische demo&rsquo;s zijn de erg snel op elkaar volgende sessies na een tijdje moeilijker verteerbaar.</p>
<p>Het is dan ook niet verwonderlijk dat naargelang de dagen van de conferentie vorderen, meer en meer mensen een frisse neus halen en &lsquo;per ongeluk&rsquo; te laat of niet meer terugkomen.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 23 September 2019.
</p>
]]>
</description>
</item>
<item>
<title>Teaching Object-Oriented design using the GBA</title>
<link>https://brainbaking.com/post/2019/04/teaching-oo-with-gba/</link>
<comments>https://brainbaking.com/post/2019/04/teaching-oo-with-gba/#commento</comments>
<pubDate>Mon, 15 Apr 2019 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2019/04/teaching-oo-with-gba/</guid>
<category domain="https://brainbaking.com/tags/teaching">teaching</category>
<category domain="https://brainbaking.com/tags/gba">gba</category>
<category domain="https://brainbaking.com/tags/C&#43;&#43;">C&#43;&#43;</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/gbacarts.jpg"/>
</p>
<p>Electrical Engineering students have to work through a programming course in their third year at KU Leuven, a course called &lsquo;<a href="https://kuleuven-diepenbeek.github.io/cpp-course/">Software Design in C/C++</a>&rsquo;. This course is one of the things I inherited from my retired colleague when I started working for the University. As is the case with most programming courses, it&rsquo;s contents was <em>boring as hell</em>.</p>
<p>So, instead of simply making minor adjustments to the syllabus and calling it a day, in the summer of 2018 I decided to throw everything in the begin and start over - hooray, a <em>greenfield</em> project! This was one of the rare opportunities for me to do so as most other courses are taught together with others. This one wasn&rsquo;t, I also had to lecture theory and administer exams. coincidentally, also in that very same summer, I re-found my love for the retro Game Boy, and started wondering how to program games for it. My knowledge of C and C++ was limited to a few years of practical use in the industry, working on administrative Windows MFC applications.</p>
<p>I got to work, by scanning documentation, cursing and swearing <em>a lot</em>, and ultimately learning how to create games for the Game Boy Advance. Most if not all GBA games are written in <code>C</code>. As much as I like simple elegance, I did opt for <code>C++</code> instead, because I wanted to bring in object-orientation and unit testing the way I was used to these, like in <code>C#</code> and Java. That also means getting used to the ugliness of C++. Oh well.</p>
<p>At the end of February 2019, all (but one) students finished their project, creating a game (concept) on the GBA, all working on the actual hardware, tested with a EZ-DRIVE cartridge. The result is compiled in the following 6-minute video:</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="https://player.vimeo.com/video/314203871" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="vimeo video" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>
<br/>
I'm actually really proud of what they achieved. Developing something for the GB(A) is notoriously hard if you are not familiar with the architecture. Some examples of 'challenges' (sources of swearing):
<ul>
<li>There is no OS. Nothing is managed. Do it yourself.</li>
<li>Hardware interaction is done through address memory mapping. That means reading and writing byte streams to hard-wired pointers.</li>
<li>Forget debugging.</li>
<li>Graphics is another tough nut to crack, using optimized sprites, a shared palette, and other techniques needed because of the limited (hardware) space.</li>
</ul>
<p>All those things are extras, the main point of the course is to learn object-oriented development, close to the hardware. Most students had difficulties enough with the <code>C++</code> syntax. They did complete another programming course, software design in Java, but that seemed to be long lost and forgotten, as is usually the case with hard working students.</p>
<p>To ease their pain, I created a concept framework in <code>C++</code>, called &lsquo;<a href="https://github.com/wgroeneveld/gba-sprite-engine/"><i class='fa fa-github'></i> gba-sprite-engine</a>&rsquo; (available on GitHub through that link), which students had to fork, compile, and use for their projects. It comes equipped with a few demo projects, and throughout the different labs, we worked our way through the GBA&rsquo;s conceptual hardware model, using the following outlines as a guideline:</p>
<ol>
<li><a href="https://kuleuven-diepenbeek.github.io/cpp-course/c/labo-1/">Introduction in C</a></li>
<li><a href="https://kuleuven-diepenbeek.github.io/cpp-course/c/labo-2/">Pointers in C and C++</a></li>
<li><a href="https://kuleuven-diepenbeek.github.io/cpp-course/gba-in-c/labo-3/">GBA Programming in C: an introduction</a></li>
<li><a href="https://kuleuven-diepenbeek.github.io/cpp-course/gba-in-c/labo-4/">GBA Programming in C: tilesets, a simple game</a></li>
<li><a href="https://kuleuven-diepenbeek.github.io/cpp-course/cpp/labo-5/">Introduction in C++</a></li>
<li><a href="https://kuleuven-diepenbeek.github.io/cpp-course/cpp/labo-6/">C++ Class Inheritance, operators and templates</a></li>
<li><a href="https://kuleuven-diepenbeek.github.io/cpp-course/cpp/labo-7/">Software design: thinking and testing before coding</a></li>
<li><a href="https://kuleuven-diepenbeek.github.io/cpp-course/gba-in-cpp/labo-8/">GBA Programming in C++: an abstraction layer</a></li>
<li><a href="https://kuleuven-diepenbeek.github.io/cpp-course/gba-in-cpp/labo-9/">GBA Programming in C++: scrolling backgrounds</a></li>
</ol>
<p>The syllabus is accessible through the links, although in Dutch.</p>
<p>Especially the live Castlevania demo&rsquo;s were quite appealing to students, showcasing sprite design, different backgrounds, and the palette:</p>
<p><figure>
<a href="../aria-of-sorrow.gif" class="lbox">
<img loading="lazy" src="../aria-of-sorrow.gif" alt="Aria of Sorrow" >
</a>
</figure>
</p>
<p>God I love that game. I&rsquo;ll gladly take every opportunity I have to look and/or play it.</p>
<p>The sprite engine does the heavy lifting in terms of image memory allocation and storage, and provides some abstract concepts for sprites/backgrounds/music/scenes. But not before we&rsquo;ve seen these in the labs ourselves (lab 1-4). Take a look at the <a href="https://github.com/wgroeneveld/gba-sprite-engine/"><i class='fa fa-github'></i> GitHub documentation of the engine</a> to get a better picture on the included features. (For the most part) Unit tested and all. It is cross-platform compatible, as the GBA is actually an ARM machine, you&rsquo;ll be needing a cross-compiler from the <a href="https://devkitpro.org/wiki/Getting_Started">DevKitPro toolchain</a>.</p>
<p>The emphasis lies on the <em>object-oriented</em> part of the course title, that is why the design of the game, and game engine, was very important to me. If you are creating a platformer like Mario, and you can jump, grab coins, and squash enemies, then I want to see that reflected in your design. Where is the statement <code>mario.jump()</code>, where are the <code>class Coin</code> and <code>class Goomba : public Enemy</code> definitions? You can extend from the following engine parts:</p>
<p><figure>
<a href="https://github.com/wgroeneveld/gba-sprite-engine/raw/master/img/design.png?raw=true" class="lbox">
<img loading="lazy" src="https://github.com/wgroeneveld/gba-sprite-engine/raw/master/img/design.png?raw=true" alt="gba-sprite-engine design" >
</a>
</figure>
</p>
<p>After the oral defense of their game, students completed a short survey that helped me assess what to do with the course during the next academic year. Most students were very enthusiastic regarding the inclusion of the GBA, compared to another dull set of assignments. They also responded positively to the question whether the Game Boy could be used in other courses as well, such as hardware architecture design, or (advanced) chip design (using an FPGA).</p>
<p>I&rsquo;m happy they liked it, and although the theoretical exam results were not that promising, the practical projects were. We will be using more or less the same course contents next year. After academic year 2019 - 2020, the course will sadly disappear into two other courses: the C hardware-related part will merge into a more OS-oriented course, and the C++ object-oriented design part will merge into a software engineering-oriented course. Both new courses still need to be planned and implemented.</p>
<p>That means there&rsquo;s still a chance for me to sneak in Castlevania, right?</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 15 April 2019.
</p>
]]>
</description>
</item>
<item>
<title>IT Competences and Certificates</title>
<link>https://brainbaking.com/post/2019/02/competences-and-certificates/</link>
<comments>https://brainbaking.com/post/2019/02/competences-and-certificates/#commento</comments>
<pubDate>Tue, 05 Feb 2019 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2019/02/competences-and-certificates/</guid>
<category domain="https://brainbaking.com/tags/competences">competences</category>
<category domain="https://brainbaking.com/tags/certificates">certificates</category>
<category domain="https://brainbaking.com/tags/phd">phd</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/generic.jpg"/>
</p>
<p>My research on soft skills in software engineering has brought me to many shady places so far. These places are dark, murky, and carry the rotten smell of mold. Welcome to the wonderful world of &ldquo;<em>you&rsquo;re doing it wrong</em>&quot;: professional competence <em>frameworks</em>. To add more strength to my point, the header image of this article is a generic one, grabbed from <a href="https://pexels.com">Pexels</a>, using the search term &ldquo;corporate&rdquo;. Can it <em>be</em> any more enterprise-y? Right, Chandler? By taking a closer look at what some of these frameworks are trying to accomplish, we can identify what it is doing well - and what it is doing wrong.</p>
<h3 id="efforts-to-create-a-professionalism-framework">Efforts to create a Professionalism Framework</h3>
<ul>
<li><a href="http://ictprofessionalism.eu/the-it-professionalism-framework/">IT Professionalism</a> framework in Europe.</li>
</ul>
<p>The more I try to learn about these frameworks, the more <a href="https://ec.europa.eu/ploteus/content/descriptors-page">my headache</a> - <a href="http://www.ecvet-toolkit.eu">gets</a> - <a href="http://www.ecompetences.eu">worse</a>. The <a href="http://ictprofessionalism.eu/wp-content/uploads/Final-report_EASME_COSME-5.pdf">final report</a> on &ldquo;Development and implementation of a European framework for IT Professionalism&rdquo; is 207 pages long. That&rsquo;s longer than most doctoral dissertations&hellip; Close your eyes for dubious company logo&rsquo;s spread throughout the document.</p>
<blockquote>
<p>If we fail to take steps to mature the IT profession, it is likely that the risks to society from IT will grow to unacceptable levels.</p>
</blockquote>
<p>Throughout the document, emphasis is put on creating (or losing) economical value. Is it time to read Piketty again? The gap between industry requirements (in terms of workforce, or what they dare to call it, &ldquo;resources&rdquo;, and in terms of required knowledge and skills) and the available labor market, delivered by learning institutes, is not denied. In fact, it&rsquo;s expressed in a loss of millions of dollars within a few years because companies cannot grow without filling these vacancies.</p>
<p>And so this initiative reveals its actual goals. Even if they claim to synthesize the lessons learned from the experiences in the IT domain, I cannot see nor smell anything that points towards that direction. Can it be used for practitioners in any way? To &ldquo;orient and support IT practitioners throughout the professional life cycle&rdquo;? I doubt it. Oh, and the word &ldquo;certification&rdquo; is another common occurrence.</p>
<h3 id="efforts-to-categorize-it-competences">Efforts to categorize IT Competences</h3>
<ul>
<li><a href="https://cepisecompetencebenchmark.org/">CEPIS</a> e-Competence bank (<em>Council of European Professional Informatics Societies</em>)</li>
</ul>
<p>Most of these initiatives mean you fill in a lot of questions divided into different categories, and the end result is a near-perfect match with an IT profile, such as &ldquo;test specialist&rdquo; or &ldquo;enterprise architect&rdquo;. There are a couple of reasons why this does not work. <br/>
First of all, <strong>non-technical</strong> abilities are completely ignored. The CEPIS survey asks me to answer questions within the plan, build, run, enable and manage categories. Where is empathy, self-efficacy, engagement and motivation? Where are the virtues and vices? <br/>
Second, <strong>context</strong> is missing. What&rsquo;s an enterprise architect? Does this mean I get to play with toys? Each profile is carefully defined to be applicable for any large company, but yet generic enough to be completely useless. <br/>
Third, thinking <em>inside</em> the box instead of <em>outside</em> <strong>hurts creativity</strong> enormously. If I&rsquo;m a test specialist, why wouldn&rsquo;t I be able to do certain tasks of an enterprise architect? These frameworks are still thinking in terms of <em>functions</em>, not <em>roles</em>. In your daily work as a software developer, you&rsquo;re the architect one day and the tester the next. Or even in a shorter timespan. Yet you never adhere to the rules of a carefully described competence profile. It&rsquo;s simply worthless.</p>
<p><figure>
<a href="../cepis.jpg" class="lbox">
<img loading="lazy" src="../cepis.jpg" title="Does this mean anything to you?">
</a>
<figcaption>Does this mean anything to you?</figcaption>
</figure>
</p>
<ul>
<li>fBOK (<em>Foundational IT Body of Knowledge</em>)</li>
<li><a href="https://www.computer.org/web/swebok">SWEBOK</a> (<em>Software Engineering Body of Knowledge</em>).</li>
<li><a href="https://online-journals.org/index.php/i-jep/article/view/4047">SWEBOS</a> (<em>Software Engineering Body of Skills</em>)</li>
</ul>
<blockquote>
<p>&ldquo;Bridge the gap between college and industry&rdquo;</p>
</blockquote>
<p>Of course a framework is worthless without the right <a href="https://www.computer.org/web/education/swebok-certificate-program">Certification Program</a>. The slogan sounds promising but completely fails to deliver. Read <a href="https://martinfowler.com/bliki/Swebok.html">What Martin Fowler has to say</a> on this:</p>
<blockquote>
<p>There are hoards of IEEE standards out there that are routinely ignored by anyone doing commercial software development. Mostly they were written by academics and those engaged in large government projects. Business people don&rsquo;t consider government as a synonym for efficiency.</p>
</blockquote>
<p>Recently I&rsquo;m also part of this academic world. Based on the amount of closed-access papers I have read as part of my research (<code>+100</code>), I&rsquo;m very sad to say that he is absolutely right. But that does not mean academics should not do research in this area at all. Rather, it means that a big, rigid framework like this, is not something companies are waiting for. Instead, we (the academics) should focus on how to improve education <strong>in conjunction with experts</strong> from the field. Theoretical models are here to stay though: they provide a useful foundation for further discuss the work, but shouldn&rsquo;t be commercialized in the form of a (competence) framework.</p>
<p>Another problem is - again - the lack of non-technical abilities. This is mitigated in &ldquo;SWEBOS&rdquo;, an academic &ldquo;approach of further development and sustainable improvement of software engineering (higher) education&rdquo; (<a href="https://www.evelinprojekt.de/en/">source</a>). The identification of these skills instead of knowledges has been based on job vacancy keyword analysis, combined with focus groups. The result is promising, but still too vague.</p>
<h3 id="efforts-to-reinvent-software-engineering">Efforts to reinvent Software Engineering</h3>
<ul>
<li><a href="http://semat.org">SEMAT</a> (<em>Software Engineering Method and Theory</em>). <a href="https://martinfowler.com/bliki/Semat.html">What Martin Fowler has to say</a>.</li>
</ul>
<p>Don&rsquo;t be fooled by the <code>.org</code> domain name: you are still heavily encouraged to participate in one of the many workshops about this new method and theory. This initiative comes from, among others, the creator of the <a href="https://www.ivarjacobson.com/scaled-agile-framework">Scaled Agile Framework safE</a> and it is even trademarked. These beasts are used to tame and encourage investment banks to spend money towards agile translations. Yup, certification is available. For only <code>£2395</code>, you&rsquo;ll be awarded with the &ldquo;Safe Program Consultant&rdquo; certificate. Don&rsquo;t forget to renew your training every few years! Sutherland&rsquo;s &ldquo;Certified Scrum Master&rdquo; programs also come with a limited use-by date - a lucrative profit model, but hardly an educational sound basis. I used to be one of the poor consultants that got &ldquo;certified up&rdquo; by its company, in order to increase my daily rate, of which I of course never saw anything myself.</p>
<ul>
<li><a href="http://manifesto.softwarecraftsmanship.org">Software Craftsmanship</a> manifesto</li>
</ul>
<p>Is programming a craft? Is it a proper <em>profession</em>? Dan North <a href="https://dannorth.net/2011/01/11/programming-is-not-a-craft/">says it isn&rsquo;t</a>:</p>
<p><em>It would be great if programming were a proper profession, but it isnt. A profession has a structured model for advancing through levels of skill and ability, be it studying for a law degree and articles (working for a legal practice) or the years of undergraduate and medical training a doctor undertakes before specializing. The latter has clearly-delineated ranks, from junior doctor, via a brutal regime of 80-hour weeks, to constant.</em></p>
<p><em>Conversely there is no minimum entry requirement for programming. Some people naturally have a flair for it (two of the best programmers I know never went to college), some teach themselves out of books, others just tinker until they get something working. A programmers skill and ability is only as good as their personal reputation: there isnt an accepted, transferable ranking like there is in a “proper” profession.</em></p>
<p>It&rsquo;s a <a href="https://lizkeogh.com/2011/01/14/why-i-didnt-sign-the-software-craftsmanship-manifesto/">heated debate</a>, joined by many well-known technological experts out there. Melissa McEwen goes so far as to call it <a href="https://qz.com/work/1371151/what-happened-to-software-craftsmanship/">the product of a 10-year-old development manifesto</a>. The problems exposed by each of these articles has been tried to mitigate in SEMAT, resulting in something completely different, with it&rsquo;s own set of misery. As Dan said it, these attempts are at risk of letting programmers egos run riot - and I&rsquo;ve seen that happen all too often when still working in <a href="/post/a-decade-in-the-industry/">the industry</a>.</p>
<h3 id="so-useful-or-not">So&hellip; Useful or not?</h3>
<p>Yes and no.</p>
<p>Yes:</p>
<ol>
<li>Creates a high-level profile list, too see what the possibilities are</li>
<li>Creates a common model to talk about</li>
<li>Somewhat useful as an economic forecast</li>
<li>Brings the skills gap to attention of (international) politics</li>
</ol>
<p>No:</p>
<ol>
<li>Creates a too bland, too high-level model that does not say anything at all</li>
<li>Completely ignores important non-technical skills</li>
<li>Lags behind important technical skills because it takes years to develop</li>
<li>Involves an unbalanced group of stakeholders</li>
</ol>
<p>For those reasons, it is not usable by educators. For those reasons, it is not workable for my research topic. At least now I know what to add to the &ldquo;not-to-focus-on&rdquo; list. In my opinion, these professionalism frameworks are a waste of money and talent. To think what could be improved in education with that much time and resources&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 5 February 2019.
</p>
]]>
</description>
</item>
<item>
<title>A Ph.D. Thesis: Iteration 2</title>
<link>https://brainbaking.com/post/2019/01/phd-iteration-2/</link>
<comments>https://brainbaking.com/post/2019/01/phd-iteration-2/#commento</comments>
<pubDate>Thu, 03 Jan 2019 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2019/01/phd-iteration-2/</guid>
<category domain="https://brainbaking.com/tags/phd">phd</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/humboldt.jpg"/>
</p>
<p>A huge amount of ideas and a quite a few months later, my original <a href="/post/phd-proposal/">proposal</a>, called <em>&ldquo;The disparity between industrial requirements and classic education of modern software engineering.&quot;</em>, changed for the better. The approved abstract is called <em>&ldquo;Improving software engineering education by closing the gap with modern non-technical industrial requirements&rdquo;</em>. After struggling to find any focus (and reference material to work with), I now settle with:</p>
<blockquote>
<p>Mastering Lean Skills in Software Engineering Education</p>
</blockquote>
<h3 id="defining-what-a-skill-is">Defining what a skill is</h3>
<p>These &ldquo;lean skills&rdquo; refer to the required skillset of modern software engineering practitioners. The skills themselves are not quite modern or new, but the ever evolving software development industry increasinly demands good noncognitive abilities next to conventional cognitive thinking - something that is on the rise for the last 10 years. Identifying non-technical requirements has been done plenty of times before and took on the form of the <a href="https://www.computer.org/web/swebok">SWEBOK</a> model and the like.</p>
<p>The problem with educational software engineering research in this area, is that either the papers are extremely vague, or they are too broad. Radermacher <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> and Sedelmaier <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> for instance identified missing soft skills in engineering education, but those skills do not speak for themselves: &ldquo;project management&rdquo;, &ldquo;personal skills&rdquo;, &ldquo;ethics&rdquo;, &ldquo;oral communication&rdquo;. I tried to create an overview of these papers as an introduction for myself into the topics and research world but ended up frustrated and confused. It also of course consumed some valuable months of my time&hellip;</p>
<p>Simply trying to pin down these terms by defining them seems to be a daunting task that will likely never receive a consensus<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. For example, I tried to <a href="https://wgroeneveld.github.io/phd/src/definities/">define</a> the differences between &ldquo;skill&rdquo;, &ldquo;ability&rdquo;, &ldquo;knowledge&rdquo; and &ldquo;competence&rdquo;. It took me more than a week and I gave up: every author gives his or hers own interpretation to these terms.</p>
<p><figure>
<a href="../skills.jpg" class="lbox">
<img loading="lazy" src="../skills.jpg" alt="noncognitive skills" title="What to call &#39;noncognitive skills&#39;?">
</a>
<figcaption>What to call &#39;noncognitive skills&#39;?</figcaption>
</figure>
</p>
<p>Since my background is with Computer Science and I&rsquo;ve been a software engineer for 11 years, I&rsquo;d like to incorporate this experience into my future work by concretizing these vague &ldquo;skills&rdquo; into something that people from the engineering industry understand and can work with. In the end, I&rsquo;ll have to define my own interpretation of the words &ldquo;lean skills&rdquo;.</p>
<p>The word <em>skill</em> is arguably not ideal as it may exclude beliefs (mindset) and values, as opposed to a skill that can be learned.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> At least it is better than the much more rigid word <em>trait</em>. The word <em>lean</em> is also problematic: it may trigger people familiar with <em>lean manufacturing</em> to think only about those principles. While it&rsquo;s intentionally related, I don&rsquo;t want to limit identification to that particular kind of manufacturing or software development. Until I come up with something better, it will have to do.</p>
<h3 id="knowing-what-to-work-with">Knowing what to work with</h3>
<p>To be able to uniquely contribute to software engineering education research, the aim is to combine insights across multiple disciplines. I&rsquo;m an avid philosophy and psychology reader and recognize the need for integration of certain key principles from these worlds into a more technical, engineering world.</p>
<p>Let&rsquo;s try to create an overview of important work in each area that would translate well into engineering education:</p>
<h4 id="philosophy">Philosophy</h4>
<ol>
<li><em>Self-cultivation</em> (Bildung), Humboldt</li>
<li><em>Virtues</em> and <em>eudaimonia</em>, Aristotle</li>
<li><em>Self-control</em>, Seneca and Aurelius</li>
<li><em>How to live</em>, Montaigne (and others)</li>
</ol>
<p>Avoid emphasis on Metaphysics and (pure) Ethics.</p>
<h4 id="psychology">Psychology</h4>
<ol>
<li><em>Grit</em>, Duckworth</li>
<li><em>Flow</em>, Csikszentmihalyi</li>
<li><em>Mindset</em>, Dweck</li>
<li><em>Thinking, fast &amp; Flow</em>, Kahneman</li>
</ol>
<h4 id="software-engineering">Software Engineering</h4>
<ol>
<li><em>Software craftsmanship</em>, McBreen</li>
<li><em>Lean software development</em>, Toyota Manufacturing</li>
<li><em>Extreme Programming</em>, Beck</li>
<li><em>PeopleWare</em>, DeMarco</li>
<li><em>Pragmatic Thinking &amp; Learning</em>, Hunt</li>
</ol>
<p>Almost all works suffer from a number of problems:</p>
<ul>
<li>Too theoretical (e.g. Metaphysics, theoretical Computer Science)</li>
<li>Too superficial (e.g. &ldquo;The passionate programmer&rdquo;)</li>
<li>Too vague (e.g. 95% of all academic papers?)</li>
<li>Too much usage of buzz-words (e.g. &ldquo;Management 3.0&rdquo;)</li>
<li>Too little research-based (e.g. &ldquo;Drive&rdquo;)</li>
<li>&hellip;</li>
</ul>
<p>It will be about finding the greatest common divisor and getting out of the way of vague or popular terms (&ldquo;business&rdquo;!). As you might have guessed, there are overlappings - the obvious one being <em>PeopleWare</em> as part of engineering and social psychology. Of course, grit and flow are natural evolutions of philosophical insights. There is plenty of techincal work released in the software engineering world based on these insights, although that is not immediately clear.</p>
<h3 id="a-practical-philosphy-for-engineering-education">A Practical Philosphy for Engineering Education</h3>
<p>To be able to effectively master these &ldquo;lean skills&rdquo;, principles from all worlds could be extracted and reformulated into a practical philosophy (course), geared towards (software) engineering students.</p>
<p>This can be as technical as we want it to be. For example, take the excellent idea of studying <a href="https://pragprog.com/book/btlang/seven-languages-in-seven-weeks">7 programmings languages in 7 weeks</a>. To facilitate rapid learning that is required in a modern ever-changing software engineering world, requiring students to adapt to a new language every week would serve the purpose of building resilience to constant change. This exercise will be theoretically substantiated by drawing from philosophical and psychological research. Without this step, students would not have a firm understanding of <a href="post/teaching-philosophy-first/">why this resilience is needed</a>, and they will not be able to translate what they have learned into the real world after graduating.</p>
<script defer src="/mermaid/mermaid.min.js">
mermaid.initialize({
startOnLoad: true,
flowchart: {
useMaxWidth: true
}
});
</script>
<div class="mermaid" align="center" >
graph LR;
A(Philosophy)
B(Psychology)
C(Software Engineering)
A --> C
A -.-> B
B --> C
</div>
<p>I have yet to come across a good body of work emerged from within the Software Engineering world that successfully combines these ideas. Engineering research is typically very technical, and engineering education research as stated before either too vague or too pedagogical. Philosophy isn&rsquo;t exactly popular, especially among pragmatic engineers. University faculties do not usually work outside their own safe boundaries.</p>
<p>That said, I&rsquo;m actually still struggling how to integrate what I want to do with what I have to do. Scientific (educational) research needs to contain well-defined questions, substantiated by references to more existing research. It&rsquo;s very easy to fall into the &ldquo;vagueness&rdquo; trap, especially if your thesis subject is too broad.</p>
<p>To remind myself of the constant dilemma between <strong>focus</strong> and <strong>exploration</strong>, I&rsquo;ll end with a quote from Maryam Mirzaei&rsquo;s research on PhD research<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>:</p>
<blockquote>
<p>In fact, figuring out the scope is the prime challenge of completing a PhD. (&hellip;) The ambiguity of scope can also manifest itself in lack of positioning. Not having a clear overall argument is an important reason for PhD failure. The project &lsquo;thesis&rsquo;, the story and the new idea, spread too widely and too thinly can result in failure.</p>
</blockquote>
<p><a href="https://www.npr.org/sections/ed/2015/05/28/404684712/non-academic-skills-are-key-to-success-but-what-should-we-call-them?t=1540302642056">Figure src</a></p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>Radermacher, Alex, and Gursimran Walia. &ldquo;Gaps between industry expectations and the abilities of graduates.&rdquo; Proceeding of the 44th ACM technical symposium on Computer science education. ACM, 2013. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Sedelmaier, Yvonne, and Dieter Landes. &ldquo;Software engineering body of skills (SWEBOS).&rdquo; Global Engineering Education Conference (EDUCON), 2014 IEEE. IEEE, 2014. <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Duckworth, Angela L., and David Scott Yeager. &ldquo;Measurement matters: Assessing personal qualities other than cognitive ability for educational purposes.&rdquo; Educational Researcher 44.4 (2015): 237-251. <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>Mirzaei, Maryam, and Mabin, Victoria J. &ldquo;The PhD in light of Project Management.&rdquo; Proceedings of the 2013 Joint NZSA+ORSNZ Conference, 2013. <a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 3 January 2019.
</p>
]]>
</description>
</item>
<item>
<title>Over analoog en digitaal</title>
<link>https://brainbaking.com/post/2018/12/over-analoog-en-digitaal/</link>
<comments>https://brainbaking.com/post/2018/12/over-analoog-en-digitaal/#commento</comments>
<pubDate>Sat, 22 Dec 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/12/over-analoog-en-digitaal/</guid>
<category domain="https://brainbaking.com/tags/games">games</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/snes_header.jpg"/>
</p>
<p>Eens blazen en hem &ldquo;<em>er uit en weer in steken</em>&rdquo; - aan wat doet deze vreemde uitspraak denken? Zedige kinderen die opgroeiden in de jaren &lsquo;90 denken hopelijk onmiddellijk aan een console <em>cartridge</em>: slecht contact met de console zelf door mogelijke stofjes zorgde er voor dat je console spel niet goed opstartte. De gebruikelijke handeling om het ding terug draaiende te krijgen was de <em>cartridge</em> uit de console trekken, eens goed op de contacten &ldquo;blazen&rdquo;, en hem er goed terug in <em>drukken</em>. Met wat geluk kreeg je dan wel het gewilde &ldquo;pling&rdquo; geluidje te horen van een Super Nintendo die dan toch maar toegeeft dat een spel geladen wordt.</p>
<p>De recente heruitgave van deze klassieke console, de &ldquo;<a href="https://www.nintendo.com/super-nes-classic/">SNES Mini Classic</a>&rdquo;, doet mijn retro hartje terug sneller slaan. 89 EUR later kan ik naar believen 21 ingebakken oude spellen herleven op mijn moderne TV op HDMI kwaliteit. Aan retro gaming console keuzes is helemaal geen gebrek: ondertussen heeft Sony ook ontdekt dat daar geld mee te rapen valt, en er zijn al jaren Chinese alternatieven op de markt. De moderne retro consoles beslaan voornamelijk drie categorieën:</p>
<ol>
<li><strong>Hardware</strong> clones: met een FPGA wordt op hardware niveau de oude CPU volledig nagebouwd, zodat je een 100% authentieke spelervaring hebt. Geen save states of besturingssysteem met uitgebreide software, maar blazen met je oude <em>cartridges</em>!<br/>
Voorbeeld: <a href="https://www.analogue.co/super-nt/">Analogue Super NT</a></li>
<li><strong>Software</strong> clones: emulatie op Linux-gebaseerde besturingssystemen die de hardware van toen nabootsen met extraatjes zoals save states. Geen originele casettes nodig, maar <em>ROM&rsquo;s</em>: digitale bestanden die een <em>image</em> bevatten van de ROM die op de chip van de spelcasette zit. <br/>
Voorbeeld: <a href="https://www.nintendo.com/super-nes-classic/">(S)NES Mini Classic</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, Raspberry Pi DIY</li>
<li><strong>Hybride</strong> consoles: emulatie-gebaseerde spelconsoles die toch de fysieke handeling van het &ldquo;<em>er weer in steken</em>&rdquo; mogelijk maken. Net voor het starten van het spel wordt in de software de ROM van de casette uitgelezen en al dan niet opgeslagen. <br/>
Voorbeeld: <a href="https://www.cybergadget.co.jp/retrofreak/en.html">retrofreak</a>, Retron 5</li>
</ol>
<p><figure>
<a href="/img/analoguent.jpg" class="lbox">
<img loading="lazy" src="/img/analoguent.jpg" title="Analogue Super NT met 8bitdo bluetooth ontvangers">
</a>
<figcaption>Analogue Super NT met 8bitdo bluetooth ontvangers</figcaption>
</figure>
</p>
<p>Allereerst even dit: waarom zou je een nieuwe, <em>oude</em> in feite, console kopen, als je al een originele Super Nintendo bezit? Misschien omdat je van de voordelen van optie 2 en 3 wenst te genieten. Maar waarschijnlijk omwille van HDMI 720p of 1080p capaciteiten die een console van 1990 niet heeft, tenzij je een oude CRT speciaal voor zo&rsquo;n soort consoles bewaart. Een ander overtuigend argument is de <em>&ldquo;region lock&rdquo;</em> van oude consoles: je kan geen Amerikaanse of Japanse <em>cartridges</em> op een Europese console spelen of omgekeerd.</p>
<p>Ik kocht dus een officiële Nintendo console uit categorie 2. Er zijn echter tal van hobbyisten die met RetroArch en RetroPi zelf die dingen in elkaar knutselen, maar daar heb ik geen geduld meer voor. Prutsen met config files, instellingen in commandline en dingen op elkaar afstemmen doe ik al genoeg voor mijn werk. De <em>shell</em> (de plastieken behuizing) van de SNES Mini Classic is mooi en verraadt niet dat er 4 ARM7 cores de console aandrijven.</p>
<p>Mijn vrouw heeft van haar jeugd nog een originele SNES console die we ook aangesloten hebben op de TV maar nauwelijks gebruiken. De vraag is hoe vaak de Mini nog gebruikt gaat worden nadat het nieuwe ervan af is natuurlijk. Als ik de 20 ingebouwde games via eBay zou moeten kopen, moet ik volgens <a href="https://gamevaluenow.com">gamevaluenow.com</a> ongeveer $650 ophoesten! De tweedehands markt op gebied van retro games loopt serieus uit de hand. De prijzen blijven gestaag stijgen en zijn alsmaar moeilijker te vinden. We bezoeken af en toe een toegeweide &ldquo;retro beurs&rdquo; waar standhouders enorme bakken vol met oude casettes aanbieden, van alle mogelijke consoles en handhelds. Dit is een leuke manier om dingen per toeval tegen te komen, en zo je fysieke collectie te vervolledigen. Een leuke, erg dure manier.</p>
<p>Dat digitale aan de SNES Mini stoort me al vanaf het eerste uur dat ik er mee speel: het keuzemenu dat een vrolijk liedje speelt terwijl jij je spel kiest. De vraag is: welk spel? Niet genoeg keuze. Tools als Hackchi2 installeren bevrijdt je Mini van het ronde getal 20 en laat je toe om eender welke ROM die je in je bezit hebt er bij op te proppen. Nog meer keuze. Welk spel? De Hackchi tool heeft addons waarbij emulators van andere consoles geïnstalleerd kunnen worden. Ik kan plots een Playstation 1, DOS(Box) of SEGA MegaDrive spel spelen op mijn Nintendo SNES&hellip; Nog meer keuze. Welk spel?</p>
<p><figure>
<a href="/img/snesmini.jpg" class="lbox">
<img loading="lazy" src="/img/snesmini.jpg" title="SNES Origineel en SNES Classic Mini">
</a>
<figcaption>SNES Origineel en SNES Classic Mini</figcaption>
</figure>
</p>
<p>Hoe meer <em>luie keuze</em> ik heb (een druk op de knop, een selectie uit een menu), hoe minder ik toegewijd ben om een spel van begin tot einde écht te <em>spelen</em>. Dit vind ik heel vreemd. Ik ben bijvoorbeeld ook opgegroeid met een Gameboy en tijdens beursbezoekjes schuim ik dan standjes af om herinneringen terug tot leven te laten komen. Die dure heraankopen maken mij blijkbaar wel erg toegewijd. Alle GBA Castlevania&rsquo;s zijn volledig herspeeld. De actie van een fysieke casette in een console te steken en die aan te zetten geeft mij veel meer goesting om er iets langdurig mee te doen dan simpelweg iets te kiezen uit een hoop dingen die reeds beschikbaar zijn.</p>
<p>Ik begin te twijfelen over console optie 2: zou ik niet beter voor optie 3 kiezen? Dan kan ik nog steeds de fysieke actie uitvoeren, maar heb ik ook save states. Buiten de legale problematiek rond de Retron 5 en de retrofreak (onrechtmatig gebruik van open source emulatie), hervalt het systeem naar optie 2 eenmaal je je cartridge &ldquo;ooit&rdquo; in het systeem gestoken hebt. Vanaf dan is de ROM gedownload en heb je gewoon een digitaal bestand dat opgestart wordt. Het is dus niet enkel de fysieke handeling die mij aanspreekt, want dat kan ik ook bij deze consoles, maar de gedachtegang. Wat gebeurt er als ik dit doe - wordt mijn spel opgestart &ldquo;zoals het hoort&rdquo;, of wordt een ROM gedownload en dit softwarematig geëmuleerd? Het Classic2Magic<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> systeem werkt in combinatie met de SNES Mini: toch nog een <em>cartridge</em> gebruiken om een spel op te starten - in je emulatie systeem. Maar waarom zou ik dan niet gewoon de ROM downloaden?</p>
<p>En optie 1, of verder spelen met de oude SNES? Wij waren vroeger eigenlijk MegaDrive fans. Dan zou ik een tweede console zoals de <a href="https://www.analogue.co/mega-sg/">Analogue Mega SG</a> moeten kopen, én een Super NT. En een HDMI Switch voor op de TV. En plaats maken voor extra kastjes onderin de TV meubel. Dus toch doet het <em>afgeven van keuze</em> (maar spellen op één console, in plaats van mijn gehackte Mini nu) mij iets. Keuze hebben is tof, maar geeft toch geen voldoening en stress. Keuze afgeven is moeilijk.</p>
<p>Hetzelfde geldt voor een e-reader. Ik heb nooit begrepen waarom mensen de interesse verliezen in het vasthebben en doorbladeren van een goed, fysiek in de hand liggend boek. Mijn vader zult een hoop digitale strips mee maar leest ze nauwelijks (herkenbaar probleem). Kleine appartementbezitters zullen er zeker hun voordeel uit halen. Maar dat is even naast de kwestie: als ik een e-reader bezit waar 20 of meer boeken in staan, wat moet ik dan lezen? Nog meer keuze. Welk boek? Hoe snel ben ik het boek effectief <em>beu</em>?</p>
<p><a href="https://www.humblebundle.com">Humble Bundles</a> kopen brengt voor een redelijk bedrag minstens 12 spellen op. Constant de super aanbiedingen in de Nintendo eShop kopen verdubbelt je spellenarchief snel, ook al heb je dan geen nood aan dat spel of eender welk (nieuw) spel. Maar <em>waarom</em>? Deze argumentatie lijkt in te gaan tegen mijn eigen beweging om een SNES Mini te kopen waarbij ik 20 games aankoop voor erg weinig geld. Het gaat mij daar echter voornamelijk om de hardware - de voorgeïnstalleerde software komt er gewoon gratis bij. Die 20 spellen interesseren me toch niet allemaal en ik zou ze nooit alle 20 fysiek (of digitaal) apart kopen.</p>
<p>Hetzelfde geldt voor muziek, voordat streaming software als Spotify de kroon stak. MP3&rsquo;s downloaden was schering en inslag. Op den duur zit je met gigabytes aan (illegale) bestanden die uit je iPod barsten waarvan je misschien 10 tot 20% vaak herbeluistert. 20 jaar geleden kocht ik CD&rsquo;s die ik weken aan een stuk opnieuw durfde af te spelen, totdat mijn zussen en ouders er gek van werden. Tegenwoordig verzuip ik in de mogelijkheden en voorstellen die Spotify aanreikt. Wat is het gevolg? Mijn jaarlijkse top lijst bevat heel weinig nummers: ik speel telkens opnieuw dezelfde gekende dingen af.</p>
<p><figure>
<a href="/img/wiichannel.jpg" class="lbox">
<img loading="lazy" src="/img/wiichannel.jpg" title="Retro Wii kanalen, al dan niet modded">
</a>
<figcaption>Retro Wii kanalen, al dan niet modded</figcaption>
</figure>
</p>
<p>Volgens mij spelen hier verschillende factoren mee:</p>
<ol>
<li>De (gedachte tot) fysieke handeling op zich</li>
<li>De veelheid of weinigheid aan keuze</li>
<li>De verandering en mentale staat</li>
<li>De financiële investering</li>
</ol>
<p>Dat laatste is zeker niet onbelangrijk. Als ik zo graag mijn geliefde Turtles IV: Turtles in Time op SNES wens te kopen, zal ik er minstens 45 EUR voor moeten neertellen om een fysieke PAL kopie van de <em>cartridge</em> in handen te krijgen - hetzij via eBay, hetzij via een beurs. Diezelfde ROM is &ldquo;gratis&rdquo; verkrijgbaar op bepaalde plaatsen van het Internet. Ik ben echter een extreme tegenstander van piraterij, gegeven dat de <em>ontwikkelaars en uitgevers er nog zijn</em> om ze financiëel te steunen<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. Waar gaat die 45 EUR nu naar toe? Naar de smerige standhouder die zijn prijzen artificieel hoog houdt omdat hij goed genoeg weet dat Turtles IV een gewild spel is dat zeer moeilijk te verkrijgen is. Natuurlijk moet er iets tegenover ruilen staan, al dan niet in de vorm van geld. Ik praat alleen in dit geval illegale downloads zeer gemakkelijk goed.</p>
<p>Dan vergeet ik nog even de enorme hoeveelheid aan namaak op de markt. Een leek ziet amper het verschil: blauwdrukken van casettes worden zo goed als 1 op 1 nagegoten. Het is precies een sport geworden om dit aan de retro enthousiasteling verpatst te krijgen zonder hij of zij er erg in heeft. Vooral op gebied van Game Boy (Advance) <em>cartridges</em> is het bedroevend gesteld. In sommige gevallen ben je bijna verplicht het open te schroeven om te kijken naar de EEPROM en batterij op het bord. Als je op eBay een Rolex horloge koopt voor $10 wéét je dat dit namaak is. In dat geval is de koper evenzeer aansprakelijk als de verkoper. Maar slimme verkopers bieden hun zaakjes aan in dezelfde prijscategorie. Aan een foto is bijna niet af te leiden of het om een namaak <em>cartridge</em> gaat of niet. Aan &ldquo;<em>How to spot fake GBA games in 10 steps</em>&rdquo; artikels heb je niets als je vanwege de beperkte beschikbaarheid vanop afstand iets aankoopt.</p>
<p><figure>
<a href="/img/fake-gba.jpg" class="lbox">
<img loading="lazy" src="/img/fake-gba.jpg" title="Welke GBA cartridge is hier fake?">
</a>
<figcaption>Welke GBA cartridge is hier fake?</figcaption>
</figure>
</p>
<p>Hoeveel keer koop je een ouder spel dat niet meer uitgegeven wordt opnieuw? Een keer via de 3DS store, een keer via de Wii store, een keer via een Steam collectie. Met de komst van de Nintendo Switch heb ik de intentie om mijn Wii te verkopen - maar de digitaal aangekochte spellen hangen daar aan vast. Kan ik dan het downloaden van een ROM bestand goedpraten? Ik heb dit immers al drie keer gekocht. Ik kan er ook niet aan doen dat Nintendo niet de optie aanbiedt om dit bestand uit mijn Wii te halen&hellip; Stel dat het officiëel gekochte digitale spel in ROM formaat af te halen is van je console, is het dan legaal om dit op je SNES Mini te plaatsen? De prijzen op de Wii waren nog gedelijk: 5 EUR voor NES, 8 EUR voor SNES en 10 EUR voor N64 spellen. Maar uiteindelijk worden ze natuurlijk ook geëmuleerd. En uiteindelijk is de Wii ook &ldquo;gekraakt&rdquo;.</p>
<p>Ik had met plezier véél meer geld uitgegeven aan retro spellen via het officiëel kanaal als Nintendo de moeite deed om frequenter deze spellen vrij te geven. Ook lang niet alles is beschikbaar. De 3DS shop bijvoorbeeld biedt niet de mogelijkheid om GBA games aan te kopen, terwijl bepaalde <em>limited editions</em> met ingeladen versies van de <em>Wario Ware</em> ROM komen. Als grote handheld gaming fan komt dit aan als een slag in het gezicht. Een loyale fan die duidelijk geen moeite heeft met heraankopen toch nog beroven van opties om nog iets extra te kopen. De afwezigheid van de mogelijkheid om op de nieuwe Nintendo Switch retro games te spelen heeft zo veel fans boos gemaakt. Maar waarom blijven wij dit opnieuw kopen, terwijl de hele Wii schijf vol zit, én ik toch nog op zoek ben naar échte <em>cartridges</em>?</p>
<p>Het wordt dus een delicate ethische kwestie.</p>
<p>Stel dat een online aankoop, bijvoorbeeld vanuit de vroegere Wii Store om een SNES spel te kopen, evenveel zou kosten als de <em>cartridge</em>. Welke versie verkies jij dan? Volgens enquêtes, en volgens mezelf, gaat de voorkeur uit naar de fysieke versie. Dat komt omdat wij als mens graag iets in handen hebben, <em>waar voor ons geld</em> willen. Vreemd, gezien het geld dat overhandigd wordt toch ook gewoon bestaat uit 1 en 0? Maar nu geldt het bovenstaande argument niet meer, dus de fincanciële investering als enkele factor beschikt over onvoldoende overtuigingskracht.</p>
<p><figure>
<a href="/img/retrofreak.jpg" class="lbox">
<img loading="lazy" src="/img/retrofreak.jpg" title="retrofreak: de alles-in-1 oplossing">
</a>
<figcaption>retrofreak: de alles-in-1 oplossing</figcaption>
</figure>
</p>
<p>En toch geeft het niet zo veel voldoening als de fysieke versie. De retrofreak console ziet er redelijk aantrekkelijk uit en kan énorm veel fysieke formaten aan. Dat zou betekenen dat ik mij niet meer moet inhouden als we nog eens naar een retro beurs gaan: <em>one ring to rule them all</em>. Jammer genoeg draait dat op Android en hangen er rechtzaken boven het hoofd van deze consoles - om nog maar te zwijgen van de Chinese kwaliteit. En zou ik dan de ROM op een SD kaart zetten<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, of van mijn vrouw genoeg geld mogen uitgeven om <em>cartridges</em> te stockeren? Ik heb geen <em>mancave</em>, en moet dan ook nog een glazen vitrinekastje kopen om te pronken met mijn dure casettes&hellip;</p>
<p>Om mijn gemoedsrust te bedaren en om voor mezelf een duidelijke lijn te trekken in wat ik oké vind en wat niet, stel ik het volgende voor. Spellen die op legale wijze gekocht zijn - digitaal of analoog, daar doe je mee wat je wil. Dat kan betekenen dat spellen omgevormd worden in ROM formaat en op de SNES Mini terecht komen. Het moet echter zélf om te vormen zijn: anders zou ik bewust naar een illegale website moeten surfen om iets te downloaden waarvan ik wéét dat het niet legaal is. Een DOS spel gekocht via <a href="https://gog.com">Good Old Games</a> kan ik met een gerust hart op de Mini spelen. Een gekocht PS1 spel dat ik zelf rip ook, maar voor <em>cartridge</em>-gebaseerde consoles heb ik dan een probleem en moet ik terug vallen op console categorie 3 of extra optie 4<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. <a href="https://www.nintendo.com/corp/legal.jsp#helping">Volgens Nintendo</a> zijn <em>&ldquo;game copying devices&rdquo;</em> echter ook illegaal. Eigen ROMs rippen creëert immers een tweede kopie van het spel, wat weer in de grijze zone valt.</p>
<blockquote>
<p>Emulators are legal to download and use, however, sharing copyrighted ROMs online is illegal. There is no legal precedent for ripping and downloading ROMs for games you own, though an argument could be made for fair use. (16/03/2017, <a href="https://www.howtogeek.com/262758/is-downloading-retro-video-game-roms-ever-legal/">bron</a>)</p>
</blockquote>
<p>Is het &ldquo;open stellen&rdquo; van de SNES Mini software legaal? Als ik een stuk hardware gekocht heb, dan mag ik daar toch op zetten wat ik wil - zolang de software zelf ook legaal is? RetroArch is open source, net als Hackchi2. Dit was natuurlijk niet de intentie van Nintendo. Als ik een wagen koop en ik beslis die te <em>tunen</em>, dan mag ik dat. Als ik echter met die aangepaste wagen op de openbare weg rij, gelden er andere regels. Dat lijkt me hier dus niet van toepassing. Het blijft echter een gecompliceerde grijze zone&hellip;</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>De combinatie tussen SNES Classic en SNES Mini is mogelijk met het <a href="http://classic2magic.com">Classic2Magic</a> systeem. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Dit klopt niet helemaal. Nintendo is er nog als uitgever, en HAL Laboratories als ontwikkelaar van Kirby. Een (groot) deel van het geld dat ik uitgeef om <em>Kirby&rsquo;s Super Star</em> op SNES te kopen zou dus naar daar moeten gaan. <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Ik laat hier nog optie 4 weg: dit is geen console maar een stukje hardware dat toestaat om op een legale manier ROM bestanden te downloaden van je eigen casettes: <a href="http://www.retrode.org">Retrode2</a>. Zij stoppen echter met de productie&hellip; <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 22 December 2018.
</p>
]]>
</description>
</item>
<item>
<title>Unit Testing PicoBlaze Assembly files</title>
<link>https://brainbaking.com/post/2018/12/unit-testing-picoblaze-assembly/</link>
<comments>https://brainbaking.com/post/2018/12/unit-testing-picoblaze-assembly/#commento</comments>
<pubDate>Wed, 05 Dec 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/12/unit-testing-picoblaze-assembly/</guid>
<category domain="https://brainbaking.com/tags/unit testing">unit testing</category>
<category domain="https://brainbaking.com/tags/assembly">assembly</category>
<category domain="https://brainbaking.com/tags/picoblaze">picoblaze</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Unit%20Testing%20Stored%20Procedures.jpg"/>
</p>
<p>To continue our <a href="/tags/unit-testing/">unit testing tradition</a>, each time I land on a new language or piece of technology, I carefully assess whether it&rsquo;s possible to write tests first. Unsurprisingly, even in Assembly it&rsquo;s possible. My recent foray into the digital electronics world has let me to write instructions for the <a href="https://www.xilinx.com/products/intellectual-property/picoblaze.html">Xilinx PicoBlaze</a> 6 FPGA microcontroller. This Assembly dialect, written in &ldquo;Psm(4)&rdquo; files, is destined for a different architecture. That means linking and leaning on Google Test using C++ isn&rsquo;t possible.</p>
<p>As any good software developer does, I decided to reinvent the wheel and create an <a href="https://github.com/wgroeneveld/opbtest">Open PicoBlaze Assembler Unit Test package</a> myself, written in Python 3. It uses the open <code>opbasm</code> and <code>opbsim</code> cross-platform assembler and simulator to compile your written Assembly, and then leverages Python&rsquo;s <code>unittest</code> package to execute assertions. Take a look at the <a href="https://github.com/wgroeneveld/opbtest">github repository</a> README file an in-depth technical background.</p>
<p>Say, I write a procedure that adds two registers and stores it in a third. This procedure lives in a <code>.psm4</code> file, together with a bunch of other procedures. What if I want to test only that &ldquo;method&rdquo;?</p>
<blockquote>
<p><strong>What are the basic needs of a unit test framework?</strong></p>
</blockquote>
<p>As a developer, I want to be able to:</p>
<ol>
<li>test a single method, individually, separate from the rest of the source.</li>
<li>test an entire file, as an integration test.</li>
<li>stub/mock out methods I am currently not interested in.</li>
<li>assert state after execution. (registers, input, output)</li>
<li>set up state before execution. (registers, input, output)</li>
</ol>
<p>The problem with Assembly is, there&rsquo;s no such thing as a &ldquo;method&rdquo;, except blocks separated by jumps and labels. For instance:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-llvm" data-lang="llvm"><span style="color:#a61717">jump</span> <span style="color:#a61717">main</span>
<span style="color:#a61717">pro</span><span style="color:#728e00">c</span> <span style="color:#a61717">add_registers</span>(<span style="color:#a61717">s</span><span style="color:#8a7b52">0</span> <span style="color:#a61717">is</span> <span style="color:#728e00">one</span>, <span style="color:#a61717">s</span><span style="color:#8a7b52">1</span> <span style="color:#a61717">is</span> <span style="color:#a61717">two</span>, <span style="color:#a61717">s</span><span style="color:#8a7b52">5</span> <span style="color:#a61717">is</span> <span style="color:#a61717">res</span><span style="color:#728e00">ult</span>) {
<span style="color:#728e00">load</span> <span style="color:#a61717">res</span><span style="color:#728e00">ult</span>, <span style="color:#8a7b52">0</span>
<span style="color:#434f54">loop1:</span>
<span style="color:#728e00">add</span> <span style="color:#a61717">res</span><span style="color:#728e00">ult</span>, <span style="color:#8a7b52">1</span>
<span style="color:#728e00">sub</span> <span style="color:#728e00">one</span>, <span style="color:#8a7b52">1</span>
<span style="color:#a61717">jump</span> <span style="color:#a61717">NZ</span>, <span style="color:#a61717">loop</span><span style="color:#8a7b52">1</span>
<span style="color:#434f54">loop2:</span>
<span style="color:#728e00">add</span> <span style="color:#a61717">res</span><span style="color:#728e00">ult</span>, <span style="color:#8a7b52">1</span>
<span style="color:#728e00">sub</span> <span style="color:#a61717">two</span>, <span style="color:#8a7b52">1</span>
<span style="color:#a61717">jump</span> <span style="color:#a61717">NZ</span>, <span style="color:#a61717">loop</span><span style="color:#8a7b52">2</span>
}
<span style="color:#434f54">main:</span>
<span style="color:#95a5a6">; this should not be executed
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">load</span> <span style="color:#a61717">s</span><span style="color:#8a7b52">5</span>, <span style="color:#8a7b52">42</span>
</code></pre></div><p>I used M4 Macro extensions on a PicoBlaze 6 board. The <code>proc</code> macro gets expanded to labels in a <code>.gen.psm</code> file using <code>opbasm</code>. What if I only want to test the <code>add_registers</code> &ldquo;method&rdquo;? Below the main label, the result register (<code>s5</code>) gets loaded with <code>42</code> (hex).</p>
<p>This will be my Python 3 test case for the above Assembly:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#728e00">from</span> <span style="color:#434f54">opbtest</span> <span style="color:#728e00">import</span> <span style="color:#434f54">OpbTestCase</span>
<span style="color:#728e00">class</span> <span style="color:#434f54">MyTestCase</span>(<span style="color:#434f54">OpbTestCase</span>):
<span style="color:#728e00">def</span> <span style="color:#d35400">test_add_registers_counts_reg1_and_reg2_into_reg3</span>(<span style="color:#434f54">self</span>):
<span style="color:#434f54">assert_that</span> <span style="color:#728e00">=</span> <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">load_file</span>(<span style="color:#7f8c8d">&#34;functions.psm4&#34;</span>)\
<span style="color:#728e00">.</span><span style="color:#434f54">testproc</span>(<span style="color:#7f8c8d">&#34;add_registers&#34;</span>)\
<span style="color:#728e00">.</span><span style="color:#434f54">setregs</span>({<span style="color:#7f8c8d">&#34;s0&#34;</span>: <span style="color:#8a7b52">1</span>, <span style="color:#7f8c8d">&#34;s1&#34;</span>: <span style="color:#8a7b52">2</span>})\
<span style="color:#728e00">.</span><span style="color:#434f54">execute</span>()
<span style="color:#434f54">assert_that</span><span style="color:#728e00">.</span><span style="color:#434f54">reg</span>(<span style="color:#7f8c8d">&#34;s5&#34;</span>)<span style="color:#728e00">.</span><span style="color:#434f54">contains</span>(<span style="color:#8a7b52">3</span>)
</code></pre></div><p>Tested a single method? Check. <br/>
Setup registers before execution? Check.<br/>
Assert state after execution? Check.</p>
<p>As you can see, I&rsquo;ve been inspired by other well-known C#/Javascript frameworks that are able to chain setup calls together. The actual assertion(s) are separate to emphasize the typical <strong>given-when-then</strong> behavioral scenario in &ldquo;modern&rdquo; testing frameworks.</p>
<p>Assertions like <code>reg</code>, <code>scratchpad</code>, <code>port</code> verify the correct end state of your Assembly file. Seeing a red or green test in your favorite IDE or in the console is a <em>huge</em> improvement over this:</p>
<p><figure>
<a href="../picoblaze_sim.png" class="lbox">
<img loading="lazy" src="../picoblaze_sim.png" title="Simulating hardware in a testbench">
</a>
<figcaption>Simulating hardware in a testbench</figcaption>
</figure>
</p>
<p>Inspecting a wave form after simulating your hardware configuration in tools like Vivado is a huge pain compared to writing separate test cases in software. I know the Test Bench tooling can be used to write test for your synthesis, but when uploading a bitstream into an FPGA, you never know whether it&rsquo;s the HDL that&rsquo;s incorrect, or the Assembly loaded into it.</p>
<p>My <code>opbtest</code> package comes with one serious downside (more of a disguised upside): it requires you to write your tests in another language, namely Python 3. I am aware of possibilities like embedded Assembly testing <a href="http://blog.code-cop.org/2015/08/how-to-unit-test-assembly.html">such as this</a>, but it&rsquo;s implementation lacks the ability to mock out statements I don&rsquo;t want to evaluate.</p>
<p>For instance, if you use a generated PRNG using the M4 macro, somewhere a <code>call random</code> generates a random 8-bit value into a register. Randomness is difficult to test, so is typically &ldquo;frozen&rdquo; in test setup. <code>opbtest</code> makes that very easy: <code>.replace(&quot;call random&quot;, &quot;load s0, s0&quot;)</code>. It uses string manipulation to scan the source file, modify the needed lines, and then recompile &amp; evaluate it with <code>opbasm</code> and <code>opbsim</code>. <code>testproc()</code> uses the same trick: inject a <code>jump [methodname]</code> at the beginning, inject a <code>jump [programend]</code> at the end of the proc.</p>
<p>Another advantage of using Python is, surprise, readability - at least compared to your Assembly to test! It&rsquo;s also non-intrusive: you don&rsquo;t need to modify your source code or include other files. And it&rsquo;s easily integrated into your CI build using <code>python -m unittest</code>.</p>
<p>If you have a feature request, want to contribute, or report a bug, feel free to <a href="https://github.com/wgroeneveld/opbtest/issues">open up a new issue</a> on Github! As we&rsquo;ll continue to use the package, I&rsquo;ll be sure to make changes here and there.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 5 December 2018.
</p>
]]>
</description>
</item>
<item>
<title>A Decade in the Software Engineering industry</title>
<link>https://brainbaking.com/post/2018/10/a-decade-in-the-industry/</link>
<comments>https://brainbaking.com/post/2018/10/a-decade-in-the-industry/#commento</comments>
<pubDate>Sat, 27 Oct 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/10/a-decade-in-the-industry/</guid>
<category domain="https://brainbaking.com/tags/jobs">jobs</category>
<category domain="https://brainbaking.com/tags/craftsmanship">craftsmanship</category>
<category domain="https://brainbaking.com/tags/development">development</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/glasses.jpg"/>
</p>
<p>It never occurred to me that an article like this might be very informative for those interested in knowing how things work in the software engineering industry. Google&rsquo;s related results to &ldquo;10 years in IT industry&rdquo; are rather depressing: &ldquo;what to do after 10 years of experience&rdquo;, &ldquo;career options after 10 years&rdquo;, &ldquo;how to survive industry after 10 years&rdquo;, &ldquo;best career path after 10 years&rdquo;. It seems to suggest you&rsquo;re done after <em>&ldquo;grinding to level 10&rdquo;</em> - time to boot up another character build? I don&rsquo;t know - there&rsquo;s a plethora of options available to you, as long as you&rsquo;re creative enough to see them.</p>
<h3 id="a-brief-history">A Brief History</h3>
<p>Before getting down to business, it might be more appropriate to frame my experience first, by explaining how I ended up <em>not</em> working for the industry anymore. My first job with a major IT consultancy firm as as software developer took quite a while and lasted 7 years. When I started looking for other opportunities, recruiters were astonished: &ldquo;wow, you stayed at one company for 7 years?&rdquo;. The current job hopping trend makes me sad: to me, switching every year might damage your CV instead of enrich it. We did consultancy work, but were always outsourced as a team. That makes a huge difference. I&rsquo;ve learned a lot in little time. After getting tired of commuting too long, I switched from consulting to in-house product development and stayed with my second employer for 4 years.</p>
<p>I&rsquo;ve had a lot of different roles, even if my title mostly stagnated at &ldquo;software developer&rdquo;. Cooler colleagues made theirs &ldquo;engineer&rdquo; and prefixed it with &ldquo;enterprise&rdquo; or &ldquo;senior&rdquo;, that always works. My experience can be roughly cut up in these different stages - I&rsquo;m sure you&rsquo;ll recognize them. If you want, you can map these to the Dreyfus model, or any other learning model.</p>
<ol>
<li>Stage 1: <strong>Ignorance</strong>. Soak up as much as you can, because you don&rsquo;t know how anything works. This took 4 years. Yes, 4 years. My Master education took that long, and after graduating, you still have no clue. Does this sound bad? I was a (junior) developer.</li>
<li>Sage 2: <strong>Competent</strong>. You&rsquo;re getting the hang of it: you start to easily recognize code parts that need refactor work, you&rsquo;ve gone <em>wide</em> by exploring all possible kinds of technologies and gone <em>deep</em> by really, really knowing something well. Another 2 years pass by. I became a (senior) developer.</li>
<li>Stage 3: <strong>Expert</strong>. People go to you if something has to be debugged. You create courses, do technical interviews, help others grow and enjoy the ride. Things are getting boring: you identify problems with your eyes closed. So you&rsquo;re seeking challenges elsewhere: in collaboration. Another 5 years are gone. I was a coach, architect, developer, &hellip;</li>
</ol>
<p>In stage 3, I discovered I like teaching others what I taught myself. In fact, I liked it so much that I started (this website? and) giving guest lectures in colleges and universities, ultimately translating into a full-time switch from industry to the academic world. Figuring out how patterns work for me was one of the most satisfactory challenges I faced while co-developing enterprise software in agile teams. But once you see through the (in-)differences between tools, languages and APIs, repeatedly applying them made the jump easier for me - towards ideas and concepts instead of application.</p>
<h3 id="so-what-did-i-learn">So, What did I learn?</h3>
<p>Not one person working for 10 years in the IT world will walk the same path above as I did: different backgrounds, education, interests, domain, company culture, implementation practices, &hellip; So take my advice with a pinch of salt as it&rsquo;s <em>personal</em> and might not help you very much. My academic colleagues are curious to hear about my experience &ldquo;in the field&rdquo; and I hope to inspire one or two, but it might also be enlightening for the lunatics I&rsquo;ve shamelessly left behind (<em>tirez votre plan!</em>)<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<h4 id="1-go-wide--go-deep">1. Go Wide &amp; Go Deep</h4>
<p>I&rsquo;m a big advocate for <strong>generalism</strong> as I&rsquo;ve written in the <a href="/about/">about me</a> page. Being a <em>Polymath</em> or a <em>Renaissance man</em> as enriched my world in so many ways I cannot even begin to imagine what it would be like if I was only interested in a few subjects. <strong>Be open to anything</strong>. Don&rsquo;t limit yourself to one programming language: do yourself a favor and learn as much languages as you can manage. <strong>Cross-pollination</strong> is extremely important - not only in (software) engineering, but in life in general! So don&rsquo;t limit applying these principles to programming, but learn from other domains as well. Try a psychology course, read some philosophy. Get your hands on anything you don&rsquo;t know anything about. This not only broadens your own knowledge, but feeds those serendipitous connections. Get to know <em>a lot of</em> things. <em>Keep on</em> wanting to know a lot of things, again and again. Build a <a href="/post/a-samurai-learning-mindset/">samurai learning mindset</a>.</p>
<blockquote>
<p>Study the science of art. Study the art of science. Develop your senses - especially learn how to see. Realize that everything connects to everything else. - Leonardo Da Vinci</p>
</blockquote>
<p>That&rsquo;s not to say that specializing isn&rsquo;t bad: in fact, it&rsquo;s the default way to go in IT. Just make sure you&rsquo;re not in so &ldquo;deep&rdquo; that you can&rsquo;t get out! <strong>Be the best at something, and the worst at something else</strong>. Are you learning JavaScript? Great, how about digging deep and really, <em>really</em> knowing how prototypal inheritance works instead of only being able to apply it&rsquo;s patterns? Did you take a look at the V8 source code? Can you learn anything from contributing to the React Github repository? Get to know something <em>very well</em>.</p>
<h4 id="2-fail-fast--fail-often">2. Fail Fast &amp; Fail Often</h4>
<p>I&rsquo;m sure you&rsquo;re familiar with the agile <em>&ldquo;demo or die&rdquo;</em> principle: if you can&rsquo;t show what you&rsquo;re working on every few weeks (iteration), we&rsquo;ll cancel that project of yours. As simple as that. Forget about specifications, Gantt charts and R4 models: <strong>don&rsquo;t just stand there, do something</strong>! Launching something means getting something in the air, as soon as possible. I&rsquo;ve sworn by Test Driven Development and Continuous Integration &amp; Deployment since then. Unit tests save lives and keep my brain sane. Software development is <em>incremental development</em>.</p>
<blockquote>
<p>If you&rsquo;re not failing every now and again, it&rsquo;s a sign you&rsquo;re not doing anything very innovative. - Woody Allen</p>
</blockquote>
<p>However, sometimes, you need to <strong>stand there, don&rsquo;t just do something</strong>. With complex pieces of software, refactoring in a new requirement comes with two pathways: that of least and of most resistance. It&rsquo;s obvious which is easier for you to go with, but that doesn&rsquo;t mean you should blindly act. Think, talk to others, turn it on it&rsquo;s head, approach it differently and come up with multiple solutions. Then pick one and go for it. Remember to let it fail first. A word of warning: failure can be painful and frustrating. You need to learn <strong>how to be resilient</strong> before - to be able to get up and do it again.</p>
<h4 id="3-work-with-people-not-technology">3. Work with People, not Technology</h4>
<p>&ldquo;Engineering&rdquo; software is hard: there&rsquo;s no clearly defined set of requirements, implementation patterns change and shift frequently as do API&rsquo;s and languages. But Creating software is first and foremost a <strong>social practice</strong>. Teamwork is obvious, but working across teams, across divisions, talking to customers, owners, business experts and devOps means even more contact with others.</p>
<blockquote>
<p>People who join a social practice gradually adopt shared values and strive for standards of excellence defined within it - Alasdair Maclntyre, After Virtue</p>
</blockquote>
<p>Some developers might not like this, but we have to face the facts and admit that social skills are as least as important as technical ones. How many times did you witness a software project fail due to technical issues? And due to miscommunication of some sort? Right. Being open to <em>anything</em> (go wide) also means <strong>being open to others</strong> as they are usually the ones who surprise you the most, you learn from the most and you can rely on the most! Software development is people development. This is not by chance the subject of <a href="/tags/phd/">my doctorate</a>.</p>
<h4 id="4-motivate-inspire--share">4. Motivate, Inspire &amp; Share</h4>
<p>First, <strong>motivate and inspire yourself</strong> to do something <em>great</em> - something hard that demands the most of your abilities. <em>Intrinsic</em> self-motivation always pays off in the long run, don&rsquo;t get fooled by money or fancy cars. It&rsquo;s easy to fall in that trap, but after a few years you&rsquo;ll notice it will become harder and harder to motivate yourself to even get out of bed. <a href="/post/journaling-in-practice/">Keep a journal</a>. I cannot express in words how much that helped me to keep pushing myself - and in the end, others.</p>
<p>Then, <strong>motivate and inspire</strong> others. Remember this order: if you&rsquo;re not motivated, you will never be able to inspire someone else to do the same! I love inspiring others; this is my number one reason to do whatever I do. This is the reason I&rsquo;m writing this, the reason I want to teach, to talk about good books I&rsquo;ve read, to convince someone to follow that course that helped me so much, &hellip; And it&rsquo;s amazing how much energy this gives me - given that others are willing to receive.</p>
<blockquote>
<p>As soon as you seek to inspire others, it inspires the best in you. - Brendon Burchard</p>
</blockquote>
<p>To inspire, you <strong>share</strong> information. You never withhold information! Remember you&rsquo;re working <em>together</em>, nobody is going to steal your job, you&rsquo;re not going to get fired, and you can even try to convince your company to publish small modules open source as a means to give something back to the community or even to make a name. Sharing is indeed caring. This doesn&rsquo;t stop with code or domain knowledge! Share as much as you like to inspire others. Share articles, buy books and give them away, bake cookies and bring them to meetings, &hellip; This has a huge impact on the bond between you and your colleagues and will make the crucial difference between team member and friend.</p>
<h4 id="5-ignore-egos">5. Ignore Ego&rsquo;s</h4>
<p>Working with others can be very tiresome at moments, especially if someone sees his or hers work only as yet another <em>career</em> opportunity. Boring chit chat about ladder climbing, money and company cars make your sandwiches hard to digest during noon. Some people are simply too stubborn. I love an emphatic approach but my daily limited willpower resources are drained very quickly if people like these ruin the peace. Whatever you do, <strong>do not go into their advances</strong>. Ignore ego&rsquo;s.</p>
<blockquote>
<p>It&rsquo;s a trap! - Admiral Ackbar</p>
</blockquote>
<p>Try to protect yourself from these leeches by promptly blocking their train of thought, changing the subject or simply moving away. I&rsquo;ve come across more than a few of these, it&rsquo;s very sad to see the software engineering field being riddled with cowboys, money makers and assholes. I suppose you&rsquo;ll encounter these in any field. The best piece of advice is to try and surround yourself with people who are brighter than you, people who also <strong>value the same things as you do</strong>. Not everyone can be changed that easily, sometimes it&rsquo;s not worth your effort. Oh, and delete your Linkedin account.</p>
<h4 id="6-sometimes-grass-is-greener">6. Sometimes, Grass Is Greener</h4>
<p>Things might start to be a drag, and you might wonder, &ldquo;what if I got to work in company Y, maybe things will be better there&hellip;&rdquo;. The answer usually isn&rsquo;t that one-dimensional: sometimes it is, sometimes it isn&rsquo;t. But that should not hold you back from taking a peek. The moment you get up in the morning and don&rsquo;t feel like going to work, you shouldn&rsquo;t immediately resign but try to figure out <em>why not</em>. If the answer is something substantial, it might be worth to still do so.</p>
<blockquote>
<p>Never waste your time trying to explain who you are to people who are committed to misunderstanding you. - Unknown</p>
</blockquote>
<p>I&rsquo;m not a fan of job hopping, and I never will be. But I&rsquo;ve been in some really, really <em>shitty</em> teams, and in some really, really <em>great</em> teams. If your critical mass is too small (say, like, only you?), you&rsquo;re not going to make it. Don&rsquo;t keep on hoping for the best. Sometimes, it&rsquo;s better to <strong>cut your losses</strong> and go. I&rsquo;m not saying you shouldn&rsquo;t try - you&rsquo;ll notice soon enough if there is any hope left.</p>
<h4 id="7-read-and-then-write">7. Read, and then Write</h4>
<p>A good writer needs to read first in order to work in the literature. The same applies for a software developer: developers are first and foremost <strong>readers</strong>. Being an author comes in second place. Therefore, keeping things <em>readable</em> will be your primary objective. Practices like Clean Code and Test-Driven Development will help immensely to achieve this objective.</p>
<blockquote>
<p>“Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. &hellip;[Therefore,] making it easy to read makes it easier to write.” - Robert C. Martin, Clean Code</p>
</blockquote>
<p>But reading shouldn&rsquo;t be limited to reading code or reading within your own subject domain. As stated before, being open to anything also means reading more on new and exciting subjects, which generates unique ideas and peaks your interest. Writing about something in detail is one of the best teach masters that forces you to look at things from another direction. Keep a Wiki, write Blog posts, track your notes, add remarks to Evernote. Anything to keep ideas and knowledge flowing.</p>
<h4 id="8-be-creative">8. Be Creative</h4>
<p>There are multiple books about &ldquo;how to be a better programmer&rdquo;: the productive programmer, the pragmatic programmer, the passionate programmer, &hellip; But there&rsquo;s surprisingly little said about the fact that you&rsquo;re <em>creating</em> something. To create could mean to have a plan (analysis) and simply execute (code) it. It could also mean to approach a problem holistically, to come up with a multitude of possible solutions and to deliberately pick the best possible fit. Creating with uncertain requirements can be scary. Who knows what will happen. I know what will happen if you don&rsquo;t: nothing.</p>
<blockquote>
<p>The human spirit lives on creativity and dies in conformity and routine. - Vilayat Inayat Khan</p>
</blockquote>
<p>Being creative does not necessarily mean drawing on paper - but that does help. For me, it means coming out of your comfort zone and trying something new. Combine things that shouldn&rsquo;t be combined. Execute your ideas, don&rsquo;t simply collect them, even if they turn out to be nothing, I bet you&rsquo;ll have learned at least something. I bootstrapped <em>Brain Baking</em> thanks to a lot of previous (failed) efforts.</p>
<h4 id="9-be-reflective--productive">9. Be Reflective &amp; Productive</h4>
<p>Thinking forward is okay, but remember to hit the breaks and shift gears to think backwards for a while. When you take notes, are you re-reading them? And how often are you doing that? Your creative process will wither without a reflective approach. Think about what you&rsquo;re trying to do, about what you&rsquo;ve done and about what you&rsquo;ll do. Act, and modify accordingly.</p>
<blockquote>
<p>Men should pledge themselves for nothing; for reflection makes a liar of their solution. - Sophocles</p>
</blockquote>
<p><em>Retrospectives</em> shouldn&rsquo;t only be held at work to help improve your team&rsquo;s or company&rsquo;s performance. They can also help yourself. Why would you limit yourself to using things what they&rsquo;re made for if they can be used in another setting? If you&rsquo;re writing code daily but you find yourself copy-pasting a lot, did you know that clipboard utilities can enhance your workflow? (Just as a means to be more productive, not by embracing copy-paste programming! First understand, then reproduce.) Are you thinking about <strong>how to do something better</strong>? Do you bother learning keyboard shortcuts of your IDE? Do you think about how to dice your onion the most efficient way on your cutting board? You should.</p>
<h3 id="what-about-applicability">What about applicability?</h3>
<p>It seems like these &ldquo;rules of thumb&rdquo; aren&rsquo;t limited to just software engineering. That makes them all the more important - and transferable to a new sector and a new challenge. The article might have more appropriately be titled &ldquo;what I&rsquo;ve learned in life so far&rdquo;. After all, what&rsquo;s the difference between work and life?</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>Remember guys, I miss you, I&rsquo;m just trying to be funny here! <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 27 October 2018.
</p>
]]>
</description>
</item>
<item>
<title>The Startup of a Lean Doctorate</title>
<link>https://brainbaking.com/post/2018/10/lean-doctorate/</link>
<comments>https://brainbaking.com/post/2018/10/lean-doctorate/#commento</comments>
<pubDate>Fri, 19 Oct 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/10/lean-doctorate/</guid>
<category domain="https://brainbaking.com/tags/phd">phd</category>
<category domain="https://brainbaking.com/tags/tools">tools</category>
<category domain="https://brainbaking.com/tags/academia">academia</category>
<category domain="https://brainbaking.com/tags/agile">agile</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/lightbulbs.jpg"/>
</p>
<p>At the start of my doctoral study, things are a bit <em>woozy</em>. The use of that word &ldquo;bit&rdquo; may be the inverse of exaggeration: shaping an abstract idea into a malleable and well-defined project is a process that can easily take up months. After that you still have to &ldquo;start&rdquo; actually doing stuff in context of your invented project! Most doctorates are classical examples of a <strong>waterfall</strong> process: come up with an abstract, do your (and a lot of) literature study, reach certain milestones. It&rsquo;s clearly visible in the <a href="https://set.kuleuven.be/phd/roadmap.htm">Arenberg Doctoral School Roadmap</a>.</p>
<p>As an <em>agile</em> software engineer, that uncertainty leaves me with an unpleasant feeling as I struggle to define clear goals on a weekly basis. Sprints of 2 or 3 weeks are out of the question&hellip; Are they? Why should they be? A quick &ldquo;<em>agile doctorate</em>&rdquo; lookup in Google Scholar nets me academic papers like <a href="http://csis.pace.edu/~ctappert/srd2015/2015PDF/d4.pdf">An Agile Approach to the Doctoral Dissertation Process</a> and <a href="http://csis.pace.edu/~ctappert/srd2016/2016PDF/a3.pdf">The Conclusion</a>. The only problem with these papers is that they propose to change the formula all together in an experimental context. There is - surprisingly - next to nothing academically published about someone&rsquo;s PhD process in an iterative or <em>agile</em> way!</p>
<hr>
<p><strong>Update, 30 Jan. 2021</strong>: I&rsquo;m about 2.5 years in, and due to <a href="/post/2020/02/agile-academia/">the way academia works</a>, I&rsquo;ve had to thoroughly readjust the way I&rsquo;m used to working. <em>&ldquo;Early feedback&rdquo;</em> (see below) and all that is great, provided it is possible. I learned the hard way that it <a href="/post/2020/02/agile-academia/">is not</a>. Frustratingly enough, that means that my work also resembles a waterfall process, even though I try to keep it from becoming like the Niagara Falls.</p>
<hr>
<h3 id="how-to-be-an-agile-academic">How to be an Agile Academic</h3>
<p>Maybe we should ask <a href="https://www.scrumalliance.org/community/profile/jsutherland">Jeff Sutherland</a> on how to achieve this, but I doubt the SCRUM Alliance principles were in his head when he did his doctorate. Katy Peplin wrote a nice article about <a href="https://www.katypeplin.com/blog/2017/10/25/be-an-agile-academic">being an agile academic</a> that advocates for principles like getting feedback, fast(er) and using Test Driven Design. As some wise men once said,</p>
<blockquote>
<p>Fail fast, fail often.</p>
</blockquote>
<h4 id="early-feedback">Early feedback</h4>
<p>To fail means to get feedback. To get feedback means to <strong>publish</strong>. That&rsquo;s right, publish as early and as often as possible! But how can you publish papers when you haven&rsquo;t even started researching, let alone writing something useful yet? I&rsquo;m not only talking about <a href="https://speakerdeck.com/jakevdp/in-defense-of-extreme-openness">lean publishing of academic papers</a> (as Jake VanderPlas said <em>in defense of extreme openness</em>), but also about concepts. Anything you put on (virtual) paper can be used to get feedback.</p>
<p>For example, Katy identified daily stand ups used in agile teams as a useful way to identify what was blocking her progress by doing a stand-up with&hellip; yourself! That way she got feedback from herself. A PhD can be a lonely process indeed, but it doesn&rsquo;t have to be that way. You can change that yourself by explicitly asking feedback to your peers, colleagues and friends.</p>
<p>My way to get feedback is to follow in Jake&rsquo;s footsteps and to simply <a href="https://wgroeneveld.github.io/phd">publish <strong>everything</strong> on Github</a>. Add a big &ldquo;feedback&rdquo; button that redirects to the Github Issues page to invite people who come across your work to leave valuable insights. Why only publishing a paper, if you can publish everything related to your work, including papers? It contains reports of meetings, brainstorms, concept items I&rsquo;m working on, definitions, bibliography, &hellip; Literally everything. <strong>Document everything</strong> - a useful tip!</p>
<p>Another way to get feedback if you&rsquo;re developing is using your trusty Unit Tests and Continuous Integration system. As I&rsquo;m not coding for my PhD, this might not apply, you might think. But actually, I can still take those concepts and try to apply them to my writing:</p>
<ul>
<li>Create separate pages for separate ideas/subjects. (Test Classes)</li>
<li>First write down <em>what</em> you&rsquo;re trying to write down. (&ldquo;X in here&rdquo;, &ldquo;WHEN I&rsquo;m finished with this, X and Y SHOULD be defined here&rdquo;). (Given, When, Then Test Cases)</li>
<li>Then write, and rewrite, and rewrite. The expected outcome of that page might also change.</li>
</ul>
<p>Publishing these pages as a website using <code>Hugo</code> makes it very easy to share a link and ask someone for feedback. Of course, before simply pushing everything into the open, your supervisor (and possibly your Faculty) should agree with this. But after showing the advantages of being open, I&rsquo;m sure that won&rsquo;t be a big problem.</p>
<h5 id="_demo-or-die_"><em>Demo or die</em></h5>
<p><em>Closing the feedback loop</em> might not be that simple: professors are usually extremely busy and have a tight schedule, so don&rsquo;t expect them to read every long piece you&rsquo;ve written. Most PhD students meet with their supervisor once a month, just like me. I know students who are less lucky and have more trouble squeezing in a meeting. If you&rsquo;re really unlucky, your supervisor might not show any interest at all in your research. That&rsquo;s quite sad and should not happen.</p>
<p>In most agile software development companies, teams present their progress weekly or every two weeks. This is a short moment of reflection that allows for (in their case last-minute) feedback from all stakeholders. I try to emulate this principle by meeting with my supervisor once a month, and meeting with another interested party <em>in the field</em> - also once a month. If you plan this in alternating two weeks, you can gather feedback every 14 days.</p>
<p>The added benefit of gathering feedback from people in the field is another important <strong>angle of approach</strong>. The result is not a pure theoretical academic work but a good balance between theory and practice. Our Engineering &amp; Technology Faculty at KU Leuven obliges PhD students to write a valorisation report to prove applicability. Another thing more easily checked off&hellip;</p>
<h5 id="reading">Reading</h5>
<p>Another way to tap into the brains of others is to simply <em>read</em>. Reading books related to your subject will spark new ideas and might even make you rethink certain options. Static feedback is still feedback, even if it&rsquo;s your own responsibility to interpret written opinions of others.</p>
<p>I am not talking about your typical academic literature, but also about popular science books, philosophy, sociology and psychology, &hellip; - anything that even remotely <em>touches</em> upon your research questions might be worth looking into. I prioritize my reading list <strong>based on interest</strong> instead of relevance: embrace the possibility for new ideas coming from <em>any</em> direction. For example, I&rsquo;m researching non-cognitive skills in software engineering; <a href="https://www.goodreads.com/book/show/22875447-work-rules?ac=1&amp;from_search=true">Work Rules!</a>, <a href="https://www.goodreads.com/book/show/40745.Mindset?ac=1&amp;from_search=true">Mindset</a> and <a href="https://www.goodreads.com/book/show/134454.The_Reflective_Practitioner?ac=1&amp;from_search=true">The Reflective Practitioner</a> are currently on my list.</p>
<h4 id="planning">Planning</h4>
<p>Another useful tip you hear often might be to &ldquo;try to work on a weekly basis&rdquo;. They are talking about <em>planning</em> your week. If planning a whole doctorate is too difficult (it is, and it&rsquo;s scope will change often) - simply plan each week. I use <a href="https://trello.com/b/xbb3Wh56/phd-wouter">Trello</a> for that and you guessed it - it&rsquo;s open to the public. It&rsquo;s a bit more intricate than your average &ldquo;todo - doing - done&rdquo; list, but not by much:</p>
<ol>
<li>Todo - backlog: anything in here. Things I will need to do in the next months - years. Very vague items. Might and probably will be split in multiple items.</li>
<li>Todo - Week X [Deadline Y]: Something to work towards, for example a seminar you&rsquo;re attending or holding next month, or a brainstorm week you&rsquo;re holding with a research group where you can get feedback from your supervisor (or others).</li>
<li>Todo - Week X: the current week. What will you be doing this week? Try to be as descriptive and concrete as possible.</li>
<li>Doing</li>
<li>Done: timestamped.</li>
</ol>
<p>Apart from that, I&rsquo;m relying on the following labels:</p>
<ul>
<li>Red: BLOCKED (no separate column, preserves the overview). You want as little as possible of those. Check on those daily!</li>
<li>Green: WRITING</li>
<li>Blue: LITERATURE STUDY (research from others to go through)</li>
<li>Orange: FEEDBACK</li>
<li>Yellow: DOCTORAL STUDY (classes to attend)</li>
<li>Purple: ADMINISTRATION</li>
</ul>
<h3 id="the-_lean_-tools-used-to-battle-with">The <em>lean</em> Tools used to battle with</h3>
<p><figure>
<a href="../acm_notes.jpg" class="lbox">
<img loading="lazy" src="../acm_notes.jpg" alt="acm notes" >
</a>
</figure>
</p>
<h4 id="1-use-_analog_-tools">1. Use <em>analog</em> tools</h4>
<p>I have never had that much freedom in any long term project I&rsquo;ve ever worked on, than my own doctorate. I am the one who decides what to focus on and I am the one who decides which direction to go to - of course all in dialogue with my supervisors. But that liberating feeling generates a lot of <strong>wild new ideas</strong>. Those ideas present themselves on unexpected moments - so you better make sure you have something to write with and something to write on. My love for pen &amp; paper is <a href="/post/journaling-in-practice/">well known</a>. I jot down ideas, mindmaps and summaries of papers and manage to fill at least 2 A4 papers every single day.</p>
<p>As with all things, if you don&rsquo;t re-read your notes, they will be lost. See my post about <a href="/post/journaling-in-practice/">journaling in practice</a> for details on how to set up an easy, working system.<br/>
After the rough sketching skep, ripened and mature ideas might be worthy of a more substantial body.</p>
<h4 id="2-use-_simple_-digital-tools">2. Use <em>simple</em> digital tools</h4>
<p>Writing requires a&hellip; typewriter? Text editor? Sublime Text. Pushing to a github repository means we&rsquo;ll be using <code>git</code> and the command line (<code>iTerm</code>) a lot. I&rsquo;m a big fan of Markdown thanks to small but great generators like <code>Hugo</code> used on this site. Instead of redirecting everyone to the Github repository homepage, I converted my PhD repository to a Hugo website and published it as a Github Page. That means written Markdown files are instantly and easily readable by a bigger audience and sharing the work through a website is a bit easier.</p>
<p>Sublime works well in combination with Git and Markdown; especially with plugins like WordCount, MarkdownEditing, GitGutter, BracketHighlighter and Compare Side-By-Side. My choice for using Markdown instead of LaTeX might sound strange for academics, but Hugo&rsquo;s publishing skills are simply unmatched if you want feedback, fast. Things like Pandoc and AcademicMarkdown can be used to convert <code>.md</code> files to academic <code>.pdf</code> papers, like <a href="http://www.ericmjl.com/blog/2016/6/22/tooling-up-for-plain-text-academic-writing-in-markdown/">Eric J. Ma</a> did. More on that later when I&rsquo;m on the verge of actually publishing something in an academic journal.</p>
<h3 id="anything-else">Anything else?</h3>
<p>I&rsquo;m sure my methods of bootstrapping my research can be further enhanced by people who&rsquo;ve been through the whole process and are also agile advocates. If you think my work might benefit from some other tool or practice not mentioned here, please let me know by <a href="https://github.com/wgroeneveld/phd/issues">adding an issue in the Github repo</a> as feedback. Every remark is greatly appreciated!</p>
<p>In the meantime, take a second to skim through <a href="https://wgroeneveld.github.io/phd/">my work so far</a>. Thank you!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 19 October 2018.
</p>
]]>
</description>
</item>
<item>
<title>Productivity Tools on all platforms</title>
<link>https://brainbaking.com/post/2018/08/productivity-tools-multiplatform/</link>
<comments>https://brainbaking.com/post/2018/08/productivity-tools-multiplatform/#commento</comments>
<pubDate>Tue, 28 Aug 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/08/productivity-tools-multiplatform/</guid>
<category domain="https://brainbaking.com/tags/Productivity">Productivity</category>
<category domain="https://brainbaking.com/tags/tools">tools</category>
<description>
<![CDATA[
<p>I&rsquo;ve grown so accustomed to some of Neal Ford&rsquo;s <a href="https://www.goodreads.com/book/show/3411606-the-productive-programmer?from_search=true">The Productive Programmer</a> &ldquo;power tools&rdquo; that each time I install a new OS or get a new laptop, I start with my list of cant-live-without tools. I don&rsquo;t usually switch between OSes a lot, but my recent switch of work environment has opened up the possibility to boot Linux again, next to Windows 10 or of course my beloved own laptop with OSX.</p>
<p>Problem is, none of those tools seem to be 100% cross-platform or work <strong>exactly</strong> the same as I expect them to work. That can be a pain if I work on Ubuntu at work but on OSX at home, or if I need to switch to Windows for a student project. Alternatives almost always exist, so here&rsquo;s a short overview of my tooling usage with their counterparts on each OS.</p>
<p>Don&rsquo;t forget to take a look at the publication date of this page as especially Unix tools have the bad habit of dying within a few years&hellip; I will try to keep this up to date when I adopt another tool.</p>
<h3 id="100-cross-platform-tools">100% Cross-platform tools</h3>
<ol>
<li>IDEA IDEs like CLion, PyCharm and IntelliJ</li>
<li>Opera</li>
<li>Spotify</li>
<li>Any great editor: Sublime Text, Visual Studio Code, GVim</li>
</ol>
<p>The newer version of Opera has built-in adblock support and reduces battery drain for up to an hour compared to (lots of) open tabs with Chrome! My Macbook Air&rsquo;s battery is slowly giving up so that&rsquo;s a major factor for me. Opera&rsquo;s JS eninge uses the same one as Chrome by the way.</p>
<p>Shortcut usage in IDEs or editors can be confusing if you&rsquo;re used to the CMD or ALT keys of a Mac (or vice versa).</p>
<h3 id="quicklaunching">Quicklaunching</h3>
<p><strong>OSX</strong>: CMD+Space is all you need. There are tools that enhance the experience but I find them unneeded since El Capitan.</p>
<p><strong>Ubuntu</strong>: Unity&rsquo;s &ldquo;dash&rdquo; thing does almost what I want: it searches in possible software and files and it&rsquo;s (a bit) customizable. The only problem is mapping it to CMD (or CTRL)+Space. This can be done in the Keyboard shortcut settings, but after choosing CTRL+Space I had to revert to Super+Space: the latter key combination has already been heavily used to autocomplete statements in IDEs!</p>
<h4 id="same-alttab-behavior">Same ALT+TAB behavior</h4>
<p>Linux' virtual desktops makes for a very configurable environment but that also means ALT+TAB might or might not include windows in the current active desktop. I simply like to &ldquo;have them all&rdquo; in there, meaning I again had to modify some settings. I had to install the <strong>CompizConfig Settings Manager</strong> and go to Desktop -&gt; Ubuntu Unity Plugin -&gt; Launcher to fiddle with the available key options in subtab <em>&ldquo;switcher&rdquo;</em>.</p>
<h3 id="multitouch">Multitouch</h3>
<p><strong>OSX</strong>: built-in. Of course&hellip;</p>
<p><strong>Ubuntu</strong>: Again a bit of a pain, even if it comes with a lot of flexibility. Scrolling with both fingers works out of the box, but swiping combined with a browser does not - ALT+LEFT/RIGHT need to be mapped to swiping. <a href="https://github.com/iberianpig/fusuma">Fusuma</a> is a small Ruby tool that monitors input and executes things based on a config file. It does not work with 2 finger motions meaning I have to do an unnecessary context switch between OSX and Ubuntu&hellip;</p>
<p>After a week working with Fusuma and alternatives, I&rsquo;m a bit disappointed by the lack of a solid implementation. Scrolling to the next virtual window for example works but without releasing the touch pad, scrolling back to the previous (by swiping up again) doesn&rsquo;t: after a motion is recognized, touch input needs to be interrupted.</p>
<h3 id="clipboard-histroy">Clipboard histroy</h3>
<p><strong>Windows</strong>: Happy <a href="https://www.nakka.com/soft/clcl/index_eng.html">CLCL</a> user for years.</p>
<p><strong>OSX</strong>: <a href="http://www.clipmenu.com">ClipMenu</a> is free and works well.</p>
<p><strong>Ubuntu</strong>: <a href="https://launchpad.net/diodon">Diodon</a> does exactly what I need after mapping ALT+C to command <code>/usr/bin/diodon</code>.</p>
<h3 id="mail-clients">Mail clients</h3>
<p>If GMail isn&rsquo;t an option, like my current work address, a mail client that emulates a threaded view is the next best thing. Again OSX wins here with the built-in Mail application that works exactly as I want it to work.</p>
<p>As an alternative, on any OS, there&rsquo;s Mozilla <strong>Thunderbird</strong>. It is a hassle to get calendars and threaded views working though, I had to follow <a href="https://www.joshcurry.co.uk/posts/mozilla-thunderbird-show-sent-messages-in-thread-view">these steps</a> to show sent messages in thread view and that still isn&rsquo;t what I want. There are &ldquo;gmail conversation&rdquo;-alike plugins like <a href="https://addons.thunderbird.net/en-US/thunderbird/addon/gmail-conversation-view/">this one</a> that come as close as they can get to what I&rsquo;m aimnig for. Don&rsquo;t forget the Lightning Calendar extension.</p>
<h3 id="terminals">Terminals</h3>
<p><strong>Windows</strong>: Install <a href="http://cmder.net">Cmder</a> and never look back. The cygwin toolchain can also be installed, I&rsquo;m not sure if GCC is included with Cmder.</p>
<p><strong>OSX</strong>: Install <a href="https://www.iterm2.com">iTerm2</a> and never look back.</p>
<p><strong>Ubuntu</strong>: Still evaluating whether the default gnome-terminal is sufficient for me. You have to remap the creation of a new tab to CTRL+T in the settings if you&rsquo;re used to iTerm. <a href="http://guake-project.org">Guake</a> and <a href="https://launchpad.net/terminator">Terminator</a> seem like good fits, but the default terminal isn&rsquo;t that far away with CTRL+ALT+T.</p>
<h4 id="custom-commands">Custom commands</h4>
<p>That&rsquo;s simply a matter of configuring your <code>.bashrc</code> or <code>.bash_profile</code> files - given you think the bash shell is good enough. I&rsquo;ve used the Z shell for years but for what I do now, Bash is more than enough. I&rsquo;m not a big fan of installing a lot of power tools for the sake of installing them.</p>
<h3 id="misc-os-things">Misc OS Things</h3>
<h5 id="quick-access-to-development-folder">Quick access to development folder</h5>
<p>OSX&rsquo;s Finder makes it easy to create shortcuts for directories that have been heavily used, like my <code>~/development</code> dir where all repositories live. Luckily, Ubuntu&rsquo;s file manger also has this feature:</p>
<p><figure>
<a href="../files_linux.png" class="lbox">
<img loading="lazy" src="../files_linux.png" alt="linux files" >
</a>
</figure>
</p>
<h5 id="taking-screenshots-of-areas">Taking screenshots of areas</h5>
<p>Emulating OSX&rsquo;s CMD+ALT+4 on Ubuntu works by mapping CTRL+ALT+4 in the Keyboard shortcut manager to <code>gnome-screenshot -a</code>.</p>
<p>For Windows 10, if ALT+Screenshot or Win+Screenshot don&rsquo;t suffice (the problem is uniformity with other OSes here!), the snipping tool will work but doesn&rsquo;t have a shortcut bind to it. In the windows menu, rightclick on snipping tool after searching for it and set a shortcut key in tab &ldquo;Shortcut&rdquo;. CTRL+Screenshot then creates a new screenshot for an area.</p>
<h5 id="auto-expand-directories-when-hovering-files">Auto-expand directories when hovering files</h5>
<p>Very annoying but it seems that Gnome has this option disabled by default and you have to re-enable it with <code>gsettings set org.gnome.nautilus.preferences open-folder-on-dnd-hover true</code> in a CLI.</p>
<h5 id="window-movement-shortcuts">Window movement shortcuts</h5>
<p>This can get very far, I have used Fvwm once and spent weeks on perfecting my shortcut configuration for windows and window management. Luckily that time of fiddling about is over and I must say that the Win+Left/Right key combination in Windows (and Ubuntu) works quite well. Win+Up does nothing in Ubuntu though, so get ready to fiddle again if you want them to work exactly like in Windows&hellip;</p>
<p>For OSX, <a href="https://www.spectacleapp.com">Spectacle</a> is a requirement.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 28 August 2018.
</p>
]]>
</description>
</item>
<item>
<title>Boeken die mij gevormd hebben tot wie ik ben</title>
<link>https://brainbaking.com/post/2018/08/boeken-die-mij-gevormd-hebben/</link>
<comments>https://brainbaking.com/post/2018/08/boeken-die-mij-gevormd-hebben/#commento</comments>
<pubDate>Mon, 20 Aug 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/08/boeken-die-mij-gevormd-hebben/</guid>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/2017inbooks.png"/>
</p>
<p>Zoals <a href="/post/2017-in-books/">2017 in boeken</a> kan worden uitgedrukt, zo kan mijn leven in zijn geheel tot nu toe worden uitgedrukt in de boeken die het sterk beïnvloed heeft. Tijdens het lezen van Montaigne&rsquo;s Essays kwam ik tot de vaststelling dat ook Michel de onderwerpen van zijn &lsquo;Essais&rsquo; laat afhangen van de voorgaande werken die hij onder ogen heeft gekregen, zoals Cicero en Seneca in deel I. Iedereen moet immers zijn inspiratie ergens vandaan halen.</p>
<p>Met behulp van moderne tools als <a href="https://www.goodreads.com/review/list/5451893?order=a&amp;shelf=read&amp;sort=date_read">Goodreads</a> kan ik - tot op zekere hoogte - achterhalen welke boeken ik in welk jaar gelezen heb, en zo achterwaarts reconstrueren welke daarvan een blijvende indruk gemaakt hebben. Als je meer dan 12 boeken per jaar leest, stapelt dat wel eens op, en kan het gerust zijn dat je je de inhoud of korte samenvatting nauwelijks nog kan herinneren. Dan is de keuze op gebied van beïnvloeding snel gemaakt.</p>
<h3 id="in-mijn-jeugd">In mijn jeugd</h3>
<p>Ik ben vrij vroeg begonnen met het lezen van volwassen romans in de vorm van &ldquo;fantasy&rdquo; fictie. Mijn vader bewaarde vanuit zijn eigen jeugd een kopie van Lord of the Rings: de tweeëntwintigste druk van 1979 om exact te zijn. De erg vergeelde boeken heb ik dan ook plichtbewust doorworsteld, maar ik denk dat ik eerder zelf tot die fantasy categorie ben terecht gekomen. Mijn ouders zijn geen literaire meesters en hebben dan ook net als alle scholen weinig moeite ondernomen om hun kinderen die voor mij nu levensbelangrijke vaardigheid mee te geven.</p>
<p>Een van de eersten moet Roger Zelazny&rsquo;s Amber serie geweest zijn (of J.V. Jones' Boek der Woorden reeks), gevolgd door Robin Hobb&rsquo;s Boeken van de Zieners. Ik kan mij niet herinneren dat ik ooit één non-fictie boek heb aangeraakt in mijn jeugd, buiten de schoolplichtige zaken die met grote tegenzin wel diagonaal bekeken werden. De gedetailleerde fantasie werelden waren een ideale plaats om als teruggetrokken tiener in weg te dromen: waar alles groots, uitdagend, en vooral ook betekenisvol was. David Eddings liet me mijn voorkeur voor het ik-perspectief ontwikkelen met zijn Belgarath reeks.</p>
<p>Klassiekere fantasy reeksen zoals Het Zwaard Der Waarheid en het Rad Des Tijds leerde ik veel later in mijn universiteitsjaren kennen, waar vrienden dezelfde smaak vertoonden. Ik zal nooit Tolkien als dé fantasy schrijver aanhalen maar dat eerder aan Hobb, Eddings of Zelazny toewijden. Een uitzondering op de regel is Stephen King&rsquo;s Ogen van de Draak: een eenzaat waarbij ik bijna een ander soort boek in handen kreeg. Mijn vader zijn Duin boek heeft me nooit kunnen overtuigen dat science-fiction mij meer zou liggen dan fantasy. Ik herinner me nog (veel) science-fiction boeken van Isaac Asimov die amusant, maar niet blijvend overkwamen. Er werd veel verslonden in die tijd: alles om maar niet te veel aanwezig te zijn in het heden.</p>
<h3 id="de-ontdekking-van-non-fictie">De ontdekking van non-fictie</h3>
<p>Mijn dagboeken gaan niet verder terug dan 2010 en dat heeft een reden: <em>self-help</em> boeken als Power Thinking van Caterina Rando en Getting Things Done van David Allen markeren het prille begin van mijn zelf-reflectiviteit. Ik was mij toen nog niet bewust dat dit uiteindelijk flauwe afkooksels zijn van oudere filosofische aspecten, zoals Aristoteles' deugdethiek. Ideeën neerpennen om er later iets mee te doen werd alleen maar meer toegepast na het lezen van Your Brain at Work van David Rock en Where Good Ideas Come From van Steven Johnson.</p>
<p>Op gebied van mijn werk als beginnende software ingenieur bleef toen vooral gek genoeg Presentation Zen van Garr Reynolds hangen: goede technische boeken die ik de afgelopen 10 jaren gelezen heb kan ik op één hand tellen (waaronder als eenzaat Structure and Interpretation of Computer Programs van Abelson en Sussman). Ik begon meer interesse in <em>meta-skills</em> te vertonen en las graag verhalende toppers van onder andere Malcolm Gladwell.</p>
<p>Diezelfde periode markeerde ook het begin van het verplichte keukenwerk waardoor mijn vader zijn meegegeven interesse voor koken eindelijk begon te leven. Ik heb toen ik bij mijn ouders woonde geen enkele keer zelf gekookt buiten het omdraaien van de eenzame pannenkoek, maar was wel telkens geïntrigeerd door de geproduceerde geuren en vooral het bakproces. Ik begon het internet te gebruiken als onderzoeksbodem en stootte tegen boeken die verantwoordelijkheid uitdroegen: The Story of Stuff van Annie Leonard en Eating Animals van Jonathan Safran Foer. Daarna heb ik zonder moeite geen enkel stuk vlees of vis meer aangeraakt.</p>
<p>In 2012 kocht ik Bread van Jeffrey Hamelman, nadat ik op een blog iets gevonden had over zuurdesem brood. Op zoek naar de smaak van dat perfecte stukje brood, gegeten in een restaurant waar we als familie vroeger jaarlijks naar toe gingen te Spanje. De laatste 6 jaar ben ik onder andere dankzij dit boek zo intensief bezig geweest met brood bakken dat ik nu een <a href="https://redzuurdesem.be/">gediplomeerde bakker</a> ben, én bij de bekende Gentse bakkerij De Superette als stagair heb meegedraaid. Als dat geen invloed van een boek is weet ik het ook niet meer. Dat één inspirerend <a href="https://redzuurdesem.be/brood-bak-boeken-welk-exemplaar-kopen-1/">boek over brood</a> werden er meer met onder andere Local Breads van Daniel Leader en natuurlijk Chad Robertson&rsquo;s werk. Weet wel dat die invloeden bewust door mijn dagelijks disciplinair schrijven versterkt werden!</p>
<h3 id="de-ontdekking-van-spiritualiteit">De ontdekking van spiritualiteit</h3>
<p>Zelf-reflectie werd verder uitgediept door simpelweg meer te schrijven, en door &ldquo;Zen of het konijn in ons brein&rdquo; van Tom Hannes of &ldquo;De 7 geheimen van de schildpad: verborgenheid vinden in jezelf&rdquo; van Ronald Schweppe. Fantasy werd verbannen naar de achterkant van de boekenkast. De sporadische Donkere Toren boek hield me enkel op de trein naar het werk bezig: het serieuze werk, met name het uitdiepen van mijn eigenheid, had duidelijke voorrang gekregen. Search Inside Yourself van Chade-Meng Tan sluit in 2014 perfect bij dit rijtje aan van memorabele openbaringen.</p>
<p>Ondertussen vond ik op software gebied mijn gading in JavaScript: the Good parts van Douglas Crockford, en begon ik ook met collega&rsquo;s op te leiden in prototypal inheritance. Ik merk trouwens dat bij het overlopen van de Goodreads lijst weinig boeken die ik 4 of 5 sterren heb gegeven mij bij gebleven zijn als &ldquo;sterk beïnvloed door&rdquo;. Mijn fysieke bibliotheek wordt regelmatig bijgewerkt met nieuwigheden die gelezen interessante maar niet inspirerende boeken vervangen. Diegene die de tand des tijds doorstaan zijn voor mij daarom dus de meest relevanate die het herlezen waardig zijn.</p>
<p>Populaire wetenschap lees ik graag als tussendoortje en blijft gedoemd om tot die &lsquo;afwisseling&rsquo; te behoren: ik herinner mij er slechts vaag titels en grote lijnen van, zoals Dreamland van David K. Randall, Moonwalking with Einstein van Joshua Foer of Bird Sense van Tim Birkhead. Quiet van Susan Cain valt voor mij ook in de zelf-reflectie categorie, en heeft me ook iets over mezelf geleerd, wat het boek promoveert tot een permanente plaats in de kast. Afwisseling is nodig, maar af en toe moet ik kunnen afwisselen van de afwisseling.</p>
<p>Gladwell&rsquo;s exceptionele performers in zijn boeken leidden me tot Linchpin van Seth Godin, Willpower van Roy F. Baumeister en Mojo van Marshall Goldsmith. Dankzij die boeken ben ik mij meer gaan interesseren in motivatie en trad ik op als coach, lesgever en <a href="/post/handing-over-enough-when-inspiring/">inspirator</a>. Ik probeer mijn ontdekkingen die je hier (en in mijn dagboeken) kan lezen door te geven door mensen aan te sporen deze voor mij belangrijke boeken ook een kans te geven. Iedereen vindt zichzelf in een ander boek terug natuurlijk: Power Thinking is eigenlijk maar een belachelijk dun boekje met weinig inhoud. Ik vergeet nog bijna het technischer werk Pragmatic Thinking &amp; learning van Andy Hunt dat ik dankzij een leesgroepje op het werk heb leren kennen.</p>
<h3 id="voorbij-positieve-psychologie">Voorbij positieve psychologie</h3>
<p>Voor onze zomervakantie huurden we ooit via Airbnb onder andere een appartement in Nancy, dat tot onze verbazing iemands effectieve woonst was. Het is geweldig om rond te snuffelen in andermans boeken, en daar trof ik in een rommelig hoekje op het nachtkastje buiten haar eigen dagboek, wat ik respectvol heb laten liggen, een kopie van Alain de Botton&rsquo;s the Art of Travel aan. De inhoud sloeg nog niet dadelijk aan maar het zaadje was toen al gepland.</p>
<p>Op gebied van voedsel spelen twee boeken voor mij in 2015 een belangrijke rol: Cooked van Michael Pollan en The Art of Fermentation van Sandor Katz. Pollan&rsquo;s leuke geschiedenisles leert me beter nadenken over verschillende kooktechnieken en zet me aan om nog meer er over op te zoeken, terwijl Katz' kloefer over fermenteren mijn passie rond kweken van bacteriën verbreed van enkel desem naar tempeh, koji en kefir. Mort Rosenblum zijn persoonlijke verbintenis met de olijvenboom gaf me genoeg stof tot nadenken over ouderdom en herkomst van producten die we zo <a href="post/nuts-about-local-nuts/">achteloos dagelijks in de keuken hanteren</a>.</p>
<p>Een hoop middelmatige boeken later las ik Flow van Mihaly Csikszentmihalyi (ik heb de naam moeten kopiëren) en Lessen in Levenskunst van Wilfried van Craen. De vorige boeken refereerden al vaak naar Flow en het boek zelf vond ik niet zo geweldig, maar ik probeer het concept wel een belangrijke rol te laten spelen in mijn leven. Wilfried&rsquo;s gelatenheid en gezapige verhalen waren de ideale compaignon op een <em>&ldquo;nadenk vakantie&rdquo;</em>. Edward Slingerhand introduceerde me in de wereld van Lao Tzu en Confucius met Trying not to try, iets wat smaakte naar meer.</p>
<p>Die <em>&ldquo;meer&rdquo;</em> kreeg in 2016 vorm in Hamlet&rsquo;s Blackberry van William Powers en Zen and the Art of Motorcycle Maintenance van Robert M. Pirsig, alhoewel die laatste niet bepaald een &ldquo;blijvende&rdquo; indruk heeft nagelaten ben ik toch blij dat ik deze gelezen heb. Hamlet&rsquo;s Blackberry is weer zo&rsquo;n boek dat ik heel toevallig ben tegengekomen, door een opruimactie van een vriend wegens verhuis. Hij had het boek niet eens gelezen&hellip;</p>
<p>Mijn gestructureerde, materialistische geest werd dankzij Marie Kondo gewezen op &ldquo;Opgeruimd!&rdquo;, waarbij ik prompt &ldquo;minimalisme&rdquo; en &ldquo;ontspullen&rdquo; naar voren schoof door verwoede lokale opruimacties organiseerde, tot de grootste ergernis van mijn vrouw. Ik ben nog steeds van plan om ooit &ldquo;Goodbye, Things: The New Japanese Minimalism&rdquo; te lezen van Fumio Sasaki.</p>
<h3 id="intermezzo">Intermezzo</h3>
<p>Robin Hobb haar Boeken van de Zieners werden waardig afgesloten met de laatste trilogie die ik natuurlijk absoluut moest lezen: boeken van 600+ pagina&rsquo;s waar je niet onmiddellijk klaar mee bent. Haar boeken van de Zoon van de Krijger relaas stelde me diep teleur door de overdreven langdradige beschrijvingen, waarbij ik de <em>punch</em> van FitzChevalric in haar andere reeks erg miste.</p>
<p>Enkele reisverhalen vonden hun intrede in mijn kast: het erg luchtige Vagabond Dreams van &ldquo;den&rdquo; Ryan Murdock wiens blog ik al een tijdje in het oog hield en de wereldklassieker &ldquo;A Walk in the Woods&rdquo; van Bill Bryson wiens verfilming op niets trok. Haaienkoorts van Morten A. Strøksnes was ook een leuke tip van een collega, maar vooral Bill deed me kleiner dan mezelf voelen in dit prachtige universum. Na het ophangen van mijn floret en degen vond ik troost bij Richard Cohen&rsquo;s By the Sword. Ik heb nog steeds geen echte vrede kunnen nemen met mijn beslissing om te stoppen met schermen, ook al las ik er een erg goed verhaal over.</p>
<p>Mijn andere nieuwe hobby, tekenen, betekende een nieuwe <em>rayon</em> in de kast waarbij vooral Danny Gregory&rsquo;s &ldquo;The Creative Licence&rdquo; en andere boeken mij enorm inspireerde door zijn persoonlijk verhaal en tekenstijl met vulpen en waterverf. Dankzij Drawing on the Right Side of the Brain van Betty Edwards kan ik <a href="/post/teaching-yourself-to-draw/">beter tekenen</a> dan mijn belachelijke pogingen in het middelbaar. The Art of Urban Sketching van Gabriel Campanario zet mij voorgoed in het pad van vulpen (en misschien ooit waterverf). Begin 2017 markeert ook het begin van mijn primitief inzicht in kunst met voornamelijk Alain de Botton&rsquo;s &ldquo;Art as Therapy&rdquo; en een aantal memorabele brieven van Vincent van Gogh.</p>
<p>Na Sandor&rsquo;s fermentatie bijbel mag ik wel zeggen, verdient Bar Tartine een tweede plaats dankzij een verjaardagscadeau. Je kan er veel gespecialiseerde technieken in terugvinden rond drogen, opleggen, fermenteren, verpoederen, mixen, &hellip; De meeste traditionele kookboeken kunnen me maar matig boeien: er een aantal keer door grasduinen levert wat tijdelijke inspiratie op en dat is het dan ook.</p>
<h3 id="aankomst-bij-filosofie">Aankomst bij filosofie</h3>
<p>Dankzij Hamlet&rsquo;s Blackberry en een hoop referenties las ik verder tot Philosophy for Life van Jules Evans en Roman Krznaric&rsquo;s Wonderbox. Roman en Alain zitten samen in the School of Life, waar in tal van dagboeken aantekening van terug te vinden zijn. Uiteindelijk las ik dankzij wat rondsnuffelen in de bibliotheek Marcus Aurelius' Meditaties. Die verdient zeker een vaste plaats maar moet nog aangekocht worden. Epicurus en Epictetus waren volgende waarbij eerlijk gezegd enkel Marcus mij inspireert: zijn reflectie is makkelijker over te zetten op eigen daden.</p>
<p>Oosterse filosofie in de vorm van Miyamoto&rsquo;s <a href="/post/a-samurai-learning-mindset">boek der 5 ringen</a> en Shunryu Suzuki&rsquo;s Zen Mind, Beginner Mind boden de nodige tegenhangers van al dat Westers filosofisch geweld. De troost van de filosofie leerde me de Botton&rsquo;s werk in populaire, aanspreekbare filosofie pas echt appreciëren.</p>
<p>Dan belanden we in het huidige 2018 waar weeral filosofie centraal staat met Donald Palmer&rsquo;s universitaire introducties, die redelijk licht verteerbaar zijn, en het uitmuntende &ldquo;Brief aan een middelmatige man&rdquo; van Joep Dohmen die pleit voor zelfontplooiing, waar ik de laatste 8 jaren dankzij mijn dagboeken al <a href="/post/journaling-in-practice">intensief mee bezig ben</a>.</p>
<p>De kans is groot dat ik een aantal belangrijke werken vergeten ben doordat ik graag boeken weggeef in de hoop anderen te inspireren, en dus vergeet wat het voor mij betekende. Ik heb te veel notities om dit allemaal nog na te kunnen gaan. In ieder geval geeft het (veel) lezen van (veel) verschillende (non-fictie) onderwerpen mij enorm veel voldoening, en blijft er hier en daar eens een boek plakken als inspiratie. Dit zijn de boeken die mij maken tot wie ik tot nu toe ben. Ik heb in de loop der jaren vooral geleerd dat die <em>&ldquo;ben&rdquo;</em> in de vorige zin erg dynamisch is: wat ik nu ben, ben ik morgen immers (misschien) niet meer&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 20 August 2018.
</p>
]]>
</description>
</item>
<item>
<title>Domain Driven Design in C</title>
<link>https://brainbaking.com/post/2018/08/domain-driven-design-in-c/</link>
<comments>https://brainbaking.com/post/2018/08/domain-driven-design-in-c/#commento</comments>
<pubDate>Fri, 03 Aug 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/08/domain-driven-design-in-c/</guid>
<category domain="https://brainbaking.com/tags/domain driven design">domain driven design</category>
<category domain="https://brainbaking.com/tags/C">C</category>
<category domain="https://brainbaking.com/tags/C&#43;&#43;">C&#43;&#43;</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Faking%20domain%20logic.jpg"/>
</p>
<p>As old as the language C may be, it took other languages a long time to catch up with something as mundane as a pointer. Pointers are the bread and butter of any C program and are widely regarded as a horrifying thing to work with. It might be a drag and require some plumbing (as with any language) but the payoff is extreme flexibility and control.</p>
<p>An address can point to anything - that includes functions. Function pointers are mostly used as callbacks but in combination with structures, they become dynamic class members! That might be a little bit exaggerated.</p>
<p>Let&rsquo;s take a look at simple concepts: a person has a certain age.</p>
<script defer src="/mermaid/mermaid.min.js">
mermaid.initialize({
startOnLoad: true,
flowchart: {
useMaxWidth: true
}
});
</script>
<div class="mermaid" align="center" >
graph LR;
A{Person}
B[Age]
C[Is Old?]
A --> B
A -.-> C
</div>
<p>I can ask the person if he&rsquo;s old, and depending on the age the response will be yes (<code>true</code>) or no (<code>false</code>). Sounds almost too simple to implement in an object-oriented language like C#:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C#" data-lang="C#"><span style="color:#728e00">class</span> <span style="color:#434f54">Person</span> {
<span style="color:#728e00">public</span> <span style="color:#434f54">Person</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">age</span>) { <span style="color:#728e00">this</span>.<span style="color:#434f54">Age</span> = <span style="color:#434f54">age</span>; }
<span style="color:#728e00">public</span> <span style="color:#00979d">int</span> <span style="color:#434f54">Age</span> { <span style="color:#728e00">get</span>; <span style="color:#728e00">private</span> <span style="color:#728e00">set</span>; }
<span style="color:#728e00">public</span> <span style="color:#00979d">bool</span> <span style="color:#434f54">IsOld</span> =&gt; <span style="color:#434f54">Age</span> &gt; <span style="color:#8a7b52">60</span>;
}
<span style="color:#434f54">Person</span> <span style="color:#434f54">george</span> = <span style="color:#728e00">new</span> <span style="color:#434f54">Person</span>(<span style="color:#8a7b52">65</span>);
<span style="color:#434f54">Debug</span>.<span style="color:#434f54">WriteLine</span>(<span style="color:#434f54">george</span>.<span style="color:#434f54">IsOld</span>); <span style="color:#95a5a6">// true
</span></code></pre></div><p>Thinking about the <code>class</code> concept in OO nets you the <code>struct</code> concept in C that will hold the age field nicely, but problems arise when we try to tackle the <code>Is Old?</code> piece of the domain model:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C" data-lang="C"><span style="color:#728e00">struct</span> <span style="color:#434f54">Person</span> {
<span style="color:#00979d">int</span> <span style="color:#434f54">age</span>;
}
<span style="color:#00979d">int</span> <span style="color:#434f54">is_old</span>(<span style="color:#434f54">Person</span><span style="color:#728e00">*</span> <span style="color:#434f54">p</span>) {
<span style="color:#728e00">return</span> <span style="color:#434f54">p</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">age</span> <span style="color:#728e00">&gt;</span> <span style="color:#8a7b52">60</span>;
}
<span style="color:#728e00">typedef</span> <span style="color:#728e00">struct</span> <span style="color:#434f54">Person</span> <span style="color:#434f54">Person</span>;
<span style="color:#434f54">Person</span><span style="color:#728e00">*</span> <span style="color:#434f54">george</span> <span style="color:#728e00">=</span> <span style="color:#434f54">malloc</span>(<span style="color:#728e00">sizeof</span>(<span style="color:#434f54">Person</span>));
<span style="color:#434f54">george</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">age</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">65</span>;
<span style="color:#434f54">prinf</span>(<span style="color:#7f8c8d">&#34;%d&#34;</span>, <span style="color:#434f54">is_old</span>(<span style="color:#434f54">george</span>)); <span style="color:#95a5a6">// 1
</span></code></pre></div><p>A couple of remarks:</p>
<ol>
<li>C has no <code>bool</code>.</li>
<li>If you want to use your structure as a class, <code>typedef</code> is pretty much required.</li>
<li>This introduces a memory leak if you don&rsquo;t <code>free(george)</code>.</li>
</ol>
<p>And of course, our main concern is the absence of any link between <code>struct Person</code> and <code>int is_old</code>. If the function is defined in a random header, the programmer has to remember it&rsquo;s location and it&rsquo;s name. It only sounds logical that it should be an integral part of the structure.</p>
<p>And it shall be - function pointers to the rescue!</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C" data-lang="C"><span style="color:#728e00">struct</span> <span style="color:#434f54">Person</span> {
<span style="color:#00979d">int</span> <span style="color:#434f54">age</span>;
<span style="color:#00979d">int</span> (<span style="color:#728e00">*</span><span style="color:#434f54">is_old</span>)();
}
</code></pre></div><p>That makes expressions as <code>george-&gt;is_old()</code> legal, but they won&rsquo;t be bind to anything. The pointer doesn&rsquo;t point to anything and we can&rsquo;t define the function within the structure. It needs to be <strong>defined</strong> somewhere else, and <strong>rewired</strong> to the pointer:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C" data-lang="C"><span style="color:#728e00">struct</span> <span style="color:#434f54">Person</span> {
<span style="color:#00979d">int</span> <span style="color:#434f54">age</span>;
<span style="color:#00979d">int</span> (<span style="color:#728e00">*</span><span style="color:#434f54">is_old</span>)();
}
<span style="color:#00979d">int</span> <span style="color:#434f54">person_is_old</span>(<span style="color:#434f54">Person</span><span style="color:#728e00">*</span> <span style="color:#434f54">p</span>) {
<span style="color:#728e00">return</span> <span style="color:#434f54">p</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">age</span> <span style="color:#728e00">&gt;</span> <span style="color:#8a7b52">60</span>;
}
<span style="color:#728e00">typedef</span> <span style="color:#728e00">struct</span> <span style="color:#434f54">Person</span> <span style="color:#434f54">Person</span>;
<span style="color:#434f54">Person</span><span style="color:#728e00">*</span> <span style="color:#434f54">george</span> <span style="color:#728e00">=</span> <span style="color:#434f54">malloc</span>(<span style="color:#728e00">sizeof</span>(<span style="color:#434f54">Person</span>));
<span style="color:#434f54">george</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">is_old</span> <span style="color:#728e00">=</span> <span style="color:#728e00">&amp;</span><span style="color:#434f54">person_is_old</span>;
<span style="color:#434f54">george</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">age</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">65</span>;
<span style="color:#434f54">prinf</span>(<span style="color:#7f8c8d">&#34;%d&#34;</span>, <span style="color:#434f54">is_old</span>(<span style="color:#434f54">george</span>)); <span style="color:#95a5a6">// 1
</span></code></pre></div><p>Isn&rsquo;t that beautiful?</p>
<p>It&rsquo;s rather cumbersome indeed, because the creation of a new person requires you to manually wire up the function to the function pointer of the struct instance and that hurts - a lot. That&rsquo;s the price to pay for emulating member functions on structures as classes&hellip;</p>
<p>Our last cleanup action would be to group every person-related thing into <code>person.h</code> and <code>person.c</code>, and lastly create a nice factory method for allocation of a new person:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C" data-lang="C"><span style="color:#434f54">Person</span><span style="color:#728e00">*</span> <span style="color:#d35400">newPerson</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">age</span>) {
<span style="color:#434f54">Person</span><span style="color:#728e00">*</span> <span style="color:#434f54">p</span> <span style="color:#728e00">=</span> <span style="color:#434f54">malloc</span>(<span style="color:#728e00">sizeof</span>(<span style="color:#434f54">Person</span>));
<span style="color:#434f54">p</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">age</span> <span style="color:#728e00">=</span> <span style="color:#434f54">age</span>;
<span style="color:#434f54">p</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">is_old</span> <span style="color:#728e00">=</span> <span style="color:#728e00">&amp;</span><span style="color:#434f54">person_is_old</span>;
<span style="color:#728e00">return</span> <span style="color:#434f54">p</span>;
}
</code></pre></div><h3 id="what-about-c">What about C++?</h3>
<p>Are you wondering what the ++ in C++ might stand for? The addition of &ldquo;real&rdquo; classes is a revelation to old-time C programmers that tried aiming for readability in a &ldquo;domain&rdquo;<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. The above example implemented in C++ is trivial:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C" data-lang="C"><span style="color:#434f54">class</span> <span style="color:#434f54">Person</span> {
<span style="color:#434f54">private</span>:
<span style="color:#00979d">int</span> <span style="color:#434f54">age</span>;
<span style="color:#434f54">public</span>:
<span style="color:#434f54">Person</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">age</span>) <span style="color:#728e00">:</span> <span style="color:#434f54">age</span>(<span style="color:#434f54">age</span>) {}
<span style="color:#00979d">bool</span> <span style="color:#434f54">isOld</span>() { <span style="color:#728e00">return</span> <span style="color:#434f54">age</span> <span style="color:#728e00">&gt;</span> <span style="color:#8a7b52">60</span> <span style="color:#728e00">?</span> <span style="color:#728e00">true</span> <span style="color:#728e00">:</span> <span style="color:#728e00">false</span>; }
};
</code></pre></div><p>The <code>isOld</code> member function of Person is a one-liner that can be an <code>inline</code> function - if it&rsquo;s defined within the class definition structure that usually lives in the header file. Otherwise; <code>bool Person::isOld() {}</code> has to be present in some cpp source file.</p>
<h3 id="but-cs-function-pointer-is-_dynamic_">But&hellip; C&rsquo;s function pointer is <em>dynamic</em>!</h3>
<p>That&rsquo;s right! That means it&rsquo;s much more than an emulated member function of a structure. You can rewire it at any time - it works just like a callback. Of course that is clearly not what we want here. Also notice the complete lack of any accessor modifiers in C: any function can fuck up our passed Person:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C" data-lang="C"><span style="color:#00979d">void</span> <span style="color:#d35400">haxx</span>(<span style="color:#434f54">Person</span><span style="color:#728e00">*</span> <span style="color:#434f54">p</span>) {
<span style="color:#434f54">p</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">is_old</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>; <span style="color:#95a5a6">// whoops
</span><span style="color:#95a5a6"></span>}
</code></pre></div><p>Fixed using C&rsquo;s pass-by-value system by leaving out the pointer <code>*</code> in the argument list. But you really don&rsquo;t want to do that with a structure as copying something like that requires quite a bit of memory overhead and beats the whole purpose of using C in the first place&hellip;</p>
<p>Remember Java fan-boys, we had to wait until Java 8 in 2014 for the language to catch up with C using lambda&rsquo;s. Take a look at what function pointers are really for:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C" data-lang="C"><span style="color:#00979d">int</span> <span style="color:#d35400">addOne</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">g</span>) { <span style="color:#728e00">return</span> <span style="color:#434f54">g</span> <span style="color:#728e00">+</span> <span style="color:#8a7b52">1</span>; }
<span style="color:#00979d">int</span> <span style="color:#d35400">multiplyTwo</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">g</span>) { <span style="color:#728e00">return</span> <span style="color:#434f54">g</span> <span style="color:#728e00">*</span> <span style="color:#8a7b52">2</span>; }
<span style="color:#00979d">int</span> <span style="color:#d35400">main</span>() {
<span style="color:#00979d">int</span> (<span style="color:#728e00">*</span><span style="color:#434f54">op</span>)(<span style="color:#00979d">int</span>) <span style="color:#728e00">=</span> <span style="color:#728e00">&amp;</span><span style="color:#434f54">addOne</span>;
<span style="color:#434f54">printf</span>(<span style="color:#7f8c8d">&#34;%d&#34;</span>, <span style="color:#434f54">op</span>(<span style="color:#8a7b52">5</span>)); <span style="color:#95a5a6">// prints 6
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">return</span> <span style="color:#8a7b52">0</span>;
}
</code></pre></div><p>Can you imagine doing that in Java 7? With anonymous inner classes and a lot of interface clumsiness, maybe. It&rsquo;s a much less worse now with v8&rsquo;s lambda&rsquo;s and the new function reference operator <code>::</code>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-Java" data-lang="Java"><span style="color:#728e00">class</span> <span style="color:#434f54">Stuff</span> <span style="color:#728e00">{</span>
<span style="color:#728e00">private</span> <span style="color:#728e00">static</span> <span style="color:#00979d">int</span> <span style="color:#d35400">addOne</span><span style="color:#728e00">(</span><span style="color:#00979d">int</span> <span style="color:#434f54">g</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span> <span style="color:#728e00">return</span> <span style="color:#434f54">g</span> <span style="color:#728e00">+</span> <span style="color:#434f54">1</span><span style="color:#728e00">;</span> <span style="color:#728e00">}</span>
<span style="color:#728e00">private</span> <span style="color:#728e00">static</span> <span style="color:#00979d">int</span> <span style="color:#d35400">multiplyTwo</span><span style="color:#728e00">(</span><span style="color:#00979d">int</span> <span style="color:#434f54">g</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span> <span style="color:#728e00">return</span> <span style="color:#434f54">g</span> <span style="color:#728e00">*</span> <span style="color:#434f54">2</span><span style="color:#728e00">;</span> <span style="color:#728e00">}</span>
<span style="color:#728e00">public</span> <span style="color:#728e00">static</span> <span style="color:#00979d">void</span> <span style="color:#d35400">main</span><span style="color:#728e00">(</span><span style="color:#434f54">String</span><span style="color:#728e00">[]</span> <span style="color:#434f54">args</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">Function</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">Integer</span><span style="color:#728e00">,</span> <span style="color:#434f54">Integer</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">op</span> <span style="color:#728e00">=</span> <span style="color:#434f54">Stuff</span><span style="color:#728e00">::</span><span style="color:#434f54">addOne</span><span style="color:#728e00">;</span>
<span style="color:#434f54">System</span><span style="color:#728e00">.</span><span style="color:#434f54">out</span><span style="color:#728e00">.</span><span style="color:#434f54">println</span><span style="color:#728e00">(</span><span style="color:#434f54">op</span><span style="color:#728e00">.</span><span style="color:#434f54">apply</span><span style="color:#728e00">(</span><span style="color:#434f54">5</span><span style="color:#728e00">)</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34;&#34;</span><span style="color:#728e00">);</span> <span style="color:#95a5a6">// prints 6
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">}</span>
<span style="color:#728e00">}</span>
</code></pre></div><p>That leaves us to conclude that if you&rsquo;re still writing C on some embedded hardware, don&rsquo;t forget that it is possible to group functions using structures but requires some plumbing that you may or may not like.</p>
<p>The C++ language is continually evolving while the ANSI C standard is &ldquo;done&rdquo;<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> - the C++11 standard eased a lot of the mystical syntax pain. So if you can migrate from <code>gcc</code> to <code>g++</code>, I don&rsquo;t see why not.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>DDD practices can&rsquo;t be implemented without proper use of an object model - within that context I&rsquo;m calling that &ldquo;domain&rdquo; driven. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Well, not completely, <a href="https://en.wikipedia.org/wiki/ANSI_C#C11">C11</a> introduced an cross-platform multi-threading API. <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 3 August 2018.
</p>
]]>
</description>
</item>
<item>
<title>Over de inflatie van intellect</title>
<link>https://brainbaking.com/post/2018/07/over-intellect/</link>
<comments>https://brainbaking.com/post/2018/07/over-intellect/#commento</comments>
<pubDate>Tue, 24 Jul 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/07/over-intellect/</guid>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/overintellect.jpg"/>
</p>
<p>Het resultaat van een onderzoek dat ik las in Frank Furedi&rsquo;s &ldquo;Waar zijn de intellectuelen?&rdquo; boezemt mij veel angst in: minder dan de helft van de samenleving wil tegenwoordig nog literatuur lezen. En dit gaat dan nog over literatuur! Ik ken veel mensen die met hun ogen draaien zodra ik nog maar het woord &ldquo;boek&rdquo; uitspreek, laat staan een conversatie over filosofie aan te gaan. Ik had er niet bij stilgestaan dat dit eenvoudig geëxtrapoleerd kan worden.</p>
<p>De eendimensionaliteit die in tegenwoordige media voorkomt is schrijnend. Zelfs als je een amusementsprogramma als het populaire &ldquo;De Kampioenen&rdquo; bekijkt door de jaren heen. De eerste 4 seizoenen bevatten (hier en daar) nog gevatte zinspelingen naar moeilijkheden in het leven die voor de kijker herkenbaar zijn. Een (klein) beetje diepgang, meer niet. Dat gecombineerd met de juiste dosis humor maakte de serie tot een groot succes. Maar 20 jaar later is De Kampioenen een erg holle echo van een ver verleden waarin alle mopjes platgeklopt worden en alle personages belachelijk gemaakt worden.</p>
<p>Het ergerlijke gevoel van beschuldiging van domheid bekruipt mij als ik kijk naar recente afleveringen. Sommige TV zenders zoals Vier zijn daar expert in: na de reclame een korte herhaling presenteren. Het moest maar eens zijn dat de kijker even onoplettend is geweest, of misschien simpelweg te stom op 15 minuten lang een belachelijk eenvoudig plot te kunnen onthouden. Gruwelijk ergerlijk en een regelrechte belediging noem ik dat.</p>
<p>Frank noemt dit de infantilisering van het publiek, of de McDonaldisering van cultuur:</p>
<blockquote>
<p>[&hellip;] Professionele tekstschrijvers gaan tewerk alsof hun publiek uit snel afgeleide kinderen bestaat [&hellip;] Kennis is een product geworden dat door vrijwel alle belangrijke instituties wordt afgenomen. Helaas kent de hedendaagse verbeelding kennis een oppervlakkig, bijna banaal karakter toe. Vaak wordt kennis voorgesteld als een geprefabriceerd, hapklaar product dat geleverd, overgedragen, op de markt gebracht en geconsumeerd kan worden.</p>
</blockquote>
<p>Een recente workshop &ldquo;bedrijfsgerichte artikels schrijven&rdquo; op het werk liet een wrange smaak achter. De focus op zo kort mogelijke zinnen om &ldquo;tot de essentie&rdquo; te komen slaat op niets: het gaat gewoon over geprefabriceerde, hapklare stukjes informatie in het strot van het gewillig publiek rammen. Het is alsof wij ervan uitgaan dat het publiek per definitie niet slim genoeg is om informatie te interpreteren. Ik heb vriendelijk gepast: die schrijfstijl ligt mij niet. Het zal niemand verbazen dat de de workshop georganiseerd werd door journalisten met een te scherpe pen.</p>
<p>Zelfs een kijkje nemen naar strips levert ons dezelfde conclusie op. Neem nu een Suske en Wiske van 1950: <a href="https://nl.wikipedia.org/wiki/De_bronzen_sleutel">De Bronzen Sleutel</a>. Er is veel tekst, het thema is volwassen en de mopjes zijn nog niet afgekookt. <em>Fast forward</em> naar 2018: BaRaBaS 2.0. Groot lettertype, weinig tekst, holle inhoud:<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<blockquote>
<p>Ook voor de kinderen hebben we de beeldtaal vergemakkelijkt. Er staan nu minder tekstballonnetjes in een prentje: wie nog niet kan lezen, kan het verhaal al wel volgen.</p>
</blockquote>
<p>Wie nog niet kan lezen? Die moet geen Suske en Wiske ter hand nemen!</p>
<p>Dit zal als muziek in de oren van Frank Furedi&rsquo;s betoog klinken. Het bevestigt jammer genoeg zowat alles wat hij aanhaalt in zijn boek. Er is niets mis met een evolutie van een strip, zeker niet gegeven de betrokkenheid van talloze scenarioschrijvers en tekenaars die komen en gaan. Wat mij wel zorgen baart is de algemene tendens tot verkinderlijking, alsof ergens bepaald is dat wij gewoon niet in staat zijn om energie te steken in iets. Er zijn genoeg bewijzen van anderen<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> die aan dezelfde alarmbel trekken.</p>
<p>De Stedelijke Bibliotheek van mijn thuisdorp is een peutertuin geworden. Als leerling van de lagere school werden wij 30 jaar geleden er duidelijk op gewezen dat de bib een plek van absolute stilte was. Ik nodig iedereen uit om eens een bezoek te brengen aan diezelfde bibliotheek in het heden - en vergeet zeker geen oordopjes. Als studenten tegenwoordig zuchten bij het zien van een boek ligt dat niet aan hun maar aan de manier waarop wij studenten behandelen. Waarom wordt op- en afgeloop met de nodige gillen getolereerd in de bibliotheek? Hebben we schrik dat deze families niet meer terugkomen?</p>
<p>Het &ldquo;omgekeerde elitarisme&rdquo; lijkt vaak te lachen met de zot die nog moeite steekt in het lezen van iets, als iemand anders er toch gewoon een samenvatting van op het internet zwiert. Een manager van mijn vorig werk vroeg altijd om een samenvatting van een boek in één zin. Ik dacht dat hij bedoelde dat je maar zoveel boeken in je leven kàn lezen maar weet nu dat het puur uit gemakzucht was. Velen bestempelen je als &ldquo;dikke nek&rdquo; of &ldquo;snob&rdquo; als je de moeite doet om buiten je eigen kenniservaring te treden met non-fictie, in plaats van respect te hebben voor die pogingen geïnformeerd te zijn op multidisciplinair niveau.</p>
<p>Inflatie van het diploma is trouwens een feit en noemt men &ldquo;<a href="https://en.wikipedia.org/wiki/Credentialism_and_educational_inflation">degree inflation</a>&rdquo;. Gary North heeft hierrond een artikel geschreven dat stelt dat het behalen van een doctoraat tegenwoordig niets meer oplevert omdat er onder andere véél meer aanbod dan vraag naar is. Hij noemt het &ldquo;<a href="https://www.lewrockwell.com/2006/01/gary-north/the-phd-glut/">The Ph.D. glut</a>&rdquo;. Een beetje inzicht in de economie van educatie werkt elke verbazing weg dat hogescholen op eender welke hype springen om zoveel mogelijk studenten te laten delibereren.</p>
<p>De verlengde gemiddelde studeertijd is een goede springplank voor de opkomst van technocratie om aan de stijgende vraag naar experten te kunnen voldoen. Mijn persoonlijke interpretatie van de woorden &ldquo;intellect&rdquo; en &ldquo;intelligentie&rdquo; (&ldquo;slimheid&rdquo;) zijn als volgt: specialisten zijn zeker bijzonder slim, in hun eigen domein. Een intellectueel daarentegen is bereid buiten zijn domein te stappen, en tot devotie tot kennis op alle vlakken waarbij kennis niet het middel maar het doel is.</p>
<blockquote>
<p>Een intellectueel leeft voor ideeën. Een technocraat leeft van ideeën. Intellectueel zijn impliceert maatschappelijk engagement. Het is moeilijk om voor ideeën te leven zonder trachten invloed op de samenleving uit te oefenen.</p>
</blockquote>
<p>Dit wordt bevestigd in de definitie van Wikipedia:</p>
<blockquote>
<p>Een intellectueel is een persoon met een grote algemene ontwikkeling. Daarnaast heeft deze persoon een sterk ontwikkeld oordeelsvermogen en is hij of zij betrokken bij het maatschappelijk en cultureel debat.</p>
</blockquote>
<p>Ik durf niet te beweren dat er binnen de universitaire muren geen experten meer leven, alles behalve: het zijn er net méér. Het idee om buiten je eigen domein te treden en ook publiek &ldquo;levensrelevante&rdquo; vragen durft te stellen wordt ook weer overgelaten aan experts op dat vlak. Papers die postdocs publiceren zijn de laatste 60 jaar supergespecialiseerd geworden. Nora Bateson benadrukt de belangrijkheid van een interrelationele band tussen alles<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. Waarom zou je dan niet de moeite doen om het idee centraler te zetten?</p>
<p>Nieuwsgierigheid en een onderzoekende geest - deze concepten zouden centraal moeten staan in de opleiding van iedereen, van kinderen in het onderwijs tot volwassenen in een vervolmakingscursus. Toen ik klein was las ik nauwelijks tot ik als twaalfjarige Fantasy fictie ontdekte. Tot mijn vierentwintigste raakte ik zo goed als nooit non-fictie aan, tenzij het moest (opdracht van school, verplicht voor werk). Ik heb uiteindelijk zelf de intrinsieke motivatie gevonden om mijn interessegebied open te breken. Je kan het mensen die niet lezen niet bepaald kwalijk nemen: we worden totaal niet geprikkeld om zoiets gek als pagina&rsquo;s achteroverslaan als hobby op te pikken. De minderheid die daar boven staat heeft gewoon zelf ontdekt wat de voordelen zijn.</p>
<blockquote>
<p>Nieuwsgierigheid is de sterkste drijfveer die er bestaat, omdat die de twee grootste afremmende krachten die er bestaan kan overwinnen: het verstand en angst. - Roelant Sagehouwer, <a href="https://www.goodreads.com/book/show/6703129-de-stad-van-de-dromende-boeken?ac=1&amp;from_search=true">De Stad van de Dromende Boeken</a><sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
</blockquote>
<p>Wat is er nodig om die nieuwsgierigheid te stimuleren? Zelfs in een Universitaire omgeving is dat tegenwoordig moeilijker dan je denkt: veel proffen en assistenten bundelen hun eigen cursussen die hoogstens verwijzen naar bronnen. Daar zijn die hapklare stukjes informatie weer. Websites over self improvement hebben het over &ldquo;go wide&rdquo; versus &ldquo;go deep&rdquo;: moet je van zoveel mogelijk onderwerpen iets kennen of veel van één onderwerp?</p>
<p>Het antwoord is natuurlijk beiden, zonder in een van de twee gevallen te overdrijven. Een gemiddelde man wordt in 2016 iets minder dan 80 jaar, waarvan de eerste en laatse jaren niet bepaald productief te noemen zijn. Volgens het Dreyfus model vereist uit te blinken in iets 10 jaar <em>doelbewust</em> oefenen: dat levert optimistisch gerekend vanaf 20 tot 70 dus 5 disciplines op waar je in je leven geweldig goed in kan zijn. Zelfs in minder dan 10.</p>
<p>De stap van ééndimensionaliteit naar veeldimensionaliteit vereist oprechte openheid wat Keri Smith in haar boek &ldquo;How to be an explorer of the world&rdquo; aanhaalt als &ldquo;<strong>everything is interesting</strong>&rdquo;. Maria Popova heeft op haar blog <a href="https://www.brainpickings.org/2012/08/24/how-to-be-an-explorer-of-the-world-keri-smith/">Brain Pickings</a> hier een leuk artikel over samengesteld. Brain Pickings is een van de veelbelovende <em>labors of love</em> die met haar enthousiasme en haar rol als kartograaf van betekenis erg aanstekelijk werkt:</p>
<blockquote>
<p>Brain Pickings is my one-woman labor of love — a subjective lens on what matters in the world and why. Mostly, its a record of my own becoming as a person — intellectually, creatively, spiritually — and an inquiry into how to live and what it means to lead a good life.</p>
</blockquote>
<p>Dàt is wat wij nodig hebben om geïnspireerd een boek open te slaan en te werken aan die grote zogenaamde algemene ontwikkeling.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p><a href="http://www.standaard.be/cnt/dmf02072007_096">De Standaard</a> <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>John Taylor Gatto: <a href="https://en.wikipedia.org/wiki/Dumbing_down">Dumbing us Down</a> <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Nora Bateson - Small Arcs of Larger Circles <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>Walter Moers: Zamonia #4 <a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 24 July 2018.
</p>
]]>
</description>
</item>
<item>
<title>Over tijdsbesef</title>
<link>https://brainbaking.com/post/2018/07/over-tijdsbesef/</link>
<comments>https://brainbaking.com/post/2018/07/over-tijdsbesef/#commento</comments>
<pubDate>Tue, 10 Jul 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/07/over-tijdsbesef/</guid>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/overtijdsbesef.jpg"/>
</p>
<p>In <a href="https://fr.wikipedia.org/wiki/Venteuil">Venteuil</a>, een klein dorpje in de Champagne streek te Frankrijk dat vijfhonderd hele inwoners telt, ligt wijnmaker <a href="http://www.champagne-autreau-lasnot.com/prehome/">Autréau-Lasnot</a>. Er zijn honderden grote en kleine champagneboeren gevestigd in de streek - overal waar je kijkt zie je wijnstokken vergezeld met rozen en bijenkorven. Ik drink geen alcohol, maar dat is geen reden om een uitgebreid bezoek af te slaan: ik hou van alles wat met fermentatie te maken heeft. Het alcoholisch bijproduct is dan voor mij natuurlijk jammer: terwijl iedereen zich bezat aan de verschillende proeverijen kan ik vrolijk wat rondkijken.</p>
<p>Een tweede reden waarom een bezoek aan zo&rsquo;n wijnmakerij de moeite is, is de visie die deze mensen hebben naar het leven toe in het algemeen. Inwoners van een landelijk dorp dat maar vijfhonderd man telt zijn gebonden om op een heel andere manier te leven dan in een drukke stad, dus dat geeft al wat prijs. In het beroep van wijnmaker speelt slechts één concept een centrale rol: <strong>tijd</strong>.</p>
<p>Om kwaliteit te produceren moet je soms tot tien jaar geduld hebben. Die tijd wordt volledig in beslag genomen door kwaliteitscontroles van je druiven op het veld, door de selectie van de juiste periode om te oogsten, en natuurlijk door gisting. Wees bereid om een slechte oogst onherroepelijk weg te kappen: het gaat dan om honderden liters aan verloren winst.</p>
<blockquote>
<p>Om kwaliteit te maken moet je af en toe bereid zijn geld te verliezen.</p>
</blockquote>
<p>&ldquo;Time is money&rdquo; - het klinkt als een zielloze one-liner zonder context. En dat is het ook. In de champagne wereld is tijd <strong>plaats</strong>. Er zijn enorme kelderruimtes nodig om genoeg flessen per jaar te produceren om goed van te leven (laten we zeggen zo&rsquo;n 10.000). De druivenpers is een gedrocht dat in de grote garage staat bij Autréau, waarna het sap naar de kelder gepompt wordt om in inoxen vaten tot 15 maanden omgevormd te worden naar witte wijn. Er zijn tientallen vaten met verschillende soorten druiven van verschillende jaren opgeslagen. Daarna wordt suiker en gist in individuele flessen toegevoegd om de bubbels te creëren. Dat vereist plaats in een tweede kelder. Die flessen moeten gedraaid worden om het residu van de gist te kunnen verwijderen en daarna te herkurken. Dat vereist plaats in een derde kelder. Voeg daar nog wat meer tijd (en dus ruimte) aan toe voor de beste combinaties van smaak te laten versmelten. Het leek alsof heel Venteuil onderkelderd was, voorzien van genoeg flessen voor de komende drie generaties!</p>
<p>Een wijnmaker draait zijn hand niet om voor een jaar meer of minder. Wij in de moderne bedrijfswereld (in context van IT) durven zelfs binnen het jaar meedere keren van werkgever te veranderen. Als je nu zegt dat je 5 jaar voor dezelfde firma hebt gewerkt krijg je gelukwensen en de term <em>&ldquo;ancien&rdquo;</em> opgeplakt. 10 jaar voor kwaliteit. 5 jaar voor een label.</p>
<center>
<img src="/img/wine.jpg" class="bordered" />
Onze gids te [Maison Autréau-Lasnot](http://www.champagne-autreau-lasnot.com/maison/)
</center>
<p>Druivenvelden zijn in de streek erg duur: de concurrentie aast constant op lapjes grond. Voor grote champagnehuizen in Reims is die kostprijs verwaarloosbaard ten opzichte van een familiebedrijf als Autréau. Ze zijn begonnen in 1932 en van generatie op generatie werd de grond binnen de familie gehouden. Dat is dan ook de enige manier om het te doen: het is zo duur dat het voor kleine bedrijven 50 jaar kost om rendabel te zijn.</p>
<p>Kunnen wij ons dat nog inbeelden? Zo&rsquo;n grote onkosten maken over generaties heen? Zo in het onzekere durven stappen? Vijf jaar wachten om te weten of je product écht goed is, of maar middelmatige brol geworden is? Om dan daarna ook de ballen te hebben om alles gewoon weg te kappen en opnieuw te beginnen?</p>
<p>Ik denk het niet. <br/>Het is tegenwoordig al een hel om vijf jaar hetzelfde te moeten doen. Als <em><a href="https://en.wikipedia.org/wiki/Polymath">polymath</a></em> is het onmogelijk om zo&rsquo;n lange periode voor hetzelfde te reserveren. Het <a href="https://en.wikipedia.org/wiki/Dreyfus_model_of_skill_acquisition">Dreyfus model</a> schrijft een decennium voor als de tijd die nodig is om exceptionaliteit te kweken - daarna wordt het tijd voor iets anders. De geïncarneerde Jezus in <a href="https://www.imdb.com/title/tt0756683/">The Man from Earth</a> doet ook elke 10 jaar iets anders - wat moet een mens anders als hij eeuwig leeft?</p>
<p>Champagne maken bijvoorbeeld. Ook al betekenen jaren niets voor onze gids, toch weet hij bij het proeven van champagne zich exact te herinneren welke blend dat was, hoe de oogst dat jaar was en in welke ton het sap aan het gisten was. De ontmoeting leert mij veel gematigder te zijn als het gaat over het spenderen van tijd. Een doctoraat van zes jaar (enkelvoud) doorploeteren hoeft helemaal niets met ploeteren te maken hebben. Die zes jaren (meervoud) zullen zo ook wel voorbij vliegen.</p>
<blockquote>
<p>&ldquo;Waar zie je jezelf over vijf jaar?&rdquo; En andere domme vragen.</p>
</blockquote>
<p>En toch leven deze boeren ook van moment tot moment: wijn maken vereist een constante bijsturing van het hele proces. Geen dag is hetzelfde. Er moet constant geproefd en aangepast worden. De globale opwarming van de aarde zorgt voor een verschuiving van oogsttijd die voor hun heel voelbaar is.</p>
<p>Ik ben ondersteboven van mijn eigen bekrompenheid over tijdsbesef na dit bezoek. Het zal nog jaren duren - en enkele extra bezoeken - eerdat het besef er volledig is. En dat is niet erg, dan kan het idee wat rijpen.</p>
<p>Om af te sluiten met onderzoek: <a href="https://www.researchgate.net/publication/233719859_What_Happened_to_the_Time_The_Relationship_of_Occupational_Therapy_to_Time">What happened to the Time? The Relationship of Occupational Therapy to Time</a>. Hierin staat het volgende als <em>key finding</em>:</p>
<blockquote>
<p>There is a connected relationship between time and occupation.</p>
</blockquote>
<p>Dus toch.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 10 July 2018.
</p>
]]>
</description>
</item>
<item>
<title>Computer Science learning pathways</title>
<link>https://brainbaking.com/post/2018/06/informatics-education-modules/</link>
<comments>https://brainbaking.com/post/2018/06/informatics-education-modules/#commento</comments>
<pubDate>Fri, 29 Jun 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/06/informatics-education-modules/</guid>
<category domain="https://brainbaking.com/tags/teaching">teaching</category>
<category domain="https://brainbaking.com/tags/phd">phd</category>
<description>
<![CDATA[
<p>Also worth reading: <a href="/post/reverse-engineering-a-curriculum/">Reverse engineering a curriculum</a>.</p>
<p>I happened to come across a very interesting study path for &ldquo;game programmers&rdquo; published at <a href="https://github.com/miloyip/game-programmer">https://github.com/miloyip/game-programmer</a>. It&rsquo;s a nice visual representation of books that help you become a better (game) programmer, starting from zero (game programming for kids) and ending at advanced game physics and Artificial Intelligence. I am not keen on becoming a game programmer but the reason this is interesting is that the author has done a great job trying to categorize the different requirements - what it takes to be a programmer in general. Let&rsquo;s take a closer look at that.</p>
<p><figure>
<a href="../miloyip.png" class="lbox">
<img loading="lazy" src="../miloyip.png" title="A cut-out part of the study path, copyright Milo Yip">
</a>
<figcaption>A cut-out part of the study path, copyright Milo Yip</figcaption>
</figure>
</p>
<h2 id="study-paths-for-any-programmer">Study paths for any programmer</h2>
<p>Starting at <strong>Computer Science (CS)</strong>, many of my favorite books on the subject are prominently displayed: <strong>Structure and Interpretation of Computer Programs</strong> (SICP) and <strong>Introduction to Algorithms</strong>. Milo also identifies 3 categories within CS: CS Foundation (SICP), Algorithms, and Mathematics for CS.</p>
<p>After the required<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> CS path, we move on to <strong>Programming Languages</strong>. For the game industry, C(++) and C# are important. Sadly, C++ is a horrible mess and requires different levels of specialized books to completely grasp. I was actually researching C++ books as I&rsquo;m preparing a &ldquo;Software design in C/C++ with Qt&rdquo; course for the coming academic year.</p>
<p>Okay, what&rsquo;s next after a basic CS layer with some intermediate language knowledge? <strong>Software development</strong>, being the practice (TDD, refactoring, clean code, legacy code) and the design (patterns). I&rsquo;m ignoring his UML reference here. Why would you separate programming languages from software development? You need basic understanding of a language to speak. Grammar (syntax) and speaking (development) are useless separately but a lot of books focus too much on only one of these.</p>
<p>After that path, the in-depth game development parts begin. Let&rsquo;s look at it this way: the bachelor years are over, time to specialize in the master years.</p>
<h2 id="study-paths-for-an-academic-master">Study paths for an academic Master</h2>
<p>As a little experiment, I decided to map out my own master education in order to compare the above to some academic reference material. You will see that the abstract &ldquo;study paths&rdquo; are very much alike.</p>
<h3 id="the-bachelor-years">The Bachelor years</h3>
<p>These are the courses I followed in 2003 to reach the grade of Academic Bachelor in Informatics (Computer Science), at <a href="https://www.uhasselt.be/">UHasselt</a>.</p>
<h4 id="first-year"><strong>First year:</strong></h4>
<ul>
<li>Introduction to CS and imperative programming 1</li>
<li>Introduction to CS and imperative programming 2</li>
<li>CS Tools (no idea anymore)</li>
<li>Math for CS 1</li>
<li>Math for CS 2</li>
<li>Logic and modeling</li>
<li>Computer-systems</li>
<li>Computer arithmetic and decision science</li>
<li>Human aspects of CS</li>
<li>Introduction to research and seminars</li>
</ul>
<p>Extremely heavy on the mathematics and logic, more than 50% of the students stop at this point and because of that. Almost everything is theoretically interesting but practically unprocessed.</p>
<h4 id="second-year"><strong>Second year:</strong></h4>
<ul>
<li>Algorithms and data-structures</li>
<li>OO programming</li>
<li>Advanced algorithms and OO programming</li>
<li>Probability statistics</li>
<li>Operating systems</li>
<li>Logic and Functional programming</li>
<li>Introduction to databases</li>
<li>Theoretical informatics</li>
</ul>
<p>Slowly building upon the first year, introducing algorithms, extending on logic, moving from imperative to object-oriented programming.</p>
<h4 id="third-year"><strong>Third year:</strong></h4>
<ul>
<li>Telecommunication and telematics</li>
<li>Software engineering</li>
<li>Computer networks</li>
<li>Compilers</li>
<li>Technology of multimedia systems and software</li>
<li>Technology of tools of User Interfaces</li>
<li>Data mining</li>
<li>Distributed systems</li>
<li>Bio-informatics</li>
<li>AI techniques</li>
</ul>
<p>Finally a lot of freedom for the student as I remember 40% of those courses were optional as I picked data mining and bio-informatics to fill up on points.</p>
<h3 id="the-master-years">The Master year(s)</h3>
<p>These are the courses I followed in 2007 to reach the grade of Master in Informatics (Computer Science), specialization human-computer interaction, at <a href="https://www.uhasselt.be/">UHasselt</a>.</p>
<ul>
<li>3D interaction and virtual environments</li>
<li>Advanced software engineering</li>
<li>Evaluation of User Interfaces</li>
<li>User-centric system development</li>
<li>Actual trends in human-computer interaction</li>
<li>Legal aspects of computer science</li>
</ul>
<p>I ignored the obvious thesis and internship. The master year included a lot (+60%) of optional courses but I can&rsquo;t remember exactly which one is and which one isn&rsquo;t. The master year has <a href="https://www.uhasselt.be/masteropleiding-in-de-informatica">changed a lot since 2007</a>: it&rsquo;s now 2 years and the specializations have expanded: I could choose from 3 (databases, the theoretical oriented one, multimedia, the graphical oriented one, and human-computer interaction, the engineering oriented one). Now there are six at that university!</p>
<p>There has been a lot of shoving-around (from bachelor to master and the other way around) since I graduated. Things like compilers for instance, and legal aspects seems to be an obligatory course now. But looking at <a href="https://www.uhasselt.be/Studiegids?n=3&amp;txtitemid=66&amp;i=135#66">the list</a> from a distance, we can clearly distinguish the following trends (only looking at the Master years now!):</p>
<ol>
<li>(Big) &ldquo;Data&rdquo; became more apparent.</li>
<li>Entrepreneurship is encouraged with some new courses dedicated to that and project management. (both required, rejoice!)</li>
<li>Networking (security, IoT) became more apparent.</li>
<li>AI and machine learning became more apparent. I was interested in this but in 2006 you could only follow a Master after Master in AI in another university.</li>
<li>&ldquo;Agile&rdquo; is a thing and part of policy informatics. (Huh?)</li>
</ol>
<p>According to the &ldquo;Computer Science Education in 2018&rdquo; interview<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, CS education has been relatively static, with core classes still focused on programming (languages, algorithms, data structures), mathematics and systems design (operating systems, computer architecture). The objectives stay the same but the content has obviously been evolving among with us.</p>
<blockquote>
<p>Over the years, I have seen curricular changes to make room for breadth courses unrelated to CS, and to make the programs more accessible to those who are not strong in mathematics. I believe that these changes come at the expense of a deeper understanding of computation.</p>
</blockquote>
<p>Something has to be cut if one intends to make room and that something usually is mathematics - for better or for worse.</p>
<h2 id="essential-computer-science">Essential Computer Science</h2>
<p>It seems to me that most courses map quite well with Milo&rsquo;s requirements on game programming. Would that also be the case with other source material?</p>
<p>Yes.</p>
<p>Look at this well-documented <a href="https://github.com/jwasham/coding-interview-university#the-daily-plan">Google Coding Interview University</a>. I&rsquo;ll let the author speak for it&rsquo;s contents:</p>
<blockquote>
<p>I originally created this as a short to-do list of study topics for becoming a software engineer, but it grew to the large list you see today. After going through this study plan, I got hired as a Software Development Engineer at Amazon. <br/>
This is my multi-month study plan for going from web developer (self-taught, no CS degree) to software engineer for a large company.</p>
</blockquote>
<p>This clearly suggests a (big?) difference between a developer and an <em>engineer</em>.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> The latter sounds a lot cooler for sure. But what exactly would be required to make the jump from one title to the other, according to jwasham? The list is too long so let&rsquo;s make some abstractions:</p>
<ul>
<li>Algorithms (including NP-completeness) and their complexity</li>
<li>Data structures (including dynamic programming)</li>
<li>Object-Oriented Programming</li>
<li>Design patterns</li>
<li>Threading, processes and scheduling</li>
<li>Networking</li>
<li>System design, scalability and data handling</li>
</ul>
<p><figure>
<a href="../csbooks.jpg" class="lbox">
<img loading="lazy" src="../csbooks.jpg" title="Which of these is the most important one? SICP of course!">
</a>
<figcaption>Which of these is the most important one? SICP of course!</figcaption>
</figure>
</p>
<p>It&rsquo;s an unordered list but you can easily map those subjects onto the previous bachelor years. It&rsquo;s a bit more practically oriented though: a lot more in-depth algorithms and less logic, probability and mathematics. Prerequisites are knowing C so imperative programming got you covered. You can read more about his personal story <a href="https://medium.freecodecamp.org/why-i-studied-full-time-for-8-months-for-a-google-interview-cc662ce9bb13">on Medium</a>.</p>
<p>A more hands-on approach is to be preferred to keep students engaged. <a href="https://techdevguide.withgoogle.com/">Google&rsquo;s Tech Dev Guide</a> or classic pair programming brain teasers on <a href="https://www.codewars.com/">Code Wars</a> suggest the same but a close inspection reveals a rather theoretical approach!</p>
<h3 id="in-applied-informatics">In Applied informatics</h3>
<p>So what about the professional Bachelor in Applied Informatics? Is this the road to become a developer but not an engineer, as explained by jwasham? Take a look at the programme from a nearby graduate school, <a href="https://www.pxl.be/Assets/website/student/werving/infobrochures/documenten/basisopleidingen/TIN_programma.pdf">PXL</a>:</p>
<h4 id="first-year-1"><strong>First year:</strong></h4>
<ul>
<li>Application development (Java/.NET/Web Essentials, Web Scripting)</li>
<li>OS Essentials</li>
<li>Security essentials</li>
<li>IT &amp; Data Essentials (&ldquo;problem solving&rdquo;)</li>
<li>Business communication skills</li>
</ul>
<h4 id="second-year-1"><strong>Second year:</strong></h4>
<ul>
<li>Java/.NET/Web Advanced</li>
<li>Server OS Essentials</li>
<li>Software Analysis</li>
<li>Security &amp; Data Advanced</li>
<li>Business communication skills 2</li>
</ul>
<p>The third year is a specialization year with three choices: application development (mobile development, programming &ldquo;expert&rdquo;, software engineering), software management (modeling, management) and networking (cloud &amp; automation, OS expert). I can only guess at the contents of the very vague course descriptions but almost anything from the computer science path seems to be completely vanished.</p>
<p>That leaves me to conclude that the <em>&ldquo;2. Programming Languages&rdquo;</em> study path with a bit of <em>&ldquo;3. software development&rdquo;</em> apply for a professional bachelor<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. Advanced principles might as well be learned on-the-job if you&rsquo;re hired (<em>&ldquo;6. Game development&rdquo;</em>) but it&rsquo;s sad to see that not even a little bit of the essentials are integrated into the plan. I know this to be true because I was a guest lecturer for courses like the essential and advanced application development parts. <br/>
Of course as an academic I&rsquo;m highly biased, but I have worked for 11 years in the software development industry where practicality is most important and most colleagues came from the applied trajectory.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Is basic Computer Science knowledge required to be a great software developer? I think that will depend on what kind of software you&rsquo;ll be working on. If it&rsquo;s domain-driven enterprise software then most of the complexity will come from unclear business rules that drives miscommunication. In that case common sense and critical thinking will be enough<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>. If it&rsquo;s a game engine, a deep learning network or a new distributed protocol then the right mindset alone won&rsquo;t cut it.</p>
<p>That also seems to clarify the difference between developing and engineering. There are a lot of <a href="https://www.google.be/search?q=software+engineer+vs+software+developer">articles on this subject</a> to be found and the explanation is never clear but bound to the industrial context.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>According to the github link, and according to all academic educations. Applied informatics seems to completely (or partially) skip this step, see later on. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>February 2018, DOI: 10.1109/MITP.2018.011021350 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>To quote the source: &ldquo;Large software companies like Google, Amazon, Facebook and Microsoft view software engineering as different from software/web development, and they require computer science knowledge.&rdquo; <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>Remember, other graduate schools offer other trajectories. <a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p>Those skills are also trained while learning CS so it&rsquo;s not to say that it will be useless! <a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 29 June 2018.
</p>
]]>
</description>
</item>
<item>
<title>Reverse engineering a curriculum</title>
<link>https://brainbaking.com/post/2018/06/reverse-engineering-a-curriculum/</link>
<comments>https://brainbaking.com/post/2018/06/reverse-engineering-a-curriculum/#commento</comments>
<pubDate>Fri, 15 Jun 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/06/reverse-engineering-a-curriculum/</guid>
<category domain="https://brainbaking.com/tags/teaching">teaching</category>
<category domain="https://brainbaking.com/tags/phd">phd</category>
<description>
<![CDATA[
<p>Also worth reading: <a href="/post/teaching-by-philosophy/">Teaching by philosophy</a>.</p>
<p>What if, instead of starting with the beginning, you&rsquo;d start with imagining where you&rsquo;d land if you&rsquo;d successfully finish a big project? Thinking like this would temporarily eliminate the <em>how</em> question and focus on the <em>what</em> or <em>why</em> question on a higher level. It&rsquo;s a good exercise that might net me new ideas or forge novel connections between two slumbering thoughts. Let&rsquo;s try to imagine what a <strong>curriculum for computer science</strong> should look like ideally without holding back on the actual practical possibilities - based on rough ideas noted in my <a href="/proposal">proposal</a>.</p>
<h2 id="1-defining-the-core-principles">1. Defining the core Principles</h2>
<p>Let&rsquo;s take a look at concepts that deserve more attention in a curriculum - any curriculum really, not simply limited to engineering. My focus is on computer science within the engineering faculty but didactic terms can be easily generalized.</p>
<h4 id="collaboration-the-camerata">Collaboration: The Camerata</h4>
<p>I was amazed by Jessica Kerr&rsquo;s article <a href="https://the-composition.com/the-origins-of-opera-and-the-future-of-programming-bcdaf8fbe960">on the Origins of Opera and the Future of Programming</a> today. She found out that <em>extreme inventive bursts</em> happen in special groups, or <strong>Camerata&rsquo;s</strong> - in music (The Camerata), art (the Salon in Paris) and even in science. The jump from science to practical software engineering is marginal and easily taken.</p>
<blockquote>
<p>the Camerata resembles the kind of “invisible college” which is the key to creativity in science.
This “invisible college” is an association of people who share ideas. Who build a new reality together, then spread it to advance the wider culture.</p>
</blockquote>
<p>The most important phenomenon to observe is this: <strong>Great teams make great people</strong>, not the other way around. &ldquo;You dont hire star developers, put them together, and poof get a great team. Its the other way around. When developers form a great team, the team makes us into great developers.&rdquo;.</p>
<p>If great teams create great people, do great educational institutions create great graduates? Can we apply industrial mentor models like eXtreme Programming to tighten the Camerata feeling in a practicum? That invisible college is very visible: it&rsquo;s <strong>the</strong> college! Sharing ideas is mostly a one-way transaction (teacher -&gt; student) but graded projects encourage (some) two-way collaboration (student &lt;-&gt; student).</p>
<h4 id="learning-symmathesy">Learning: Symmathesy</h4>
<p>To continue with Jessica&rsquo;s article, she touches upon another very important principle in software engineering: learning. Not just learning, but within a system that grows and changes, and affects your whole self. Nora Bateson calls it a <a href="https://norabateson.wordpress.com/2015/11/03/symmathesy-a-word-in-progress/">symmathesy</a>. Focusing on <em>life long learning</em> is a start, but symmathesy goes much broader than that: it&rsquo;s the context where the learning happens that is paramount to me. Learning within a living system, learning alone as <a href="/tags/self-improvement/">self improvement</a> or together, part productivity part generality. Both models get little to no attention in traditional education.</p>
<p>It&rsquo;s no secret that the software landscape is continually evolving. That means a healthy focus on <strong>transferable concepts</strong> is much more important than practical framework or programming language knowledge. Stack Overflow keeps track of technological popularities and it&rsquo;s always interesting to read what they have to say about (the brutal) <a href="https://stackoverflow.blog/2018/01/11/brutal-lifecycle-javascript-frameworks/">lifecycles of JS frameworks</a>. Brain Moschel&rsquo;s article on <a href="https://www.bitovi.com/blog/longevity-or-lack-thereof-in-javascript-frameworks">longevity (or the lack thereof) in JS Frameworks</a> also provides some thoughtful insights. Don&rsquo;t forget the choice is influenced by company location - and according to Jessica, also by the &ldquo;time (culture) they live in&rdquo;.<br/>To distinguish the important from the unimportant.</p>
<p>A third part of learning is being able to manage the heap of stuff to learn. Not only sifting through useless things to learn, but more importantly being <strong>productive in learning anything</strong>. The word &ldquo;productive&rdquo; has a individual connotation here and touches upon pragmatism and thinking &amp; learning models. Knowing how flow works and how to divide your time in bursts of Deep Learning and Shallow Learning.
<br/>To put it simply: knowing how learning works. Henry Stanley talks about <a href="https://recurse.henrystanley.com/post/better/">becoming a dramatically better programmer</a> - interesting choice of words.</p>
<h4 id="context-creation-mental-models">Context creation: Mental models</h4>
<p>Mental models are models formed in your mind when you talk about specific parts in the software you know. When communicating to other team members, you need a model to find a common ground to talk about. The problem is that each developer&rsquo;s mental model is potentially incomplete and out of date.</p>
<p><figure>
<a href="../model.jpg" class="lbox">
<img loading="lazy" src="../model.jpg" alt="mental models" >
</a>
</figure>
</p>
<blockquote>
<p>We spend time reconciling our mental models enough to communicate with each other; this is a <a href="http://www.michaelnygard.com/blog/2018/01/coherence-penalty-for-humans/">coherence penalty</a>.</p>
</blockquote>
<p>I&rsquo;m convinced that this coherence penalty also applies within conversations between teachers and students. A teacher creates a virtual model in his mind of different courses that are tied together and nicely intertwined. Students also create virtual models in their minds but it&rsquo;s much more fragmented: courses are mostly seen as separate obstacles to overcome without any clear context.</p>
<p>Before teaching the <em>how</em> (syntax), we need to teach the <em>why</em> (<a href="post/teaching-philosophy-first/">philosophy</a>). Our mental models should find a common ground! A lecturer and the students can also be seen as part of the same <strong>Symmathetic</strong> team: why wouldn&rsquo;t systems thinking apply within educational institutions?</p>
<h4 id="creativitypostserendipitous-creativity-serendipity"><a href="/post/serendipitous-creativity/">Creativity</a>: Serendipity</h4>
<p>Malleability of software as a material is very understated. The ever faster application of changes (agility) is well-known, but the ability to transfer learned skills from one problem (project) to another is not. Creativity touches upon and enhances previous sections on collaboration, learning and context. I see creativity as an integrated part of the above but it&rsquo;s worth to accentuate it separately.</p>
<blockquote>
<p>Theres something extra special about development teams: software is the most malleable material weve ever used in engineering, by thousands of times. Theres nothing else like it, and this changes the meaning of “team.”</p>
</blockquote>
<p><figure>
<a href="../idea.jpg" class="lbox">
<img loading="lazy" src="../idea.jpg" alt="the curriculum idea" >
</a>
</figure>
</p>
<p>It doesn&rsquo;t only change the meaning of team, but also the way you should think about limitations of your own expertise: there is (almost) none - except time constraints that are not relevant here. Emphasis on the creative process with the right help of brainstorming and retrospectives, techniques that can also be rightfully applied within a classroom, guided or not.</p>
<h4 id="organic-software-development-changeability">Organic (software) development: Changeability</h4>
<p>Small pieces of easily readable code maximize maintainability. Engineering isn&rsquo;t a long wined singular method of combining stuff anymore: it&rsquo;s about incremental improvements, not unlike nature! While researching reference material for this article, Googling &ldquo;growing software&rdquo; nets me <a href="http://softwaregarden.io/manifesto/">confusing manifesto&rsquo;s</a> that are partially what I&rsquo;m aiming for, and even more confusing <a href="http://shop.oreilly.com/product/9781593271831.do">books</a> that are about managing engineers.</p>
<p>Jessica&rsquo;s symmathesy explains that source code, continuous integration and deployment are also <strong>part of the team</strong> and <em>living (organic) things</em>. If you take care of these &ldquo;things&rdquo;, these &ldquo;things&rdquo; take care of you. Malleability works both ways. Clear software that grows bit by bit, as you do, is the only way to achieve a ubiquitous mental model within - and outside of - your team. That personal evolving relationship between the coder and the code is what makes the team great (and therefore, the people great).</p>
<p>A typical software design course doesn&rsquo;t place enough emphasis on the longevity of software. Projects are graded and students move on to the next very individually tailored (towards technicality, not the student) course. The team constantly changes: there&rsquo;s no overarching project. The opportunity is there though: a typical <a href="https://www.uhasselt.be/Masteropleiding-industriele-wetenschappen#tabs6">Master of Science in Industrial Engineering</a> programme takes five years<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, a lot longer than small to average software projects in the industry!</p>
<h2 id="2-incorporating-those-principles">2. Incorporating those Principles</h2>
<p>There are many ways to change an educational (master) programme:</p>
<ol>
<li>Redefine course content. (ex. remove C++, add Python)</li>
<li>Redefine the way the courses are given. (ex. flipped classrooms, activating students)</li>
<li>Redefine the entire structure. (ex. self-directed, community-driven education like <a href="https://www.recurse.com/">Recurse</a>)</li>
</ol>
<p>Apart from a small portion of every possibility above, my take would be to take the existing courses and integrate the principles we&rsquo;ve extracted in part 1. It wouldn&rsquo;t hurt to shake up the contents now and then (1.) or to enabling students by introducing more active ways of lecturing (2.), but let&rsquo;s for now focus on incorporating those principles without changing too much content.</p>
<p><figure>
<a href="../teach.jpg" class="lbox">
<img loading="lazy" src="../teach.jpg" alt="teaching curriculum-minded" >
</a>
</figure>
</p>
<h4 id="a-create-a-software-engineering-philosophy-teach-all-courses-in-context-of-this-shared-understanding">A. Create a software engineering philosophy. Teach all courses in context of this shared understanding.</h4>
<p>This is the single most important missing piece of the puzzle. The shared mental model of what there is to be taught and in what context (why?). That philosophy should contain the core principles: <strong>make concepts visible</strong> and put everything into perspective! Purposes should be clear for students. After all, we&rsquo;re trying to spark a curiosity, an interest in engineering. Simply grading them course by course won&rsquo;t help there.</p>
<p>Openness in academia is an interesting topic by itself. Prof. Philip Dutré talks about <a href="http://phildutre.blogspot.com/2015/04/docenten-maak-je-onderwijsevaluaties.html">transparency in education evaluation</a> in his blog (in Dutch) and is worth reading. The way you grade is very important to students: they (mostly) learn what will be graded, not necessarily what you think they might find interesting. Grading should be open for everyone and again, in context of the global engineering philosophy.</p>
<h4 id="b-introduce-long-term-projects-across-courses-let-students-branch-and-redesign-continually-and-vigorously">B. Introduce long-term projects across courses. Let students branch and redesign continually and vigorously.</h4>
<p>Start in the first Bachelor year with a project that will be refactored and redesigned up to the Master years. It should be something crystal clear that can bear becoming gradually more complex. Let students fail by sudden difficulty spikes. This is the only way they&rsquo;ll get a taste of the malleability of bigger projects. <br/>
Later boarding students could start with reference projects on different levels.</p>
<p>Cross-course material only benefits the shared philosophy: A and B go hand in hand.</p>
<h4 id="c-prioritize-on-learning-within-a-living-system">C. Prioritize on learning within a living system.</h4>
<p>I would even opt for this one to use possibility (1.) and replace something useless like &ldquo;business management&rdquo; with a completely new course that focuses exclusively on this. The earlier in the programme track it&rsquo;s given, the better. Again, this should seamlessly integrate with other courses while making context explicit.</p>
<p>What the exact contents of this course would be seems like an entire new article to me.</p>
<h2 id="whats-next">What&rsquo;s next?</h2>
<p>This has proven to be a refreshing exercise. We&rsquo;ve only talked about high-level principles without worrying about the implementation (the <em>how</em>). Also, the concrete elaboration of my personal software engineering philosophy is something that will grow incrementally over the coming years, with the needed feedback from both the industry and the education institutions.</p>
<p>Taking a closer look at different universities and their take on the problem will also be worthwhile. I&rsquo;m sure I&rsquo;m not the only researcher with these ideas. There is some research available on how children grasp programming more quickly given a conceptual explanation first.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>Including the bachelor prerequisite years. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 15 June 2018.
</p>
]]>
</description>
</item>
<item>
<title>Over het introduceren van bedrijfsethiek</title>
<link>https://brainbaking.com/post/2018/06/over-bedrijfsethiek/</link>
<comments>https://brainbaking.com/post/2018/06/over-bedrijfsethiek/#commento</comments>
<pubDate>Mon, 11 Jun 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/06/over-bedrijfsethiek/</guid>
<description>
<![CDATA[
<p>Addendum: <a href="https://techbeacon.com/lessons-7-highly-successful-software-engineering-cultures">7 highly successful software engineering cultures</a> is de moeite om in detail na te lezen, waarbij bedrijven zoals GitLab hun <em>&ldquo;Team Handboek&rdquo;</em> open stellen. Het gaat véél verder dan enkel een cultuur: er staat in wanneer aandeelhouders samenkomen, hoe er omgegaan wordt met nieuwe kandidaten en hoe je je verlof dient in te plannen. <strong>Transparantie</strong> zò sterk door de aorta van het bedrijf laten stromen, is zeer bewonderenswaardig.</p>
<p>Een cultuur kweken, hoe doe je dat? Op een Petri schaaltje? Wat als die specifieke cultuur <em>bedrijfscultuur</em> zou zijn? Een interessant probleem waar uiteraard ook filosofie bij komt kijken. Ethiek, in de bedrijfswereld. Een klassieke <strong>gouden regel</strong> introduceren en verwachten dat vanaf dan alle werknemers zie regel handhaven zou naïef zijn: we weten uit ervaring dat dit heel vaak onvoldoende is. Wat ik met &ldquo;uit ervaring&rdquo; bedoel is:</p>
<ol>
<li>Ideeën zoals deze worden vaker aanvaard <em>bottom-up</em> in plaats van <em>top-down</em>.</li>
<li>Het is bewezen dat gedragsveranderingen weken (al dan niet maanden) duren, mét actieve inspanning.</li>
<li>Via één of twéé kanalen iets verspreiden betekent niet dat iedereen het ziet. Alles open trekken dus.</li>
<li>Het is niet omdat iemand je idee ziet, dat het blijft hangen. Herhaling en geregeld aanwakkering tot enthousiasme is noodzakelijk.</li>
</ol>
<h3 id="een-praktische-benadering">Een praktische benadering</h3>
<p>Wat is het <strong>nut</strong> van een bedrijfsethiek? Staan we daar voldoende stil bij, en brengen we dit voldoende aan zonder klassieke ethiek en vakterminologie van de filosofie te betrekken? Met andere woorden: Schrijf iets</p>
<ul>
<li>Beknopt,</li>
<li>Verstaanbaar,</li>
<li>Herhaalbaar en</li>
<li>Inspirerend.</li>
</ul>
<p>Bedrijfsleiders stellen graag een <strong>charter</strong> op die als kapstok kan dienen om waardes van het bedrijf aan op te hangen. Is dit wat we hier willen bereiken?</p>
<blockquote>
<p>Een <a href="https://nl.wikipedia.org/wiki/Charter_(hedendaags)">charter</a>, oorkonde, handvest of manifest is een tekst die is opgesteld om op gebalde wijze een aantal principes over een bepaald onderwerp te codificeren en als een referentietekst te presenteren, waarop wetten en handelingen kunnen worden gestoeld en algemene gedragslijnen kunnen worden afgestemd of aan getoetst.</p>
</blockquote>
<p>Wat mij daar vooral in tegensteekt, zijn de woorden &ldquo;wetten&rdquo; en &ldquo;gedragslijnen&rdquo;: beknopt, verstaanbaar en herhaalbaar zal het zeker zijn, maar inspirerend zeker niet. Typische charters gaan voor zaken als klanttevredenheid, garantie tot vlotte communicatie overgoten met een zakelijk sausje, ondertekend door het bestuur en bij voorkeur opgehangen in de inkomhal.</p>
<p>Wat is het alternatief? Een opstelling van een aantal Bijbelse <strong>geboden</strong>? Beknopt, verstaanbaar en herhaalbaar, misschien zelfs ook inspirerend voor de juiste personen die hun bedrijfsleven als een religieuze ervaring beschouwen.</p>
<p>Een technische <a href="https://www.managementsite.nl/kennisbank/organisatiecultuur">definitie</a> van bedrijfscultuur:</p>
<blockquote>
<p>de gemeenschappelijke verstandhouding van de leden van en de belanghebbenden bij het bedrijf. Schein (1992)</p>
</blockquote>
<p>De extractie van kernwaarden om tot die verstandhouding te komen is niet zo moeilijk (zie het voorbeeld hieronder). In plaats van ethiek te zien als doel, moeten we het ombuigen tot <strong>een middel</strong>. En dat middel moet elke keer gehandhaafd worden als er iets te bereiken valt in het bedrijf. Elke keer: dus alle acties, hoe klein of groot ook, zouden in context van de ethiek geplaatst moeten worden. Enkel zo kan de verschuiving in de gedachtegang tot stand komen.</p>
<h3 id="een-academische-benadering">Een academische benadering</h3>
<p>Bedrijfsethiek als opleidingsonderdeel van <a href="https://onderwijsaanbod.kuleuven.be/syllabi/n/D0R91AN.htm#activetab=plaatsen_in_het_onderwijsaanbod_idp7440448">Economische Wetenschappen</a> geeft de volgende topics aan die belangrijk zouden zijn binnen de bedrijfsethiek:</p>
<ul>
<li>Welke rol spelen waarden en normen in het goede beheer van de onderneming</li>
<li>De aard van ethiek en bedrijfsethiek in het bijzonder</li>
<li>Rechten en plichten van werkgevers en werknemers</li>
<li>Marketingethiek</li>
<li>Corporate Governance</li>
<li>Onderneming en maatschappij</li>
<li>De ecologische uitdaging van de onderneming</li>
</ul>
<p>Enkel de eerste twee punten zijn hier interessant, de rest gaat veel te ver in op de technische implementatie die mij hier niet bezig houden. Welke rol spelen waarden en normen in het goede beheer van de onderneming? Dit betekent dat de waarden en normen <strong>in context</strong> geplaatst moeten worden. Bedrijfscultuur lijkt een onderdeel te zijn van &ldquo;bedrijfsethiek&rdquo; in de bredere zin van het woord, waar ook bedrijfscodes en strategische marketing bij horen. Ik ben enkel geïnteresseerd in de cultuur die iets zou moeten losmaken van de werkgevers en werknemers.</p>
<p>Een adequate bedrijfsethiek vereist een visie op het goede leven, op fundamentele waarden en doelen die betekenis geven aan het handelen - zegt <a href="https://www.ensie.nl/lexicon-van-de-ethiek/bedrijfsethiek">Ensie</a>. <strong>De creatie van een zinvolle omgeving waarin personeelsleden worden getransformeerd van passieve contractuele werknemers tot gemotiveerde leden van een doelgerichte en waardevolle organisatie</strong>.</p>
<p>Passief -&gt; actief door middel van doel en waarde - prachtige woorden, op naar een voorbeeld!</p>
<h2 id="een-uitgebouwd-voorbeeld">Een uitgebouwd voorbeeld</h2>
<p>Onderstaande ethiek hebben we als &ldquo;<strong>De <a href="http://www.prato-services.eu/">Prato</a> Way</strong>&rdquo; uitgewerkt op basis van feedback van collega&rsquo;s. Die feedback werd verzameld op basis van een inbeeldingsvraagstuk:</p>
<blockquote>
<p>Stel dat het nu december volgend jaar is, hoe zou jij willen dat het in het bedrijf er aan toe gaat? Wat heb jij, jouw team of het bedrijf gedaan om de waarden nog meer te laten leven?</p>
</blockquote>
<p>De vraag mag zo breed of zo nauw als je zelf wenst geïnterpreteerd worden: van collega- of klanteninteracties tot betere manieren van implementaties van de software. De antwoorden werden in kleinere groepen gevormd en samengevat. Om hier concrete acties uit te halen werd er gevraagd naar een eerste concrete actie vanuit de groep om die inleving te kunnen verwezenlijken.</p>
<p>Een kanttekening: er zijn reeds eerder brainstorm sessies gevoerd rond de cultuur van het bedrijf, waar de kernwoorden &ldquo;<em>Growing Smart Together</em>&rdquo; (GST) zijn uitgekomen. Onder het GST model werden een aantal concrete zaken georganiseerd op korte en lange termijn om dit te laten leven. Die pogingen bleken echter niet voldoende gecategoriseerd onder de gedeelde noemer: GST. In plaats van de organisatie van een aantal mensen te laten afhangen, zou die cultuur als algemeen draagvlak moeten fungeren. Onderstaande slagzinnen dienen als <strong>gemeenschappelijke fundamenten</strong> om de GST filosofie te laten leven.</p>
<h3 id="1-tevredenheid-is-de-oogst-van-hart-werk">1. Tevredenheid is de oogst van Hart-werk.</h3>
<center>![ethiek img](/img/pratoway/1.png)</center>
<p><em><strong>Hart</strong> werken is zeker en vast <strong>hard</strong> werk. Samenwerken en communiceren met respect voor je collega en klant. Tevredenheid ligt ons nauw aan het <strong>hart</strong> omdat we het <strong>hart</strong> op de juiste plaats hebben.<br/>
Een tevreden klant is een gelukkige klant. Een tevreden collega is een gelukkige collega. <br/>
Een goede oogst vol Hart-werk dus!</em></p>
<h3 id="2-de-beste-intenties-voorkomen-klanten-interventies">2. De beste intenties voorkomen klanten interventies.</h3>
<center>![ethiek img](/img/pratoway/2.png)</center>
<p><em>Wij kijken positief naar het leven en nemen aan dat iedereen met de beste intenties handelt, zowel klant als collega. Loopt er al eens iets mis, dan stropen we gewoon de mouwen op en gaan we ertegenaan. <br/>
Anderen helpen is ook jezelf helpen!</em></p>
<h3 id="3-echte-compainons-delen-meer-dan-alleen-maar-brood">3. Echte comPAINons delen meer dan alleen maar brood.</h3>
<center>![ethiek img](/img/pratoway/3.png)</center>
<p><em>Er wordt gezegd dat planten beter groeien als je ze dagelijks complimentjes toefluistert. Dat kunnen we niet hard maken, maar dat collegas daarvan opfleuren is een feit! Het “Je bent me dr eendje” initiatief heeft dit zeker bewezen. Deel daarom meer dan enkel kennis en breek ook eens brood bij een lach en een traan.<br/>
Zet elkaars talenten in de verf. Vier ook kleine successen!</em></p>
<h3 id="4-een-gedeelde-voedingsbodem-kweekt-inventieve-ideeën">4. Een gedeelde voedingsbodem kweekt inventieve ideeën.</h3>
<center>![ethiek img](/img/pratoway/4.png)</center>
<p><em>Het magische woord <strong>serendipity</strong>, de “toevallige” samenkomst van ideeën onder de juiste condities, is voor ons al lang geen geheim meer. Die condities zijn heel simpel: een gedeelde voedingsbodem! Wees betrokken in alle initiatieven en deel uw mening om verder te bouwen aan een beter Prato.<br/>
Kruisbestuiving van ideeën zorgt voor vruchtbare concepten.</em></p>
<h3 id="5-te-midden-van-de-moeilijkheid-ligt-jouw-mogelijkheid">5. Te midden van de moeilijkheid ligt jouw mogelijkheid.</h3>
<center>![ethiek img](/img/pratoway/5.png)</center>
<p><em>Jouw mogelijkheid staat voor dingen zelf in beweging kunnen zetten. Wij zijn allemaal een uniek radertje in het Prato tandwiel en kunnen allemaal even betrokken zijn - als we dat willen. De pure kracht van verantwoordelijkheid zit in ieder van ons. <br/>
Obstakels zijn er om gezamenlijk uit de weg te ruimen!</em></p>
<h3 id="6-goede-dingen-gebeuren-als-je-openstaat-voor-verandering">6. Goede dingen gebeuren als je openstaat voor verandering.</h3>
<center>![ethiek img](/img/pratoway/6.png)</center>
<p><em>Het buigzame twijgje blijft groeien na een storm, terwijl de grote onbuigzame eik splijt. Durf zelf op zoek te gaan naar verandering en durf mee te gaan met voorstellen van collegas die niet meteen aansluiten met je eigen visie. <br/>
Goede dingen gebeuren als je onderweg af en toe vragen stelt over het pad dat je hebt afgelegd en nog gaat afleggen. Durf dingen in vraag te stellen bij jezelf, je team en Prato.</em></p>
<h2 id="toepassingen-in-context-van-ethiek-plaatsen">Toepassingen in context van ethiek plaatsen</h2>
<p>Zoals al eerder gezegd, een uitgebouwde &ldquo;verstandhouding&rdquo; moet als middel voor alle doelen dienen en een antwoord kunnen geven op de &ldquo;waarom&rdquo; vraag bij elke actie. Om ethiek levend te houden kan een bedrijf dus alle communicatie verrichten met het oog op deze waarden.</p>
<p>Enkele voorbeelden:</p>
<ul>
<li>Interne vragenlijsten over tevredenheid van werknemers. Indien vragen gesteld worden, plaatsen in één van de bovenstaande punten. (OfficeVibe, MonkeySurvey)</li>
<li>Organisatie van Retrospectives rond één van de thema&rsquo;s.</li>
<li>Externe communicatie: de cultuur zelf ook in de verf zetten!</li>
<li>Thema maanden organiseren rond stukjes van het thema om daar op in te spelen. Bijvoorbeeld bij &ldquo;tevredenheid&rdquo; foto&rsquo;s verzamelen van tevreden collega&rsquo;s en klanten, bij &ldquo;meer dan brood delen&rdquo; organisaties van sociale activiteiten, &hellip;</li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 11 June 2018.
</p>
]]>
</description>
</item>
<item>
<title>A Ph.D. Thesis Proposal</title>
<link>https://brainbaking.com/post/2018/06/phd-proposal/</link>
<comments>https://brainbaking.com/post/2018/06/phd-proposal/#commento</comments>
<pubDate>Mon, 04 Jun 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/06/phd-proposal/</guid>
<category domain="https://brainbaking.com/tags/phd">phd</category>
<description>
<![CDATA[
<p>The following Ph.D. proposal has been tailored to act as a clarification for colleagues and professors, hence it&rsquo;s written in Dutch. The English abstract will follow later. The thesis subject:</p>
<blockquote>
<p><strong>The disparity between industrial requirements and classic education of modern software engineering.</strong></p>
</blockquote>
<h2 id="de-probleemstelling">De probleemstelling</h2>
<blockquote>
<p>Wat missen ontwikkelteams en developers<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> tegenwoordig?</p>
</blockquote>
<p>Vanuit die vraag ben ik vertrokken.</p>
<p>Als software ingenieur met meer dan een <a href="/about">decennium ervaring</a> heb ik een grote interesse ontwikkeld in de manier waarop software tot stand komt. Ik heb een stevige technische achtergrond met een voorliefde om die kennis te delen die zich uit in een actieve rol als coach en lesgever.</p>
<p>Het traditioneel coachen en lesgeven brengt echter niet altijd even veel op. Dat kan natuurlijk aan mij liggen (de manier waarop), aan het de stof die ik wil overbrengen (het onderwerp) of aan de interesse van het doelpubliek (de ontvanger). Bij veel teams waar ik de afgelopen jaren tijd in heb doorgebracht is het moeilijk om iedereen op dezelfde golflengte te krijgen.</p>
<p><figure>
<a href="../sweng_prob.png" class="lbox">
<img loading="lazy" src="../sweng_prob.png" alt="sw engineering probleem" >
</a>
</figure>
</p>
<p>Ik begon mij af te vragen hoe ik het probleem zou kunnen identificeren en hier iets concreet rond doen. De vraag werd een <strong>meta-vraag</strong>: in plaats van te vragen wat te leren begon ik te vragen hoe het leren te leren. Dus: <em>wat zien we over het hoofd wanneer we toegeven dat software schrijven niet altijd gesmeerd loopt?</em></p>
<p>Aan industriële eisen van moderne software engineers wordt vaak niet voldaan. De alsmaar groeiende nood aan informatici verergert dit probleem slechts: het voorzetzel &ldquo;goede&rdquo; is compleet verdwenen in die nood. De schuld geven aan een gebrek van een goede opleiding lijkt erg kortzichtig.
Vandaar dat ik bovenstaande vraag wil ombuigen naar een doctoraatsvoorstel:</p>
<blockquote>
<p><strong>De ongelijkhheid tussen industriële vereisten en klassieke opleidingen van moderne software ingenieurs.</strong></p>
</blockquote>
<p>Op die manier formuleer ik de probleemstelling met persoonlijke inbreng in context van coaching in de industrie en in context van doceren in de onderwijsinstelling.</p>
<p>De woorden in de (Engelstalige) titel verklarend:</p>
<ol start="0">
<li><strong>Disparity</strong>: De vraag waaruit ik ben vertrokken, afgebakend en doelgericht op klassieke opleidingen.</li>
<li><strong>Industrial requirements</strong>: Ik wil het hebben over software die in de industrie gemaakt wordt - de industrie waar ik een integraal deel van uitmaak. Het moet concreet toepasbaar zijn. Ik wil nauw samenwerken met bedrijven, niet enkel met een onderwijsinstelling.</li>
<li><strong>Software engineer</strong>: met een insteek vanuit de praktische <em>engineering</em> hoek, niet de theoretische computerwetenschappen hoek. In de industrie noemen we onszelf alemaal graag &lsquo;ingenieur&rsquo;, maar dat gaat verder dan enkel het technische programmeerwerk.</li>
<li><strong>Modern</strong>: Het doctoraat moet actueel zijn, in de tegenwoordige tijd. Zelfs al zou het onderzoek jaren duren, daarna moet het nog van toepassing zijn. In de ontwikkelwereld verandert alles bliksemsnel. Ik wil mij focussen op concepten, niet op frameworks die vervangen worden, en zo een blijvende impact maken.</li>
</ol>
<h2 id="de-doelstelling">De doelstelling</h2>
<p><figure>
<a href="../phd_summary.jpg" class="lbox">
<img loading="lazy" src="../phd_summary.jpg" alt="phd summary" title="PhD samenvatting. Klik om te vergroten.">
</a>
<figcaption>PhD samenvatting. Klik om te vergroten.</figcaption>
</figure>
</p>
<p>Voordat we die ongelijkheid uit de weg kunnen ruimen moeten we een andere vraag stellen: wat valt er allemaal onder die zogenaamde industriële vereisten? Die eisen kunnen we langs diverse opleidingen plaatsen om een kritische blik te werpen op de inhoud ervan. Als we terugdenken aan de vraag &ldquo;wat missen we&rdquo;, onderscheiden we<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> een aantal belangrijke <strong>deelvragen</strong>:</p>
<h4 id="1-productiviteit">1. Productiviteit</h4>
<p>Productiviteit manifesteert zich op drie manieren binnen software ontwikkeling:</p>
<ol>
<li>In het beheren van ondersteunende <em>tools</em>. <br/>Bijvoorbeeld shortcuts vanbuiten kennen van uw geliefde IDE of blind kunnen typen.</li>
<li>In efficiëntere codeertechnieken. <br/>Bijvoorbeeld door het sneller herkennen en toepassen van patronen (zie ook Pragmatiek).</li>
<li>In het <em>metafysische</em>. <br/>Bijvoorbeeld strategiëen voor het overwinnen van afleiding of het beter richten van je sterktes.</li>
</ol>
<p>Zonder een <strong>bewustwordingsproces</strong> op gang te brengen gaat dit niet beteren. Een simpele productiviteitswinst van 1%<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> kan al voor een flinke besparing op jaarbasis zorgen. Ondersteunende tools winnen en verliezen snel aan populariteit waarbij kennis van specifiek ingebouwde hulpmiddelen snel irrelevant worden. Die kennis kan echter omgezet worden naar een bewustwording van hun bestaan zodat men ook in de toekomstige tools efficiënt kan werken.<br/>
Een goede ingenieur is een luie ingenieur die zich constant afvraagt &ldquo;kan ik hier meer uit halen met minder moeite?&rdquo;.</p>
<p>Een ander aspect van metafysische productiviteit is het zoeken naarde juiste stemming. Daarmee bedoel ik Flow van <a href="https://www.ted.com/talks/mihaly_csikszentmihalyi_on_flow">Mihaly Csikszentmihalyi</a>, Deep Work van <a href="https://www.ted.com/talks/cal_newport_why_you_should_quit_social_media">Cal Newport</a> en een Growth Mindset van <a href="https://www.ted.com/talks/carol_dweck_the_power_of_believing_that_you_can_improve">Carol Dweck</a>.</p>
<p>De nodige aandacht dient gegeven te worden aan kwantificeerbaarheid van deze productiviteit binnen software engineering om een correct formeel onderzoek te kunnen uitvoeren.</p>
<h4 id="2-samenwerking--begeleiding-software-maak-je-niet-alleen">2. Samenwerking &amp; Begeleiding: Software maak je niet alleen</h4>
<p>Desondanks bekende boeken als <em>&ldquo;PeopleWare: Productive Projects and Teams&rdquo;</em> van <a href="https://en.wikipedia.org/wiki/Peopleware:_Productive_Projects_and_Teams">Tom DeMarco</a> is dit iets waar bedrijven altijd het meeste budget in snoeien. 80%<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> van de ontwikkelproblemen zijn mens-gerelateerd.</p>
<p>Scholen laten studenten vaak samenwerken aan projecten maar vergeten uit te leggen wat de woorden &ldquo;<em>samen</em>&rdquo; en &ldquo;<em>werken</em>&rdquo; feitelijk betekenen als ze in één woord gebruikt worden. Bijgevolg kunnen wij niet verwachten dat dit in teams vanzelf goed komt.</p>
<p>In de industrie wordt binnen <em>eXtreme Programming</em> vaak het <em>pair programming</em> principe toegepast: met twee personen aan één computer ontwikkelen. De ervaring leert mij dat dit een zeer efficiënte techniek kan zijn om op korte termijn iedereen op dezelfde golflengte te krijgen. Het kan echter ook een recept voor een ramp zijn als geen van beiden toegevingen kan doen.</p>
<p>Een gebrek aan een goed <em>mentor model</em> kan vreselijke gevolgen hebben voor de continuïteit van een software project. Begeleiding is van cruciaal belang om op collega&rsquo;s één lijn te brengen met een minimale inspanning.</p>
<p>Wij hebben vaak de behoefte om volledige controle te hebben en dat is makkelijk terug te vinden in code. Elkaar volledig vertrouwen kan alleen maar als iedereen weet wat de vereisten van een moderne ingenieur zijn en zich daar achter schaart.
Wantrouwen moet omgebogen worden naar slim vertrouwen.<br/>
Ik wil mij hier richten op een mens-gerichte oplossing die los staat van project ontwikkelingsmethodologieën die komen en gaan als scrum en kanban.</p>
<h4 id="3-pragmatiek-het-belangrijke-van-het-onbelangrijke-onderscheiden">3. Pragmatiek: Het belangrijke van het onbelangrijke onderscheiden</h4>
<p><em>Verstandsverslaving</em> is jammer genoeg een erg aanstekelijke ziekte onder software ingenieurs, en volgens <a href="https://www.happysmarts.com/">Raj Raghunathan</a> ook een doodzonde van geluk. Het verschil tussen een goede en een heel goede software ingenieur is weten wanneer te stoppen met <em>engineering</em>.</p>
<p>We wensen immers technologie te gebruiken om iets (het domein) uit te drukken, en niet om iets te gebruiken om technologie te tonen. <strong>Soberheid</strong> is een deugd die dringend in de software industrie gestandaardiseerd moet worden.</p>
<p>Dit probleem beperkt zich echter niet binnen de software ingenieurs maar komt ook terug bij ingenieurs in het algemeen. Ik merk uit mijn ervaring als lesgever dat studenten opdrachten vaak te goed willen doen, en uit mijn ervaring als technische coach dat collega ontwikkelaars dit nog steeds niet hebben afgeleerd.</p>
<p><figure>
<a href="../frameworks.jpg" class="lbox">
<img loading="lazy" src="../frameworks.jpg" alt="frameworks problemen" >
</a>
</figure>
</p>
<p>De focus leggen op het <em>concept</em> in plaats van het <em>framework</em> is echter makkelijk gezegd: hoe doe je dat? Waarom zijn hogescholen zo gebrand op praktische voordelen van frameworks die na 2 jaar toch niet meer actueel zijn? Waarom zijn universiteiten zo gebrand op theoretische concepten zonder een praktisch voorbeeld aan te halen?</p>
<p>Ik wil op zoek gaan naar een goede cocktail van het conceptuele met het praktische. Het is momenteel een moeilijk te definiëren en moeilijk te beheersen kunst om op het juiste moment die grens te trekken. Het beoordelen van Frameworks zoals <a href="https://angularjs.org/">Angular</a> en <a href="https://reactjs.org/">React</a> zou kunnen betekenen dat hier gewoon concepten uit overgenomen kunnen worden zonder zich te moeten toeleggen op een volledig nieuw systeem.</p>
<h4 id="4-software-ontwikkeling-als-een-organisch-proces">4. Software ontwikkeling als een organisch proces</h4>
<p>De metafoor die zegt dat software ontwikkelen een beetje zoals tuinieren is sluit mooi aan met mijn idee. Maar wanneer beslis je om takken weg te knippen en bomen bij te planten? Op welke manier druk je je dan uit? Het &ldquo;groeien&rdquo; van software wordt altijd ondersteund door <em>test-driven development</em>, zoals het groeien van bomen wordt ondersteund door organische meststoffen. Op die manier reduceer je drastisch het mythische &ldquo;aantal WTFs per minuut&rdquo;.</p>
<p><figure>
<a href="../wtfm.jpg" class="lbox">
<img loading="lazy" src="../wtfm.jpg" alt="aantal wtfs per minuut" >
</a>
</figure>
</p>
<p>De beschrijving van vereisten met de <strong>natuurlijke taal</strong> in code zorgt voor een belangrijke bijdrage tot onderhoudbaarheid. Concepten die van belang zijn voor je product (zoals een vacature, sollicitatie of contract) moeten dezelfde dingen betekenen in de code zelf. Ik wil hier <em>Domain-Driven Design</em> aanraken, maar er niet helemaal in mee gaan.</p>
<p>Ook <em>Veranderbaarheid</em> of <em>agility</em> is een alsmaar belangrijker onderdeel van software ontwerp dat ook in deze categorie past. Technologieën volgen elkaar in een moordend tempo op: moet je dat altijd volgen?</p>
<p>De criminologische <a href="https://nl.wikipedia.org/wiki/Broken_windows_theory">broken windows theorie</a> die stelt dat omgevingen die vuil zijn, meer vuil aantrekken, is jammer genoeg ook van toepassing bij software ontwikkeling. Net als bij het tuinieren zakt de moed je in de schoenen bij het tegenkomen van een groot overwoekerd stuk <em>legacy code</em>.</p>
<p>Buiten <a href="https://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627">Growing Object-Oriented Software, Guided by Tests</a> van Steve Freeman ontbreekt eender welke vorm van een formeel model om software ontwikkeling te benaderen als een organisch proces waar ik met dit voorstel een verschil in kan maken.</p>
<h4 id="5-creativiteit">5. Creativiteit</h4>
<p>Iets creëren vereist altijd een zekere vorm van creativiteit. Patronen leren herkennen maakt het mogelijk om deze toe te passen op andere projecten. Die patronen kunnen een aantal dingen zijn:</p>
<ol>
<li>Letterlijke <em>design patterns</em> zoals de &ldquo;<a href="https://en.wikipedia.org/wiki/Design_Patterns">Gang of Four</a>&rdquo; ze aanbiedt.</li>
<li>Concepten lenen van verschillende programmeertalen en bibliotheken als een echte <em>polyglot</em>.</li>
</ol>
<p>Over creativiteit hoor je bitter weinig als software ontwikkelaar en dat is een gemiste kans. Het is zelfs een <strong>kerndeel</strong> van het beroep, als dagelijkse scheppers van virtuele werelden. Hoe bevorderen grote bedrijven als Google de creativiteit van hun techneuten?</p>
<p>Computerwetenschappen is een van de weinige concrete wetenschappen die zich niet moet houden aan de fysieke wetten van onze wereld zoals zwaartekracht. De enige beperking binnen dit domein is je eigen creativiteit! Ik ben ervan overtuigd dat hier meer aandacht aan besteed moet worden.</p>
<h2 id="de-manier-waarop">De manier waarop</h2>
<p>Moderne software moet bestand zijn tegen frequente wijzigingen in de vereisten door onder andere grillen van de klant. Daarom kiest men tegenwoordig voor een <em>iteratieve methode</em> die in staat stelt om regelmatig wijzigingen door te voeren zonder jaren nodig te hebben om één groot pakket te realiseren.</p>
<p>Dit concept wil ik graag doortrekken in dit doctoraatsvoorstel. In plaats van een monografie te schrijven die pas na een (heel) aantal jaren af is, zou ik het <em>iteratief</em> willen aanpakken door een <strong>collectie van opeenvolgende artikels</strong> te schrijven in context van het algehele onderwerp. Deze papers worden op het einde van de rit één mooi geheel door middel van een voorwoord en conclusie.</p>
<p>Dit sluit beter aan met de <em>agile proces</em> dat ook bij Prato gebruikt wordt om sneller feedback te kunnen verzamelen en ook sneller een meerwaarde te kunnen bieden.</p>
<p><figure>
<a href="../agile.png" class="lbox">
<img loading="lazy" src="../agile.png" alt="het agile proces" >
</a>
</figure>
</p>
<h2 id="de-toepasbaarheid">De toepasbaarheid</h2>
<p>Een industriëel getint onderzoek zonder directe toepasbaarheid voelt maar slap aan. Voor mij persoonlijk, als deels software ontwikkelaar bij <a href="http://www.prato.be">Prato</a> en deels lesgever aan <a href="http://www.kuleuven.be">KULeuven</a>, is het voornaam dat de toepasbaarheid van het voorstel zowel in de industrie als in de onderwijsinstelling mogelijk is. Ik zou daarom ook nauw willen samenwerken met beide partijen. Die <em>disparity</em> of ongelijkheid in de titel van het voorstel vormt een brug tussen deze beide werelden.</p>
<h3 id="a-industriële-toepasbaarheid">A. Industriële toepasbaarheid</h3>
<p>De bewustwording van industriële eisen stelt ons in staat om aan zelfontplooiing te doen als individuele ontwikkelaar en als ontwikkelteam. Concrete resultaten van het onderzoek kan de manier waarop opleidingen tot stand komen aanscherpen, ook binnen een bedrijf.</p>
<p>Onderzoek rond productiviteit kan bijvoorbeeld direct geïntroduceerd worden als een kostenreductie van 1+%<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. Die introductie gaat uiteraard meer werk zijn dan enkel het resultaat van dit werk voordragen: dat is nog maar het begin.</p>
<p>Als we de vraag waaruit ik ben vertrokken kunnen beantwoorden, kunnen we ook onze (sprekend vanuit mijn standpunt als technische coach) ontwikkelaars laten zien waar men naar toe kan groeien. Dit kan zelfs gebruikt worden als officieel groeimodel voor ingenieurs, in plaats van archaïsche classificaties van functiedefinities als &ldquo;junior&rdquo;, &ldquo;senior&rdquo; en &ldquo;architect&rdquo;.</p>
<p>Ook de aanwerving en inzetbaarheid<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> van nieuwe ontwikkelaars kan hierop afstemd worden. Het subjectief buikgevoel of algehele gebrek aan uniforme testen wordt vervangen door een heldere blik op de vereisten van een moderne ingenieur.</p>
<h3 id="b-didactische-toepasbaarheid">B. Didactische toepasbaarheid</h3>
<h4 id="a-als-curriculum-wijziging">A. Als curriculum wijziging</h4>
<p>Kijken we naar een professioneel bachelorprogramma als toegepaste informatica, dan onderscheiden we vakken in ongeveer deze groepen:</p>
<ul>
<li>Syntactiek (Java, .NET, PHP, &hellip; &ldquo;essentials&rdquo;)</li>
<li>Techniek (Netwerken, OS, &hellip;)</li>
<li>Analytiek (Problem solving, business, &hellip;)</li>
</ul>
<p>Merk op hoe weinig van bovenstaande subonderwerpen hieronder vallen. Af en toe verschijnt er een vak &ldquo;communicatie&rdquo; onder de laatste groep. Los van de gebrekkige inhoud is dat zeker een stap in de goede richting.</p>
<p>Kijken we naar een academisch masterprogramma als computerwetenschappen of (industriële) ingenieurswetenschappen, dan onderscheiden we de volgende extra groepen:</p>
<ul>
<li>Technische Concepten (Algoritmes, datastructuren, &hellip;)</li>
<li>Functionele Concepten (Wiskunde, natuurkunde)</li>
</ul>
<p>Deze grondlaag <strong>kan</strong> voor een uitmuntend inzicht zorgen van een toekomstige software ingenieur. Het probleem is dat niemand een student uitlegt waarom concepten en leren leren belangrijk zijn. Levensbeschouwing om toekomstige samenwerking en inzicht in elkaars denken te bevorderen wordt totaal achterwege gelaten in exacte wetenschapsrichtingen als deze. <br/>
Een curriculum wijziging die meer toegespitst is naar de noden van de industrie kan dus zeker geen kwaad, ook al komen niet alle afgestudeerde studenten uiteindelijk in die sector waar ik mij nu tot richt terecht.</p>
<p>Een concreet voorbeeld: het vak &ldquo;Software ontwerp in Java&rdquo; leert studenten het <em>ontwerpen software</em> aan met <em>behulp van</em> Java als taal. In werkelijkheid moeten studenten teveel syntactiek leren en verbasteren ze het vak naar &ldquo;Java&rdquo;. Het belangrijkste valt dus tevergeefs weg.</p>
<h4 id="b-als-deel-van-lesec">B. Als deel van LESEC</h4>
<p>Dit voorstel past perfect binnen de onderzoeksgroep <a href="https://set.kuleuven.be/LESEC">LESEC</a>:</p>
<blockquote>
<p>A community of researchers and practicioners contributing to the advancement of education in the Science, Engineering &amp; Technology group.
This includes R&amp;D and consultancy activities, and the establishment of a network for cooperation and the exchange of experiences.</p>
</blockquote>
<h2 id="huidig-onderzoek">Huidig onderzoek</h2>
<p>Er is reeds huidig academisch onderzoek ondernomen in de aparte subonderwerpen. Het is iets moeilijker om bestaande wetenschappelijke artikels terug te vinden rond het overkoepelende onderwerp. Typisch wordt een vraag als &ldquo;<em>wat missen we nog in de dev teams?</em>&rdquo; empirisch beantwoord door vallen en opstaan in de bedrijven zelf.</p>
<p>Dit is de status van het huidig onderzoek in context van mijn voorstel:</p>
<h4 id="a-rond-het-curriculum-van-software-engineers">A. Rond het curriculum van software engineers</h4>
<ul>
<li><a href="http://www.inf.usi.ch/jazayeri/">Mehdi Jazayeri&rsquo;s</a> werk als <a href="http://www.inf.usi.ch/jazayeri/docs/papers/educationofSEASE.pdf">The Education of a Software Engineer</a></li>
<li><a href="http://users.ece.utexas.edu/~perry/education/SE-Intro/fakeit.pdf">A rational design process: how and why to fake it</a></li>
</ul>
<h4 id="1-rond-productiviteit">1. Rond Productiviteit</h4>
<ul>
<li><a href="http://www.andre-meyer.ch/category/research/">André Meyer&rsquo;s Ph.D. research rond productiviteit</a></li>
<li><a href="https://research.google.com/pubs/pub43835.html">Google Research &ldquo;how developers search for code&rdquo;</a></li>
<li><a href="https://arxiv.org/abs/1801.06475">A Systematic Review of Productivity Factors in Software Development</a></li>
<li><a href="https://pdfs.semanticscholar.org/03e0/a475e5c2e39fd1f834acc4fbf5fee49467e3.pdf">L. Hatton: The Chimera of Software Quality</a></li>
</ul>
<h4 id="2-rond-samenwerking--begeleiding">2. Rond Samenwerking &amp; Begeleiding</h4>
<ul>
<li><a href="https://ieeexplore.ieee.org/document/7958489/">Complex group decision making in agile projets</a></li>
<li><a href="https://www.sciencedirect.com/science/article/pii/S0950584918300223">Non-technical individual skills are weakly connected to the maturity of agile practices
</a></li>
<li><a href="https://www.gu.se/english/research/publication/?publicationId=262631">Group developmental psychology and software development performance</a></li>
<li><a href="https://openresearchsoftware.metajnl.com/articles/10.5334/jors.bc/">The Big Effects of Short-term Efforts: Mentorship and Code Integration in Open Source Scientific Software</a></li>
<li><a href="https://link.springer.com/chapter/10.1007/978-94-017-9115-1_26">A Mentorship Framework for Work Integrated Learning in Software Development</a></li>
</ul>
<h4 id="3-rond-pragmatiek">3. Rond Pragmatiek</h4>
<ul>
<li><a href="https://www.gu.se/english/research/publication/?publicationId=262633">On the relation between unit testing and code quality</a></li>
<li><a href="https://www.researchgate.net/publication/291754462_Pragmatic_software_engineering_for_computational_science">Pragmatic software engineering for computational science</a></li>
<li><a href="https://www.jnd.org/dn.mss/the_research-practice_gap_1.html">The Research-practice gap</a></li>
<li><a href="https://www.infosys.com/consulting/architecture-services/white-papers/Documents/engineering-enterprise-architecture.pdf">Over-engineering enterprise architecture and business competitiveness</a></li>
<li><a href="https://www.esrale.org/">Learning research</a>: en de toepasbaarheid op sw.eng. Hoe leren we? Welke manieren zijn goed om teams dingen bij te leren? Brown bags VS random meetings VS coding schools VS &hellip; <em>Microlearning</em> onder andere.</li>
<li><a href="https://link.springer.com/article/10.1007/s10009-002-0083-4">What makes good research in Software Engineering</a></li>
</ul>
<h4 id="4-rond-software-ontwikkeling-als-organisch-proces">4. Rond Software ontwikkeling als organisch proces</h4>
<ul>
<li><a href="https://www.sciencedirect.com/science/article/pii/S0167642314005449#fg0010">Theorizing about software development practices</a></li>
<li><a href="https://www.gu.se/english/about_the_university/staff/?languageId=100001&amp;userId=xgrelu&amp;userName=Lucas%20Gren">Lucas Gren&rsquo;s Ph.D. research rond agile software engineering</a></li>
</ul>
<h4 id="5-rond-creativiteit">5. Rond Creativiteit</h4>
<ul>
<li><a href="https://www.emeraldinsight.com/doi/abs/10.1108/00907320010359623">Creativity research: implications for teaching, learning and thinking</a></li>
<li><a href="https://link.springer.com/article/10.3758/BF03196731">The cognitive neuroscience of creativity</a></li>
<li><a href="https://journals.aom.org/doi/abs/10.5465/256995">Assessing the Work Environment for Creativity</a></li>
<li><a href="https://books.google.co.uk/books/about/How_Would_You_Move_Mount_Fuji.html?id=9yzUtgAACAAJ&amp;redir_esc=y">How Would You Move Mount Fuji?: How the World&rsquo;s Smartest Companies Select the Most Creative Thinkers</a></li>
</ul>
<p> </p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>De woorden &lsquo;programmeur&rsquo;, &lsquo;ontwikkelaar&rsquo;, en &lsquo;software ingenieur&rsquo; worden hier door elkaar gebruikt, ondanks hun wezenlijke verschillen. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Dit is een afgeleide uit eigen ervaring en moet onderzocht worden. <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>1% is het subjectief aangenomen absoluut minimum. <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>Zie ook het <a href="http://preferproject.eu/">PREFER Project</a>: <em>Professional Roles and Employability of Future EngineeRs</em>. <a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 4 June 2018.
</p>
]]>
</description>
</item>
<item>
<title>Teaching by philosophy</title>
<link>https://brainbaking.com/post/2018/05/teaching-philosophy-first/</link>
<comments>https://brainbaking.com/post/2018/05/teaching-philosophy-first/#commento</comments>
<pubDate>Thu, 31 May 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/05/teaching-philosophy-first/</guid>
<category domain="https://brainbaking.com/tags/teaching">teaching</category>
<category domain="https://brainbaking.com/tags/philosophy">philosophy</category>
<description>
<![CDATA[
<p>Also worth reading: <a href="/post/reverse-engineering-a-curriculum/">reverse engineering a curriculum</a>.</p>
<p><strong>Awareness</strong>, that&rsquo;s the keyword I&rsquo;m looking for here.</p>
<p>Students are required to slog through a lot of classes during their university years. You pick a major, computer science, and you start learning things like algorithms, data structures, compilers, operating systems, and more abstract (maybe even worse) things like mathematics, geometry and logic. You of course accept those separate subjects as a part of the computer science major - there&rsquo;s little other choice. Professors do their best at throwing random theories at you while you do your best at catching them - and possibly letting them go after passing the exam.</p>
<h3 id="the-problem">The problem</h3>
<p>But nobody ever tells you why you need to learn mathematics, geometry and logic. You implicitly know algorithms, data structures and compilers are part of &ldquo;computer science&rdquo; and there are overlapping pieces of knowledge to be learned. For instance, the first year you&rsquo;d need to learn a <em>syntax</em> to express those algorithms in. Probably Java. But why would you need to learn the same amount of proofs that mathematics majors need to learn? All subjects are intertwined but you don&rsquo;t know how. And nobody seems to care.</p>
<p>A more concrete example. I teach &ldquo;software design in Java&rdquo;, an introductory course in <strong>software design</strong> using <strong>Java</strong> as a syntax. We need something to express yourselves in and that&rsquo;s not going to be Dutch or English. But since for most students it&rsquo;s also their first time with Java, the &ldquo;design&rdquo; part rapidly succumbs to heavyweight syntax lifting in Java: brackets here, generics there, libraries and imports everywhere. Students simply call this course &ldquo;Java&rdquo;. Uh, wait&hellip;</p>
<p>The &ldquo;software design in&rdquo; part seems to have been be completely dropped. Whoops! Did you as a teacher maybe intend to learn them something else except</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">List</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">string</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">stuff</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">ArrayList</span><span style="color:#728e00">&lt;&gt;();</span> <span style="color:#95a5a6">// don&#39;t forget ;
</span></code></pre></div><p>? Didn&rsquo;t think so.</p>
<h3 id="the-solution">The solution</h3>
<h4 id="1-the-graduate-school-solution-drop-concepts">1. The graduate school solution: drop concepts</h4>
<p>A short sighted solution would be to rename the course.</p>
<blockquote>
<p>Software design in Java -&gt; <strong>Java</strong></p>
</blockquote>
<p>Skip the design, that&rsquo;s something students will pick up during classwork, their thesis or after school. It&rsquo;ll even depend on the firm they will land in so why bother. Just fit them with enough syntax knowledge that is not translatable to another language (because we dropped the concept!). That would require the language to be stable and growing.</p>
<p>And that would require the school to be ever vigilant of &ldquo;hot new fuzz&rdquo; from the IT world so the course &ldquo;Java&rdquo; could be redone in &ldquo;TypeScript&rdquo; or even &ldquo;Solidity&rdquo;.</p>
<h4 id="2-the-university-school-solution-drop-implementation">2. The university school solution: drop implementation</h4>
<p>A short sighted solution would be to rename the course.</p>
<blockquote>
<p>Software design in Java &gt; <strong>Software design</strong></p>
</blockquote>
<p>Skip (emphasis on) the syntax, that&rsquo;s something students will pick up during classwork, their thesis or after school. It&rsquo;ll even depend on the firm they will land in so why bother. Just fit them with enough conceptual knowledge that is applicable in any language (but you&rsquo;d have to get your hands dirty first!).</p>
<p>Did you see what I did there?</p>
<h4 id="3-my-solution-use-philosophy">3. My solution: <strong>use philosophy</strong>!</h4>
<p>Instead of immediately focusing on how to write example x or y in Java, instead focus on <strong>why</strong> you&rsquo;re teaching this course. Focus on why &ldquo;software design&rdquo; is prepended in the course title, but still followed by &ldquo;in Java&rdquo;. I had no clue that by learning (let&rsquo;s call it following a course instead) mathematics, I was actually learning how to use lemma&rsquo;s (something you know works) to deduct another truth (something you&rsquo;re trying to aim at). If the professor explained why math is important to computer science students (pick a concept and apply it somewhere else) and how it fits into my education, I would no doubt have paid more attention.</p>
<p>Therefore, every single practical lab should:</p>
<ol>
<li><a href="https://startwithwhy.com/">Start with why</a></li>
<li>Followed with practical examples using syntax as a means to an end</li>
</ol>
<p>Simply translating &ldquo;MVC&rdquo; into &ldquo;Model-View-Controller&rdquo; would not suffice. Why would you want to separate these concepts? What is each concept? <strong>Show them</strong>. And then, show them the syntax. But since students sleep during the theory (the explaining part) and struggle during the labs (the practical part), you have to be very, very consistent with this message. Repeat it every single time a lesson starts.</p>
<p>Otherwise &ldquo;Software design in Java&rdquo; will inevitably degrade into &ldquo;Java&rdquo;.</p>
<p>That is why <a href="/post/thinking-in-terms-of-objects/">thinking in terms of objects using natural language</a> is so important to me. The most important exercise in the design course contains almost zero syntax difficulty, but since later exercises require more Java knowledge like threading and JavaFX, they seem to be of higher importance.</p>
<p>One could say: &ldquo;I don&rsquo;t really know what threads are doing in such a course!&rdquo; and I would heartily agree with you. But unfortunately, sometimes at schools subject matter is jammed together within one course because of &hellip;. (fill in: time constraints, political issues, lack of consultation with professors)</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 31 May 2018.
</p>
]]>
</description>
</item>
<item>
<title>Over entropie</title>
<link>https://brainbaking.com/post/2018/05/over-entropie/</link>
<comments>https://brainbaking.com/post/2018/05/over-entropie/#commento</comments>
<pubDate>Sun, 20 May 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/05/over-entropie/</guid>
<description>
<![CDATA[
<p>Filosofie kan gezien worden als een <strong>poging</strong> om <strong>dingen</strong> rondom de mensheid te definiëren. Ik noem het een <strong>poging</strong>, en geen manier, omdat we al duizenden jaren kritiek aan het geven zijn op elkaars definities. Ik noem het <strong>dingen</strong>, en niet zichtbare dingen, omdat juist ongrijpbare dingen ons zo sterk intrigeren dat we ook de nood voelen om daar een theoretische vorm aan te koppelen.</p>
<p>Ons bewustzijn produceert veel prachtige wetenschapstakken maar ook veel angsten. Dé grootste angst van de mensheid moet dan wel een doodsangst voor chaos zijn. Welke pogingen ondernemen wij dagelijks om die chaos in te tomen:</p>
<blockquote>
<p>Verwondering -&gt; Angst</p>
</blockquote>
<ul>
<li>Het gras moet afgemaaid zijn. De tuin moet er immers netjes bij liggen. Mails moeten weggewerkt worden. De afwas moet gedaan zijn. De keuken moet er immers ook netjes bij liggen. (<strong>Wegwerken</strong>)</li>
<li>Boeken horen in de boekenkast. Auto&rsquo;s horen in de parking. Liefst mooi in een rijtje, in een op voorhand opgelegde manier &ldquo;gesorteerd&rdquo;. (<strong>Groeperen</strong>)</li>
<li>Pijn hoort benoemd te worden (&ldquo;het zal wel buikpijn zijn, waarschijnlijk van die vis van gisteren&rdquo;). De aanwezigheid van objecten en mensen in een bepaalde omgeving moet een plaats gegeven worden. (&ldquo;Het is normaal dat deze persoon bij ons in de straat komt rond deze tijd, het is de postbode.&quot;) (<strong>Verklaren</strong>)</li>
<li>Ik doe alsof mijn neus bloedt. (<strong>Ontkenning</strong>)</li>
</ul>
<p>Als er aan één of meer van deze voorwaarden niet voldaan wordt stijgt onze stress waarde onverbiddelijk. Om met de grote hoeveelheid aan onzekerheid te kunnen leven verzonnen wij manieren om hier mee om te gaan: onzekerheid wegwerken, onzekerheid groeperen en vooral: onzekerheid verklaren. Deze voorwaarden zijn allemaal varianten van <strong>controle</strong>.</p>
<h3 id="oorspronkelijkheid">Oorspronkelijkheid</h3>
<p>In een poging om de oorspronkelijkheid van alles te verklaren gaat de filosofie doorheen de jaren uit van een aantal stellingen zoals alles is kennis of alles is beheersing. Waarom willen we dingen weten? Waarom willen we dingen beheersen?</p>
<blockquote>
<p>Verwondering -&gt; Angst -&gt; Verklaring</p>
</blockquote>
<p>Het ontstaan van Logos uit de Mythos gebiedt ons varklaring als eindpunt aan te nemen. Maar waarom verklaren wij dingen?<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> Uit drang naar <strong>kennis</strong> of naar <strong>beheersbaarheid</strong> of <strong>zingeving</strong>, de stiekeme joker die positivisten als A. Comte over het hoofd zagen? En waar komt die drang dan van? Vanuit angst. Voor het manifesteren van angst is er verwondering.</p>
<blockquote>
<p>Cosmos: the world or universe regarded as an orderly, harmonious system. a complete, orderly, harmonious system. Order; Harmony. - English Dictionary</p>
</blockquote>
<p>Pythagoras beschreef met het woord &ldquo;<a href="https://en.wikipedia.org/wiki/Cosmos#cite_note-2">kosmos</a>&rdquo; het universum als een oderlijk geheel, in zijn ideologie volledig bestaand uit wiskunde. Veel onderzoeken na Pythagoras voegen hier alleen maar meer verklaringen aan toe onder de noemer van de natuurkunde. Het is duidelijk dat wij als mens nooit openlijk getwijfeld hebben aan de ordelijkheid van het heelal, ook al hebben we dit zelf verzonnen. Noem het maar een wetenschappelijke variant van <strong>controle</strong> - een mooi voorbeeld van groeperen en verklaren.</p>
<p>De oersterke nieuwsgierigheid (verwondering) naar het achterliggende die ons drijft tot een verklaring, ook al is er misschien geen zinnige. &ldquo;De wereld is plat!&rdquo; - 200 jaar later &ldquo;ahneen toch niet!&rdquo;. Of het nu onderbouwd is of niet, en met wat het onderbouwd is, dat maakt allemaal niet uit. Zolang alles maar netjes en ordelijk is, en érgens aan opgehangen kan worden.</p>
<p>Is het je ook al opgevallen dat mensen niet graag toegeven dat ze dingen niet weten? Zelfs wetenschappers trappen hier soms in. Dit is zo gekend dat het zelfs een psychologisch fenomeen is geworden met een toepasselijke naam: <strong><a href="https://en.wikipedia.org/wiki/Jumping_to_conclusions">Jumping conclusion bias</a></strong>. Iets wat niet waargenomen kan worden kan niet verklaard worden en bestaat dus niet, aldus de empirische grondslag van onze exacte wetenschappen. Niet bestaan kan echter ook aanzien worden als een onzekerheid (angst) die door zuivere <strong>ontkenning</strong> aan de kant geschoven wordt.</p>
<h3 id="onzekerheid-wegwerken-en-groeperen">Onzekerheid wegwerken en groeperen</h3>
<p>Veel dingen groeperen onder één gezamelijke noemer geeft minder dingen om mee om te gaan. Wegwerken en groeperen is daarom hetzelfde. Vuile was laten rondslingeren in de slaapkamer, in de sofa en op de keukenkast geeft meer prikkels dan vuile was op één plaats: de linnenmand. <a href="https://en.wikipedia.org/wiki/Cognitive_load">Cognitieve overload</a> treedt op wanneer ons brein met te veel tegelijkertijd te maken krijgt. Dit is wetenschappelijk (empirisch) bewezen en neem ik aan voor waar, niet alleen omdat het voor mijzelf geldt, maar omdat het eenvoudig te extrapoleren is naar iedereen. Wat dan met adrenaline junkies? Onbewuste prikkels zijn ook prikkels: niemand is bezig met zijn boodschappenlijstje, e-mails en aandelen tijdens een vrije val.</p>
<p>Een opgeruimd huis betekent ook een opgeruimd innerlijk. &ldquo;Meer controle over je leven? Begin met opruimen!&rdquo; luidt een slogan over schoonmaken. Dit kunnen we veralgemenen naar de volgende stelling:</p>
<blockquote>
<p>Een opgeruimde buitenwereld betekent ook een opgeruimde innerlijke wereld.</p>
</blockquote>
<p>Mattheüs 23:26 draait de stelling echter om: <em>&ldquo;Gij blinde Farizeer, reinig eerst wat binnen in den drinkbeker en den schotel is, opdat ook het buitenste derzelve rein worde&rdquo;</em>. En daar kan ik wel reden in vinden, net als vele Stoïcijnen. De onzekerheid die we zo neurotisch willen wegwerken is immers slechts een schaduw van ons eigen bewustzijn. Meer hierover later in onzekerheid laten voor wat het is.</p>
<p>Onder &ldquo;wegwerken&rdquo; versta ik ook het <strong>ombuigen van de natuur</strong> naar onze wil. Hoezo hier kunnen geen rijstvelden groeien? Irrigeren die handel! Hoezo jullie beschikken niet over een virusresistente variant van de mango? Importeren die handel! De onzekerheid die weggewerkt wordt is dus zeker niet altijd slecht. Vooruitgang heeft veel te danken aan onze aversie voor chaos. De vraag is echter of we de vraag wel stellen voordat we iets ombuigen. En het antwoord is meer en meer een overduidelijke neen.</p>
<h3 id="onzekerheid-verklaren">Onzekerheid verklaren</h3>
<p>Waarom willen wij toch altijd ons eigen geweten gerust stellen door middel van een onbenullige verklaring? Het gebeurt zo snel dat we er ons niet eens altijd van bewust zijn. Tijdens een overnachting in een burcht op een hoger gelegen gebied in Duitsland merkte mijn vrouw de afwezigheid op van de in dat gebied gekenmerkte agressieve muggen. Ik stond onmiddellijk klaar met een <strong>logische verklaring</strong>: &ldquo;Het is hier hoger, muggen zullen zo hoog niet vliegen.&rdquo;. Achteraf gezien klinkt dat belachelijk, want of het nu waar is of niet, ik ken niets van het gedrag van muggen maar voelde de drang om te antwoorden.</p>
<p>De Westelijke wereld heeft die drang te danken aan de Grieken: de scheiding van de Mythos en de Logos sinds Socrates zorgde voor een dramatische verschuiving in ons denkpatroon. In plaats van te aanvaarden of iets toe te schrijven aan het hogere (dat ook een verklaring kan zijn), gaan we meer onderzoekend dingen bestuderen en verklaren gebaseerd op andere werkelijke verklaringen. Volgens mij heeft Socretes dit verklaren slechts ingedeeld in logica en mythica: de drang om te willen verklaren is ongewijzigd gebleven. Enkel de intensiteit is versterkt. Volgens Comte<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> is mythos een verslapte vorm van logos met al een ingebakken tikje cognitieve verklaring.</p>
<p>Wij denken kennelijk dat we experten zijn in alles, terwijl we in werkelijkheid niets weten. Grootouders die zeggen &ldquo;ga maar naar de Kerk dan maak je minder ruzie&rdquo;, ouders die zeggen &ldquo;ga maar met de auto dat is veiliger&rdquo;, collega&rsquo;s die zeggen &ldquo;gebruik dit maar dat is beter&rdquo;, het Internet die zegt &ldquo;fenomeen x komt door y&rdquo;. Onzekerheid verklaren. En erger: <strong>onzekerheid aannemen</strong>.</p>
<blockquote>
<p>we doen er alles aan om zekerheden te creëren, maar er zijn geen zekerheden in het leven. - Alan Watts</p>
</blockquote>
<p>De onzekerheid van het menselijk bestaan was draagbaar dankzij de <em>mythos</em> van God. Na de Middeleuwen werd dit Geloof meer en meer buiten gewerkt en vervangen door de besturing van logische redenering. Maar niet alles <strong>is</strong> logisch te verklaren. Beter gezegd: niet alle wetenschapstakken zijn volledig uitgewerkt en niet alle personen kennen alle details van alle takken. Dus moeten we altijd terugvallen op (bedorven) kennis van anderen.</p>
<p>Of moeten we terugvallen op onzekerheid.</p>
<h3 id="onzekerheid-laten-voor-wat-het-is">Onzekerheid laten voor wat het is</h3>
<p>In een poging de nood tot controle los te laten kunnen we ook gewoon meer open staan voor onzekerheid in ons leven. In plaats van ons op een bepaalde manier te kleden omdat we reacties vrezen van anderen, kunnen we ook gewoon onze schouders ophalen.</p>
<p>Hoe vaak heb jij je angst voor het onbekende laten zegevieren?<br/>
Juist ja.</p>
<h4 id="minder-wegwerken-en-groeperen">Minder wegwerken en groeperen</h4>
<blockquote>
<p>Een opgeruimde innerlijke wereld vermindert de stress van een onopgeruimde buitenwereld.</p>
</blockquote>
<p>Hoe goed ik ook mijn best doe, het zal me nooit lukken om &ldquo;een opgeruimde innerlijke wereld is een opgeruimde buitenwereld&rdquo; naar waarde te kunnen schatten. De rommel van de buitenwereld blijft bestaan, ik stoor me er gewoon minder aan.</p>
<p>Tot op welke hoogte moeten we ons minder storen aan rommel? De balans opzoeken tussen opruimen en onopgeruimd laten is moeilijk en vooral ook subjectief. Wat doet mij rust geven als ik kijk naar een nauwkeurig verzorgde tuin waar geen greintje chaos meer te bekennen is? Ik weet het niet. Het feit dat ik mijn vinger hier niet op kan leggen duidt toch op een aangeboren oergevoel dat ons <em>instinctief doet weglopen van (te veel) chaos</em>.</p>
<p>Het is dat instinct dat we moeten onder controle krijgen. Merk op dat ik het woord &ldquo;controle&rdquo; hanteer waarvan ik net beweer dat we af moeten geraken! Het beheersen van rauwe emoties valt in diezelfde categorie. Aristoteles zijn <strong>matiging</strong><sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> kan ons ook hier van groot nut zijn: zoek geen grenzen op (ondeugden en deugden) maar zoek matiging op.</p>
<blockquote>
<p>Deugd is de gulden middenweg tussen twee ondeugden: tussen die van overmaat en die van tekortkoming. - Aristoteles</p>
</blockquote>
<p>Het blijven wegwerken van vetcellen, het dwangmatig opkuisen, het willen overwinnen wat niet overwonnen kan worden, het niet ontkennen van het kennen. Allemaal opgelost met matiging. Want volledig stoppen met wegwerken van vetcellen, kuisen en overwinnen zou ons roven van een doel en uiteindelijk ook lust om te leven.</p>
<h4 id="minder-verklaren">Minder verklaren</h4>
<p>In hoeverre is verklaren hetzelfde als oordelen? Een oordeel vellen gebeurt zo snel dat we het zelf bijna nooit door hebben. Systeem 1 (het snelle, onderbewuste, primitieve brein) van Daniel Kahneman<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> oordeelt in minder dan één oogwenk gebaseerd op een complex aantal parameters waarvan zowel huidige zintuigen als voorgaande geregistreerde gebeurtenissen deel uitmaken. Het goede nieuws is dat we blijkbaar wel in staat kunnen zijn om dit (gedeeltelijk) te overschrijven met Systeem 2 (het trage, beredenerende brein), voordat het gevolg van de handelingen van systeem 1 de volledige greep krijgt over ons bewustzijn.</p>
<p>De Stoïcijnce<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> (verklaring van) oordelen zoekt het in het innerlijke, en niet in de wereld rondom ons. Waarom willen we een onbekende persoon die mogelijks als &ldquo;dreigend&rdquo; gezien kan worden door Systeem 1 onmiddellijk kunnen classificeren door te proberen verklaren waarom deze persoon in onze nabijheid is? Om het aantal onbekende variabelen te kunnen reduceren en ons stress niveau te laten zakken. De makkelijkste verklaring is een verklaring buiten onszelf. Die chauffeur rijdt slecht &ldquo;want het is een Johnny&rdquo;. Criteria? Volkswagen, petje, zonnebril. Die chauffeur rijdt slecht &ldquo;want het is weer een vrouw&rdquo;. Doe je oordeel weg, en weg is je gevoel, ik ben benadeeld.</p>
<blockquote>
<p>Doe je oordeel weg, en weg is je gevoel, &ldquo;ik ben benadeeld&rdquo;. - Marcus Aurelius</p>
</blockquote>
<p>In plaats van zonder meer verklaringen - van anderen én van jezelf - aan te nemen, kunnen we ons misschien beter eerst enkele kritische vragen stellen:</p>
<ol>
<li>Is het wel nodig dat ik dit weet? (Moet het verklaard worden?)</li>
<li>Is deze persoon iemand die snel verklaringen geeft om zijn eigen angst onder controle te houden?</li>
<li>Is een tweede verklaring nodig?</li>
</ol>
<p>Ik heb uit ervaring geleerd dat pessimisten meer angst tonen door sneller (onlogische) verklaringen te geven dan optimisten. Na een tijdje leer je aan te voelen bij wie je meer of minder moet twijfelen. Vergeet niet dat dit ook op jezelf van toepassing is!</p>
<h4 id="is-er-zonder-verklaringen-wel-een-toekomst">Is er zonder verklaringen wel een toekomst?</h4>
<p>De filosofie is immers niets meer dan één groot onderzoek naar het onderzoek - het <em>meta-</em> onderzoek. Maar het is evenzeer op zoek naar verklaringen, en evenzeer in de hoop om entropie te kunnen beteugelen. Onze wetenschappelijke honger drijft ons altijd maar verder. Weinig mensen zullen durven toegeven dat dit negatief is en ons wijzen op de geweldigste en beste uitvindingen van ons als mensheid zoals kernenergie, ruimtevaart en geneeskunde. De weg der vooruitgang als énige weg is een onwrikbaar idee dat diep geankerd zit in ons Westerlijk denken.</p>
<p>In mijn ogen is er niets meer natuurlijk aan een IVF-behandeling. Dat klinkt erg hard voor mensen die een grote kinderwens hebben en niet willen aanvaarden dat dit niet voor hun is weggelegd. Met &ldquo;weggelegd&rdquo; doel ik niet op een hogere entiteit die op voorhand iemand&rsquo;s lot zou vastleggen, maar op de helaasheid van stom &ldquo;toeval&rdquo;, of chaos. Het woord toeval of geluk in die context is trouwens een synoniem voor chaos: we kunnen iets niet verklaren dus schrijven het maar &ldquo;ergens&rdquo; aan toe. In plaats van als mens <strong>alles</strong> te wensen overwinnen, zelfs de dood, het leven en de ruimte, wordt het dringend tijd te beseffen dat we op veel vlakken te ver aan het gaan zijn.</p>
<p>Ik zou stom zijn om te ontkennen dat onze gezonde schrik van chaos ons niet ver gebracht zou hebben. Maar de redenen om verder te blijven gaan zijn ondertussen ook veranderd. Weten wij nog waarom we sommige dingen blijven verder verklaren? Het verhaal heeft ondertussen ook een politiek en kapitalistisch tintje gekregen: &ldquo;wij als X zullen eens laten zien hoe ver we staan&rdquo;.</p>
<p>Als computerwetenschapper ben ik maar al te graag bezig met onderzoek en het aanbrengen van structuur en dus het &ldquo;overwinnen&rdquo; van chaos of het &ldquo;scheppen&rdquo; van orde. Toch vraag ik mij regelmatig af wat het nut is van die overwinningen en scheppingen. Meestal dienen ze slechts als financiëel doel in de ogen van anderen.</p>
<blockquote>
<p>Verwondering.</p>
</blockquote>
<p><strong>Stil staan en niet verklaren doet soms véél meer deugd dan vooruit gaan en verklaren.</strong></p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>Paul Cortois, Meditaties bij een machine, deel 1: interesses, instrumenteel en intrinsiek <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Auguste Comte, A general view of positivism <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Aristoteles, Nicomachean Ethics Book I: defining eudaimonia and the aim of Ethics <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>Daniel Kahneman, Thinking fast and slow <a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p>Marcus Aurelius, Meditaties <a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
<p>
By <a href="/about">Wouter Groeneveld</a> on 20 May 2018.
</p>
]]>
</description>
</item>
<item>
<title>Thinking in terms of objects</title>
<link>https://brainbaking.com/post/2018/04/thinking-in-terms-of-objects/</link>
<comments>https://brainbaking.com/post/2018/04/thinking-in-terms-of-objects/#commento</comments>
<pubDate>Sat, 28 Apr 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/04/thinking-in-terms-of-objects/</guid>
<category domain="https://brainbaking.com/tags/teaching">teaching</category>
<description>
<![CDATA[
<p>Writing software isn&rsquo;t much different than describing a world. <strong>The</strong> world, where we live in, is <strong>a</strong> world, not the <strong>only</strong> one. With software, we could, theoretically speaking, describe our own world. If we don&rsquo;t think about software, how would we describe that or another world? How would I build a fantasy world in a novel where my readers can relate to the world and be engaged?</p>
<p>By <strong>describing</strong> with our <strong>language</strong>. If there descriptions are a priori or a posteriori doesn&rsquo;t really matter.</p>
<h2 id="using-language-to-describe-a-world">Using language to describe a world</h2>
<p>I can claim the following</p>
<blockquote>
<p>&ldquo;Two plus three is five&rdquo;</p>
</blockquote>
<p>No senses are involved in this claim, and this is a tautology. (A = A, 2 + 3 = 5, the left-hand side of the equation is the right-hand side and the other way around.) This claim is a bit more difficult to put in terms of objects, because when we try to decronstruct the sentence, we can extract the following elements:</p>
<ul>
<li>What is &ldquo;plus&rdquo; (an operation)</li>
<li>What is &ldquo;two&rdquo;, &ldquo;three&rdquo; and &ldquo;five&rdquo; (numbers)</li>
<li>What is &ldquo;is&rdquo; (the equation)</li>
</ul>
<p>THe &ldquo;operation&rdquo; is something we can do with the &ldquo;numbers&rdquo;. I put operation between quotes because it denotes a property on the second word between quotes, &ldquo;numbers&rdquo;. Thus we can deduct the following object with properties:</p>
<pre><code>Number {
plus(Number other);
}
</code></pre>
<p>As we know, in any (modern) programming language, the concept of numbers is almost always defined for us. &ldquo;Things&rdquo; involving mathematics - or any a priori claim - are usually provided. In <em>Ruby</em>, numbers are first-class citizens meaning they are also objects - as they should be.</p>
<p>As a second example, I could also claim:</p>
<blockquote>
<p>&ldquo;A tree has a green leaf&rdquo;</p>
</blockquote>
<p>This clearly is a posteriori claim: to be able to verify its truthfulness, you&rsquo;d have to see with your own eyes that the leaf is in fact green. A posteriori claims are much easier to convert into objects as we have implicitly learned our own language empirically.</p>
<p>So:</p>
<ul>
<li>What is &ldquo;tree&rdquo; (a &ldquo;something&rdquo;)</li>
<li>What is &ldquo;has&rdquo; (denoting a property)</li>
<li>What is &ldquo;green&rdquo; (a property)</li>
<li>What is &ldquo;leaf&rdquo; (another property, of the tree, and a &ldquo;something&rdquo;)</li>
</ul>
<p>As soon as we encounter <strong>has a</strong> in a sentence, we know it means the left-hand side of the &ldquo;has a&rdquo; is the one receiving the property, and the right-hand side is the property we&rsquo;re talking about.</p>
<blockquote>
<p>&ldquo;(A tree) HAS A (green leaf)&rdquo;</p>
</blockquote>
<p>Gives us:</p>
<pre><code>Tree {
green leaf
}
</code></pre>
<p>But what&rsquo;s a green leaf?</p>
<pre><code>Tree {
Leaf {
green
}
}
</code></pre>
<p>&ldquo;A tree has a green leaf&rdquo; means &ldquo;a tree has a leaf, and that leaf is green&rdquo;. But what does &ldquo;green&rdquo; mean?</p>
<blockquote>
<p>&ldquo;(A tree) HAS A (leaf). (That leaf) HAS A (color), (That color) IS (green)&rdquo;</p>
</blockquote>
<p>So we&rsquo;re missing a few properties that are hidden within the structure of our language!</p>
<pre><code>Tree {
Leaf {
Color: green
}
}
</code></pre>
<p>The schematic is confusing when we&rsquo;re talking about &ldquo;a tree has a green leaf&rdquo; and &ldquo;a Shrubbery has a brown leaf&rdquo;. In that case we&rsquo;d also need to define:</p>
<pre><code>Shrubbery {
Leaf {
Color: brown
}
}
</code></pre>
<p>, And those &ldquo;Leaf&rdquo; objects are one and the same: they describe a leaf that can have the property color. Of course, the leaves of the tree are not the same as the leaves on the shrubbery, but they both can be classified as &ldquo;Leaf&rdquo;. <strong>in context of</strong> shrubberies and trees, it&rsquo;s obvious that we&rsquo;re talking about leaves as organic material with a color that can wither.</p>
<pre><code>Tree {
leaf(green)
}
Shrubbery {
leaf(brown)
}
Leaf {
color
}
</code></pre>
<p>In fact, in my first claim, I can deduct the following: &ldquo;numbers can be added up with each other&rdquo; simplified to &ldquo;numbers can be <em>plussed</em> with each other&rdquo; and thus &ldquo;(a Number) HAS A (plus another number)&rdquo;.</p>
<p>Notice that, in a <strong>formal language</strong> such as a programming language, objects aren&rsquo;t handled exactly the same as our syntactically correct speaking language:</p>
<ul>
<li>&ldquo;A green leaf&rdquo; becomes &ldquo;<strong>object</strong> leaf with <strong>property</strong> color that <strong>is</strong> green&rdquo; - I didn&rsquo;t talk about colors at all!</li>
<li>&ldquo;A lazy employer&rdquo; becomes &ldquo;<strong>object</strong> employer with <strong>property</strong> character that <strong>is</strong> lazy&rdquo; - I didn&rsquo;t talk about character at all!</li>
</ul>
<p>Those implicit extra properties that we need, &ldquo;color&rdquo; and &ldquo;character&rdquo;, can be valid objects on their own.</p>
<pre><code>Color {
Redvalue
Greenvalue
Bluevalue
Aphavalue
}
Character {
Wellbeingness
Laborwillingness
}
</code></pre>
<p>The pure color &ldquo;green&rdquo; could then be defined as Color(red: 0, green: max, blue: 0, alpha: max). There character &ldquo;lazy&rdquo; could then be defined as Character(Wellbeingness: ?, Laborwillingness: low). Notice the first property of the object &ldquo;character&rdquo;: it&rsquo;s undefined. It&rsquo;s there, but we don&rsquo;t care if we&rsquo;re talking about a lazy character. We do care about the red, blue and alpha values if we&rsquo;re talking about pure green: otherwise a color wouldn&rsquo;t be viewed as &ldquo;green&rdquo;.</p>
<h2 id="relationships-in-a-world">Relationships in a world</h2>
<p>When thinking in terms of objects, we&rsquo;ve seen two major categories of partial sentences:</p>
<ol>
<li>X <strong>HAS-A</strong> Y</li>
<li>X <strong>IS-A</strong> Y</li>
</ol>
<h3 id="1-property-acquisition">1. Property acquisition</h3>
<p>This should hopefully be clear by now after looking at the &ldquo;a tree has a leaf&rdquo; example, leaving behind the complexity of the color.</p>
<h3 id="2-property-definition">2. Property definition</h3>
<p>Without directly using the technical term &ldquo;inheritance&rdquo;, &ldquo;x is y&rdquo; defines X in terms of Y. &ldquo;green is a color&rdquo;, or implicitly &ldquo;the leaf is green&rdquo;. Things can indeed build upon other things by defining <strong>subsets</strong>:</p>
<blockquote>
<p>&ldquo;a tree has a leaf&rdquo;</p>
</blockquote>
<p>combined with</p>
<blockquote>
<p>&ldquo;an oak is a tree&rdquo;</p>
</blockquote>
<p>means</p>
<blockquote>
<p>&ldquo;an oak has a leaf&rdquo;</p>
</blockquote>
<p>, since the oak <strong>is a</strong> tree. We can build a simple schematic of the oak like this:</p>
<pre><code>Tree {
leaf
}
Oak is-a Tree {
}
</code></pre>
<p>To avoid having to redefine the leaf as part of the oak, a <em>keyword</em> is used to denote the relationship between the oak and the tree. Once the assumption of the tree containing a leaf holds, we can safely conclude the oak also contains a leaf. In Java, &ldquo;is-a&rdquo; means <code>extends</code> and <code>implements</code>, in C# or C++ <code>:</code>.</p>
<p>Organic matter in our own world consists of other organic matter, that can be reduced to chemicals, that can be reduced to sub-atoms. That doesn&rsquo;t necessarily mean we should introduce all those concepts in the world we&rsquo;re building. <strong>Only introduce a concept if it has some meaning</strong> in your world. Are you going to do something with it? Will it be able to decide things on it&rsquo;s own? Will it contain logic? If that is not the case, don&rsquo;t bother.</p>
<p>Remember to make <em>implicit concepts</em> <strong>explicit</strong>. Don&rsquo;t forget &ldquo;color&rdquo;!</p>
<h2 id="in-practice">In practice</h2>
<p>The most challenging part about writing (software) is deconstructing the requirements in the above terms to be able to identify our much-needed objects. Let&rsquo;s look at an example.ca</p>
<p>You&rsquo;re creating a simple game in which a character (Mario) can move in a 2D world, collecting coins within a time limit. Mario moves in a level that has enemies and can die if he touches one.</p>
<p>Redefine that world in those sentences or <em>acceptance criteria</em>:</p>
<ol>
<li>Mario can move =&gt; Mario &ldquo;has a&rdquo; move()</li>
<li>Moving can be done on the X or Y axis =&gt; move &ldquo;needs a&rdquo; X, Y</li>
<li>Mario has a total score</li>
<li>Mario can collect coins</li>
<li>A coin has a static score</li>
<li>The world has a time limit</li>
<li>Enemies can move</li>
<li>Mario can touch someone</li>
<li>Enemies can touch someone</li>
<li>Die is &ldquo;game over&rdquo;</li>
<li>&hellip;</li>
</ol>
<p>Since Mario and the enemies share properties, it would be wise to reduce the clutter by defining both as a <code>Player</code> or moving object.</p>
<p>All these claims are true context of the <code>Game</code> or <code>2D World</code> (we also might need those concepts as our base collection of objects). The fact that Mario <strong>can</strong> move has the same connotation that Mario <strong>has-a</strong> &ldquo;move&rdquo; property. We could define a third category of a sentence:</p>
<blockquote>
<p>Move needs a X and Y (in order to &ldquo;work&rdquo;)</p>
</blockquote>
<p>Mario can move, but won&rsquo;t move without providing a direction. Since the world is a 2D world, there will be two (dimensions) times two (positive, negative) possibilities.
Instead of saying &ldquo;move needs a x&rdquo;, one can also say <em>&ldquo;move has-a direction&rdquo;</em> that eliminates the need of a third keyword.</p>
<p>Now it&rsquo;s your turn to come up with a schematic for the identified objects! Try not to <strong>over-analyze</strong> the criteria by building something too complex. It will grow - and shrink - in time.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 28 April 2018.
</p>
]]>
</description>
</item>
<item>
<title>Death to pseudocode?</title>
<link>https://brainbaking.com/post/2018/04/pseudocode/</link>
<comments>https://brainbaking.com/post/2018/04/pseudocode/#commento</comments>
<pubDate>Fri, 06 Apr 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/04/pseudocode/</guid>
<category domain="https://brainbaking.com/tags/java">java</category>
<category domain="https://brainbaking.com/tags/functional programming">functional programming</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/btrees.png"/>
</p>
<p>Coming across pseudocode isn&rsquo;t something that might happen every day except if you&rsquo;re used to browsing through the more theoretical and academic oriented &ldquo;computer science&rdquo; handbooks. We, the practical &ldquo;software engineers&rdquo; of nowadays, usually stop searching for something after our browser hits Stackoverflow. Stack is loaded with technical samples, gists of code, and lot&rsquo;s of won&rsquo;t-ever-compile-wrongly-copy-pasted code. Real code. If you&rsquo;re working in Java, you probably end up with articles full of Java snippets.</p>
<p>That got me wondering. Why would one go into the trouble of putting together pseudocode to present to the reader? He or she has to make the translation into the language he or she is currently working with. Yes, it&rsquo;s obnoxious but it also gives everyone the opportunity to implement the example in their own language, whether it&rsquo;s functional or not. Does this positive outweigh the negative? It sometimes does not.</p>
<p>Consider for example a more theoretical example. In <a href="https://www.goodreads.com/book/show/108986.Introduction_to_Algorithms?ac=1">Introduction to Algorithms</a>, a proportion of the chapters is dedicated to different sorting algorithms. The following pseudocode describes the partitioning subroutine of quick sort:</p>
<pre><code>/**
* partition list so that each element of A[p..q-1] &lt;= A[q] &lt;= A[q + 1 .. r]
* x &lt;- A[r]
* i &lt;- p - 1
* for j &lt;- p to r - 1
* do if A[j] &lt;= x
* then i &lt;- i + 1
* exchange A[i] with A[j]
* exchange A[i + 1] with A[r]
* return i + 1
* @param list A
* @param oneBasedStartIndex p
* @param oneBasedEndIndex r
* @return i + 1 (partition index)
*/
</code></pre>
<p>It&rsquo;s javadoc wrapped around the method <code>protected int partition(List&lt;Integer&gt; list, int oneBasedStartIndex, int oneBasedEndIndex) {</code>. I&rsquo;d like to point out a few things about this pseudocode:</p>
<ol>
<li>variable assignment (line 1, 2) is exactly the same as in real code.</li>
<li>The same applies for a loop, given you&rsquo;re not writing in Scala.</li>
<li>Then, we hit a roadblock. What does &ldquo;exchange A[i] with A[j]&rdquo; mean?</li>
</ol>
<p>Then, it hit me. Real code should reflect pseudocode. Not only reflect it, but literally read like it. I&rsquo;m thinking about clean code now, and <a href="/post/hiding-complexity/">hiding the complexity in methods</a>. Rob Cameron knows exactly what I mean, he calls hit &ldquo;<a href="https://dev.to/cannikin/make-your-pseudocode-your-real-code-96n">Make Your Pseudocode Your Real Code</a>&rdquo;. He shows a crystal clear example from some pseudocode in Ruby on Rails to his first effort in implementing it. But it doesn&rsquo;t stop there: with some clever method extractions, you can get pretty close to the original pseudocode. Human readable code. Ubiquitous.</p>
<p>This is my implementation of the partition method:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"> <span style="color:#00979d">int</span> <span style="color:#434f54">x</span> <span style="color:#728e00">=</span> <span style="color:#434f54">list</span><span style="color:#728e00">.</span><span style="color:#434f54">get</span><span style="color:#728e00">(</span><span style="color:#434f54">oneBasedEndIndex</span> <span style="color:#728e00">-</span> <span style="color:#434f54">1</span><span style="color:#728e00">);</span>
<span style="color:#00979d">int</span> <span style="color:#434f54">i</span> <span style="color:#728e00">=</span> <span style="color:#434f54">oneBasedStartIndex</span> <span style="color:#728e00">-</span> <span style="color:#434f54">1</span><span style="color:#728e00">;</span>
<span style="color:#728e00">for</span><span style="color:#728e00">(</span><span style="color:#00979d">int</span> <span style="color:#434f54">j</span> <span style="color:#728e00">=</span> <span style="color:#434f54">oneBasedStartIndex</span><span style="color:#728e00">;</span> <span style="color:#434f54">j</span> <span style="color:#728e00">&lt;=</span> <span style="color:#434f54">oneBasedEndIndex</span> <span style="color:#728e00">-</span> <span style="color:#434f54">1</span><span style="color:#728e00">;</span> <span style="color:#434f54">j</span><span style="color:#728e00">++)</span> <span style="color:#728e00">{</span>
<span style="color:#728e00">if</span><span style="color:#728e00">(</span><span style="color:#434f54">list</span><span style="color:#728e00">.</span><span style="color:#434f54">get</span><span style="color:#728e00">(</span><span style="color:#434f54">j</span> <span style="color:#728e00">-</span> <span style="color:#434f54">1</span><span style="color:#728e00">)</span> <span style="color:#728e00">&lt;=</span> <span style="color:#434f54">x</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">i</span><span style="color:#728e00">++;</span>
<span style="color:#434f54">Lists</span><span style="color:#728e00">.</span><span style="color:#434f54">exchangeIndexes</span><span style="color:#728e00">(</span><span style="color:#434f54">list</span><span style="color:#728e00">,</span> <span style="color:#434f54">i</span><span style="color:#728e00">,</span> <span style="color:#434f54">j</span><span style="color:#728e00">);</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">}</span>
<span style="color:#434f54">Lists</span><span style="color:#728e00">.</span><span style="color:#434f54">exchangeIndexes</span><span style="color:#728e00">(</span><span style="color:#434f54">list</span><span style="color:#728e00">,</span> <span style="color:#434f54">i</span> <span style="color:#728e00">+</span> <span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">oneBasedEndIndex</span><span style="color:#728e00">);</span>
<span style="color:#728e00">return</span> <span style="color:#434f54">i</span> <span style="color:#728e00">+</span> <span style="color:#434f54">1</span><span style="color:#728e00">;</span>
</code></pre></div><p>Instead of doing the swapping in 3 lines, two times repeated, they&rsquo;re simply hidden:</p>
<pre><code> int temp = list.get(oneBasedA - 1);
list.set(oneBasedA - 1, list.get(oneBasedB - 1));
list.set(oneBasedB - 1, temp);
</code></pre>
<p>Pseudocode makes it possible to understand what an algorithm should do, even in technical terms, closely related to real code. Without the clutter of your favorite language. &ldquo;Exchange indexes&rdquo; is still not the same as &ldquo;exchange x with y&rdquo;. We&rsquo;re entering the realm of <strong>Domain Specific Languages</strong> (DSL) here. After sleeping over it for a few days, I refactored the above code to:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">exchange</span><span style="color:#728e00">(</span><span style="color:#434f54">i</span><span style="color:#728e00">).</span><span style="color:#434f54">with</span><span style="color:#728e00">(</span><span style="color:#434f54">j</span><span style="color:#728e00">).</span><span style="color:#434f54">in</span><span style="color:#728e00">(</span><span style="color:#434f54">list</span><span style="color:#728e00">);</span>
</code></pre></div><p>What a difference. Exchange act as a <a href="/post/builders-dsl">builder pattern</a> and wraps oneBasedA in a new class that gets mutated by oneBasedBy. The final act, <code>in(list)</code>, redirects to the actual implementation.</p>
<p>At first, I wasn&rsquo;t really convinced, because it does require quite a bit of work to translate it into actual code - based on the target language. If a book like &ldquo;introduction to algorithms&rdquo; would present elementary algorithms in plain &ldquo;old&rdquo; Python, it would require students to have some knowledge of it. But then again, would that be a bad thing? That will reduce the overhead required to comprehend what&rsquo;s going on.</p>
<p>I&rsquo;m still not really fond of presenting pseudocode in an academic book. I want to focus on comprehension, not on syntax translation after I know what I have to do. I still often swear while trying out a certain algorithm in a textbook because one line of pseudocode contains so much <strong>hidden assumptions</strong>:</p>
<ul>
<li>You&rsquo;d almost need to write mutable code, even if you don&rsquo;t want to.</li>
<li>It&rsquo;s mostly not really suited for extreme object-oriented programming if it&rsquo;s not designed for that. That doesn&rsquo;t mean it&rsquo;s not possible, but simply that it&rsquo;s more work to do the translation.</li>
<li>It&rsquo;s mostly not really suited for functional programming if it&rsquo;s not designed for that. That doesn&rsquo;t mean it&rsquo;s not possible, but simply that it&rsquo;s more work to do the translation.</li>
</ul>
<p>On the other hand, I certainly agree with Rob: pseudocode is extremely useful to <strong>make things clear</strong>. For designing new parts together with colleagues, for rapid architecture design and for <a href="/post/serendipitous-creativity/">talking to the duck</a>. When it comes to <strong>clear code</strong>, there&rsquo;s nothing better than a shared understanding, independent of any programming language. Given you can translate any pseudocode to clear &ldquo;pseudo/real&rdquo; code, I&rsquo;d rather come across something like that, where a part of the heavy language lifting has been done for me.</p>
<p>What else can accompany pseudocode? Clear unit tests:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"> <span style="color:#434f54">@Test</span>
<span style="color:#728e00">public</span> <span style="color:#00979d">void</span> <span style="color:#d35400">bucketSort</span><span style="color:#728e00">()</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">simpleTestCaseFor</span><span style="color:#728e00">(</span><span style="color:#728e00">new</span> <span style="color:#434f54">BucketSort</span><span style="color:#728e00">());</span>
<span style="color:#728e00">}</span>
<span style="color:#434f54">@Test</span>
<span style="color:#728e00">public</span> <span style="color:#00979d">void</span> <span style="color:#d35400">quickSort</span><span style="color:#728e00">()</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">simpleTestCaseFor</span><span style="color:#728e00">(</span><span style="color:#728e00">new</span> <span style="color:#434f54">QuickSort</span><span style="color:#728e00">());</span>
<span style="color:#728e00">}</span>
<span style="color:#434f54">@Test</span>
<span style="color:#728e00">public</span> <span style="color:#00979d">void</span> <span style="color:#d35400">heapSort</span><span style="color:#728e00">()</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">simpleTestCaseFor</span><span style="color:#728e00">(</span><span style="color:#728e00">new</span> <span style="color:#434f54">HeapSort</span><span style="color:#728e00">());</span>
<span style="color:#728e00">}</span>
<span style="color:#434f54">@Test</span>
<span style="color:#728e00">public</span> <span style="color:#00979d">void</span> <span style="color:#d35400">insertionSort</span><span style="color:#728e00">()</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">simpleTestCaseFor</span><span style="color:#728e00">(</span><span style="color:#728e00">new</span> <span style="color:#434f54">InsertionSort</span><span style="color:#728e00">());</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">private</span> <span style="color:#00979d">void</span> <span style="color:#d35400">simpleTestCaseFor</span><span style="color:#728e00">(</span><span style="color:#434f54">Sortable</span> <span style="color:#434f54">sorter</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">List</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">Integer</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">result</span> <span style="color:#728e00">=</span> <span style="color:#434f54">sorter</span><span style="color:#728e00">.</span><span style="color:#434f54">sort</span><span style="color:#728e00">(</span><span style="color:#434f54">Arrays</span><span style="color:#728e00">.</span><span style="color:#434f54">asList</span><span style="color:#728e00">(</span><span style="color:#434f54">4</span><span style="color:#728e00">,</span> <span style="color:#434f54">2</span><span style="color:#728e00">,</span> <span style="color:#434f54">3</span><span style="color:#728e00">,</span> <span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">6</span><span style="color:#728e00">,</span> <span style="color:#434f54">5</span><span style="color:#728e00">));</span>
<span style="color:#434f54">Assertions</span><span style="color:#728e00">.</span><span style="color:#434f54">assertArrayEquals</span><span style="color:#728e00">(</span><span style="color:#434f54">Arrays</span><span style="color:#728e00">.</span><span style="color:#434f54">asList</span><span style="color:#728e00">(</span><span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">2</span><span style="color:#728e00">,</span> <span style="color:#434f54">3</span><span style="color:#728e00">,</span> <span style="color:#434f54">4</span><span style="color:#728e00">,</span> <span style="color:#434f54">5</span><span style="color:#728e00">,</span> <span style="color:#434f54">6</span><span style="color:#728e00">).</span><span style="color:#434f54">toArray</span><span style="color:#728e00">(),</span> <span style="color:#434f54">result</span><span style="color:#728e00">.</span><span style="color:#434f54">toArray</span><span style="color:#728e00">());</span>
<span style="color:#728e00">}</span>
</code></pre></div><p>What&rsquo;s missing? These are integration tests that verify the whole algorithm. For quicksort, the partitioning is a substantial part of the sorting process that deserves it&rsquo;s own test cases, tucked away in <code>QuickSortTest.java</code>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"> <span style="color:#434f54">@Test</span>
<span style="color:#728e00">public</span> <span style="color:#00979d">void</span> <span style="color:#d35400">partition_accordingToR</span><span style="color:#728e00">()</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">QuickSort</span> <span style="color:#434f54">sort</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">QuickSort</span><span style="color:#728e00">();</span>
<span style="color:#434f54">List</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">Integer</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">toPartition</span> <span style="color:#728e00">=</span> <span style="color:#434f54">Arrays</span><span style="color:#728e00">.</span><span style="color:#434f54">asList</span><span style="color:#728e00">(</span><span style="color:#434f54">2</span><span style="color:#728e00">,</span> <span style="color:#434f54">8</span><span style="color:#728e00">,</span> <span style="color:#434f54">7</span><span style="color:#728e00">,</span> <span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">3</span><span style="color:#728e00">,</span> <span style="color:#434f54">5</span><span style="color:#728e00">,</span> <span style="color:#434f54">6</span><span style="color:#728e00">,</span> <span style="color:#434f54">4</span><span style="color:#728e00">);</span>
<span style="color:#434f54">List</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">Integer</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">partitioned</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">ArrayList</span><span style="color:#728e00">&lt;&gt;(</span><span style="color:#434f54">toPartition</span><span style="color:#728e00">);</span>
<span style="color:#434f54">sort</span><span style="color:#728e00">.</span><span style="color:#434f54">partition</span><span style="color:#728e00">(</span><span style="color:#434f54">partitioned</span><span style="color:#728e00">,</span> <span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">toPartition</span><span style="color:#728e00">.</span><span style="color:#434f54">size</span><span style="color:#728e00">());</span>
<span style="color:#434f54">Assertions</span><span style="color:#728e00">.</span><span style="color:#434f54">assertArrayEquals</span><span style="color:#728e00">(</span><span style="color:#434f54">partitioned</span><span style="color:#728e00">.</span><span style="color:#434f54">toArray</span><span style="color:#728e00">(),</span> <span style="color:#434f54">Arrays</span><span style="color:#728e00">.</span><span style="color:#434f54">asList</span><span style="color:#728e00">(</span><span style="color:#434f54">2</span><span style="color:#728e00">,</span> <span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">3</span><span style="color:#728e00">,</span> <span style="color:#434f54">4</span><span style="color:#728e00">,</span> <span style="color:#434f54">7</span><span style="color:#728e00">,</span> <span style="color:#434f54">5</span><span style="color:#728e00">,</span> <span style="color:#434f54">6</span><span style="color:#728e00">,</span> <span style="color:#434f54">8</span><span style="color:#728e00">).</span><span style="color:#434f54">toArray</span><span style="color:#728e00">());</span>
<span style="color:#728e00">}</span>
</code></pre></div><p>It&rsquo;s usually not that hard to extract unit tests from books like Introduction to Algorithms: they provide a lot of visual examples to clear up any misunderstandings. Each partitioning step of quicksort can be drawn separately using the current partitioned array so you can see what&rsquo;s going on with each instructive cycle. Simply use these examples: throw them in a test case and you&rsquo;re all set.</p>
<p>And yet, a part of me wished for a deeper integration of unit testing and clear code as a blueprint to take on those nasty mathematical problems, instead of the separate (too) abstract pseudocodes of &ldquo;subroutines&rdquo; (That word alone says enough.) I&rsquo;ve seen books like &ldquo;growing object-oriented software guided by tests&rdquo; and books like &ldquo;introduction to the theory of computation&rdquo;, but I&rsquo;ve yet to see a book that manages to combine theory with (clear code and) tests&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 6 April 2018.
</p>
]]>
</description>
</item>
<item>
<title>Concentrating on serendipitous creativity</title>
<link>https://brainbaking.com/post/serendipitous-creativity/</link>
<comments>https://brainbaking.com/post/serendipitous-creativity/#commento</comments>
<pubDate>Sun, 25 Mar 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/serendipitous-creativity/</guid>
<category domain="https://brainbaking.com/tags/collaboration">collaboration</category>
<category domain="https://brainbaking.com/tags/concentration">concentration</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/tea.png"/>
</p>
<p>When was the last time you were able to focus well on a difficult task in an office landscape? For long periods of time? Did you manage to finish the task in time? Knowledge workers are increasingly pushed together in large open spaces to promote collaboration and serendipity. But those unplanned happy accidents create another completely unplanned rather unhappy accident: the loss of concentration. According to Cal Newport&rsquo;s &ldquo;<a href="https://www.goodreads.com/book/show/25744928-deep-work">Deep Work</a>&rdquo; term, long uninterrupted hours of concentration manage to get difficult things done - not short bursts of collaboration. He calls those bursts &ldquo;Shallow Work&rdquo;. Being able to concentrate well for a longer period of time is often needed to solve a complex problem. Problems like these are not uncommon in the software industry where I&rsquo;m in. Deliberate practice and &ldquo;flow&rdquo; are related to Deep Work. The ability to concentrate for longer periods on time is becoming an increasingly rare skill.</p>
<p>It doesn&rsquo;t take a genius to realize constant interruption (called collaboration) doesn&rsquo;t do your concentration skills any good. But locking yourself in a room all day wouldn&rsquo;t work either because some shallow collaboration tasks are required to bring a big project to a happy end.</p>
<p>And that brings us to the first <strong>impasse</strong>: the current trend in latest office landscaping fully favors collaboration. It&rsquo;s almost impossible not to see all your colleagues while you&rsquo;re stationed at your &ldquo;desk&rdquo; (squeezed between two others): peer pressure is imminent. That&rsquo;s most of the time a good thing: nobody likes seeing someone wasting his time surfing away while you&rsquo;re working your ass off. But that unconsciously creates stress even if you&rsquo;re sure that you&rsquo;re okay with it. offices are designed to increase the like-hood of <strong>happy accidents</strong>: bumping into a colleague who&rsquo;s working on something else. That bump might just create the next best thing as (if you both are open for it) you share ideas and merge two thoughts into one.</p>
<p><figure>
<a href="/img/bert_and_ernie.jpg" class="lbox">
<img loading="lazy" src="/img/bert_and_ernie.jpg" alt="Talk to the duck!" >
</a>
</figure>
</p>
<p>In software engineering, that concept is called &ldquo;<strong>talk to the duck</strong>&rdquo;. (The duck being your colleague) If you don&rsquo;t know how to solve a problem, likely you&rsquo;re simply suffering from some sort of tunnel vision. Once another approach to the problem is suggested and your &ldquo;aha&rdquo; moment has passed, the problem made its way for a solution. A similar approach to finding another strategy to approach the problem is taking a break. Stand up, walk a bit, go to the toilet, and even before reaching it you might have already figured it out yourself.</p>
<p>So what&rsquo;s wrong with creating temporary ducks to talk to? Nothing, except that those ducks might be working on something themselves and need to drop that work in order to help you. So what&rsquo;s wrong with that? Maybe nothing. Maybe a lot, as once you notice how <strong>easy</strong> it becomes to talk to someone else about your problem, you&rsquo;ll definitely think of doing it again the moment you stumble upon another problem. Maybe you&rsquo;ll turn to a colleague just a bit faster. And faster. Wait, did you think this problem through before asking? No you didn&rsquo;t!</p>
<p>This creates an &ldquo;ask-a-lot&rdquo;-loop that locks down others that also want to work. Look at it the same way as an overload of meetings, except they&rsquo;re immediate and unplanned. Remember that context switching requires a mental overhead of at least 20 minutes. Uninterrupted concentration? Deep Work? Forget that.</p>
<p>Quack quack.</p>
<p>The other side of the coin: too much separation. A mental lockdown is good but doesn&rsquo;t get any enterprise software out of the door. Some researches or professors might have the luxury of a private office space, but writing papers is mostly a lonely task. Imagine multiple software development teams &ldquo;collaborating&rdquo; if everyone is tucked away in their own little space (or worse, cubicle). The urge to stand up and ask something completely diminishes: &ldquo;I&rsquo;ll try to fix this myself&rdquo;. The result is a mismatch and unstable codebase where everyone knows a little bit about something but the coherent whole is absent.</p>
<p>At least you&rsquo;ll get to squeeze in those wanted Deep Work hours!</p>
<p>A possible solution might be a shared workspace with remote cells where you can concentrate on hard stuff, but you&rsquo;re not too far away from the rest of the chaotic action. Alas that solution doesn&rsquo;t work well if not everyone respects your intentions to do some Deep Work: you&rsquo;re still reachable to quack. Company policies should clear things up but we all know that doesn&rsquo;t work well either. We have a &ldquo;<strong>silent room</strong>&rdquo; at work, but it&rsquo;s mostly used as a meeting room thanks to the lack of other available rooms. What&rsquo;s more, the &ldquo;silent&rdquo; room isn&rsquo;t silent at all: it&rsquo;s located near the central printer and the air conditioning pipes, causing a constant humming that without a doubt creates a nice headache even without that Deep stuff.</p>
<p>Balancing collaboration and concentration requires:</p>
<ol>
<li>Respect from others</li>
<li>Shared insight on when to utilize both.</li>
</ol>
<p>As long as there&rsquo;s someone in your company who doesn&rsquo;t think of Deep Work as something relevant, you won&rsquo;t be able to create that shared understanding.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 25 March 2018.
</p>
]]>
</description>
</item>
<item>
<title>Hiding Code Complexity</title>
<link>https://brainbaking.com/post/2018/02/hiding-complexity/</link>
<comments>https://brainbaking.com/post/2018/02/hiding-complexity/#commento</comments>
<pubDate>Mon, 26 Feb 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/02/hiding-complexity/</guid>
<category domain="https://brainbaking.com/tags/domain driven design">domain driven design</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/complexity.png"/>
</p>
<p>We like to talk about the architecture of our software because we like complexity. Software developers are the bears, and complex patterns seem to be the honey. The more I pair with people the more I wonder: &ldquo;what makes us decide to take on a simple question with a difficult answer&rdquo;? Why would anyone choose to implement something so complex, that it cannot be easily understood even the day after it&rsquo;s committed?</p>
<h4 id="answer-1-because-the-underlying-model-is-complex">Answer 1: because the underlying model is complex</h4>
<p><strong>Legacy</strong> systems. They always take the blame. But by introducing more complexity to work with, on the surface, we create even more legacy. The inner workings should never, ever, be exposed. I don&rsquo;t care about status 40 or 70 or 10 simply because it&rsquo;s persisted like that and you can&rsquo;t change it. That doesn&rsquo;t mean you should simply return that status and check the flags: instead we could try to <strong>hide that complex matter</strong> and encapsulate it in <strong>simple methods</strong>. That sounds simple. And it is. And yet, it almost never pops into people&rsquo;s minds.</p>
<p>Let&rsquo;s say that I&rsquo;ve written a system that, based on certain statuses, should execute an action. For instance, I can only delete something in my shopping cart if the status is 40, 53 or 70.</p>
<pre><code> if(shoppingCart.status == 40 || shoppingCart.status == 53 || shoppingCart.status == 70) {
delete();
}
</code></pre>
<p>Extract method to the rescue:</p>
<pre><code> if(isPossibleToDelete(shoppingCart)) {
delete();
}
private bool isPossibleToDelete(shoppingCart) {
return shoppingCart.status == 40 || shoppingCart.status == 53 || shoppingCart.status == 70
}
</code></pre>
<p>But what do those numbers even mean?</p>
<pre><code> private bool isPossibleToDelete(shoppingCart) {
return shoppingCart.status == CartStatus.NEW_CART || shoppingCart.status == CartStatus.BLOCKED || shoppingCart.status == CartStatus.MERGED
}
</code></pre>
<p>Ban those numbers to an enum and give them a <strong>meaningful name</strong>.<br/>
We&rsquo;re not done yet:</p>
<pre><code> if(shoppingCart.isPossibleToDelete()) {
delete();
}
</code></pre>
<p>It&rsquo;s a subtle difference, but the cart knows about it&rsquo;s status and that means you can hide that complexity behind the ShoppingCart class implementation. Most developers will know enough if they read &ldquo;isPossibleToDelete&rdquo; and those who need to know the details can dive deep. See how simple that was? <strong>Hidden within a method</strong>, no other tricks used. Even if the underlying model still uses the ugly status checks, the rest of your software should never check on 40, 53 or 70 again. Ban those numbers to the enum and don&rsquo;t even use the enum values at your leisure.</p>
<p>If possible, go as far as making the status property private.</p>
<p>Another example. What if your legacy database structure doesn&rsquo;t allow an easy-to-read persistent layer but forces you to write in four different tables to get something done? The answer is the same as above: encapsulate everything. Don&rsquo;t simply implement (or generate, for that matter) CRUD operations based on your tables. Don&rsquo;t let your tables (or boss) rule your codebase!</p>
<pre><code> public void Save(RosterClientLink link) {
Persist(link);
var client = GetClientById(link.client.Id);
var roster = getRosterById(link.roster.Id);
client.Rosters.Add(roster);
Update(client);
}
</code></pre>
<p>Having such a method gives away that you&rsquo;re leaning on a CRUD operation too much. The link class doesn&rsquo;t say anything and it&rsquo;s not even clear that it modifies client data unless you take a look. A second attempt:</p>
<pre><code> public void attachWorkRosterToClient(Client client, Roster roster) {
Persist(new RosterClientLink(client.Id, roster.Id));
Persist(roster);
client.Rosters.Add(roster);
Update(client);
}
</code></pre>
<p>Simply having this method is better than nothing - it makes the intention to attach the roster to a client visible. Instead of requiring every developer to know the inner workings of those tables, they can simply &ldquo;attach&rdquo;. Your business should also be speaking about &ldquo;attaching&rdquo; then. But again, we&rsquo;re not done yet:</p>
<pre><code> public void attach(Roster roster) {
Persist(new RosterClientLink(this.Id, roster.Id));
Persist(roster);
this.Rosters.Add(roster);
Update(this);
}
</code></pre>
<p>That makes <code>client.attach(roster);</code> possible, and that&rsquo;s easier to read and ultimately, understand. One could argue that <code>roster.attachTo(client)</code> makes more sense but think about <strong>responsibilities</strong> here: who owns what? Why would the roster be able to attach itself to a client, while a client owns and creates the rosters?</p>
<h4 id="answer-2-because-we-want-to-prove-ourselves">Answer 2: because we want to prove ourselves</h4>
<p>You might think you look cool if you can handle a pattern in a pattern. You might be proud of yourself once you managed to generalize one callback that will never be re-used. Hoping others would be proud of you to. If those others can&rsquo;t make much of your code, I would dare to say that it won&rsquo;t be the case.</p>
<p>Using a factory because you&rsquo;re convinced that creating <em>anything</em> has to be done by a factory might not be the best move to make. Using dependency injection because it&rsquo;s <em>best practice</em> doesn&rsquo;t make much sense to me either and that&rsquo;s a trap that almost everyone falls in. What&rsquo;s wrong with this:</p>
<pre><code> public class Stuff {
private readonly IDep _One;
private readonly IDep two;
public Stuff(IDep one, IDep two) {
_One = one;
_Two = two;
}
public Stuff() : this(new One(), new Two()) {
}
}
</code></pre>
<p>The first constructor is used in unit testing and allows us to <em>inject</em> (aha!) mocks into the loaded instance, while the second constructor is used in production. This approach has some drawbacks, like any other approach - like the cascading effect of object creation. But that might be enough for your application.</p>
<p><a href="https://en.wikipedia.org/wiki/KISS_principle">Keep it simple, stupid</a>.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 26 February 2018.
</p>
]]>
</description>
</item>
<item>
<title>Take your time.</title>
<link>https://brainbaking.com/post/take-your-time/</link>
<comments>https://brainbaking.com/post/take-your-time/#commento</comments>
<pubDate>Fri, 16 Feb 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/take-your-time/</guid>
<category domain="https://brainbaking.com/tags/journaling">journaling</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/takeyourtime.jpg"/>
</p>
<p>&ldquo;Let&rsquo;s try to keep silent for a minute and enjoy the complete absence of traffic noise!&rdquo; I yelled to my friends. We were standing on a sandy hill in the middle of national park &ldquo;Hoge Veluwe&rdquo;. One of our friends, a biologist, enticed us to help him identify animal tracks in the sand. I don&rsquo;t know anything about even-toed ungulates, but I know a bit about the joy of discovery. <br/>
&ldquo;Great idea!&rdquo;. I closed my eyes and smelled the very beginning of spring. <br/>
A few seconds passed.<br/>
A few more.<br/>
&ldquo;Woah there I can&rsquo;t shut up for more than ten seconds!&rdquo; muttered a few. After a lot of laughs, everyone forgot about the pathetic attempt to create some silence and carried on with snapping pictures and posting them on-line.</p>
<p>Maybe a big sign upon entering the park that states &ldquo;cellphones forbidden&rdquo; would help. Or carrying decibel meters or something like that. But people seem to be preoccupied with whatever they are doing every single day, without one single break, not even on a short vacation. I sometimes feel the sparks of flow and wonder, but they never stay long enough for me to fully enjoy until I look back. I wonder if others feel it too. I doubt my friends were doing that - especially after discussing the ugly car we drove by half an hour ago.</p>
<p>When I drove home from work today, I took the liberty to dismount my bike and walk through a forest I pass every day. The difference between cycling through and walking through is huge, and then I wondered: what if instead of walking, which seems to be an improvement, I simply stop, and stare? The low winter sun and the clear sky combined with light green grassy hills soaked into my mind. I start to notice details. The contrast between the shades of leafless dead trees and the setting sun. The puffy seed pods of the weeds. Things I would not notice while walking, let alone biking.
And yet by biking to and from work, I&rsquo;m an exception: most people drive. The higher the velocity, the more my mind wanders. I&rsquo;m convinced this doesn&rsquo;t only happen to me - mindfulness proves that.</p>
<p><figure>
<a href="/img/pigs-in-the-woods.jpg" class="lbox">
<img loading="lazy" src="/img/pigs-in-the-woods.jpg" alt="pigs in the woods" >
</a>
</figure>
Warthog spotting in the woods&hellip;</p>
<p>It boggles my mind that a small adventurous feeling group of young (I&rsquo;m obligated to write that) men can&rsquo;t even shut up for more than 10 seconds to simply listen to nature instead of to man-made sounds. I can&rsquo;t claim to be an expert on being in the moment, but at moments like this, in the very middle of nature, it might be easier for everyone than at home where every single object yells &ldquo;distraction!&rdquo;.
Pets can help here too. Since our cat Muesli likes to stare out the window, I sometimes join him doing the same for a few minutes. It&rsquo;s actually very difficult, to simply do that: stare. See. Look. Leaves. Wind. Nothing more. My brain automatically goes into overdrive mode claiming I have to be productive so it comes up with a list of stuff to think about. Letting those things go requires a bit of practice. And I mostly fail at that, but I enjoy the process. Just like <a href="/post/i-am-jealous-of-my-dog/">I&rsquo;m jealous of my dog</a>, I&rsquo;m also jealous of my cat.</p>
<p>The more I experience those moments, the more I&rsquo;m starting to like it. There are a lot of reasons for us to try and slow down a bit more:</p>
<ul>
<li>It makes me be more content of &ldquo;things&rdquo; (figure of speech) I have</li>
<li>It makes me want less useless &ldquo;stuff&rdquo; (literally)</li>
<li>It makes me feel humble. A part of a bigger whole. Just like our dog and cat. We humans tend to think we rule this universe when in fact, we let our immediate needs rule us.</li>
</ul>
<p>Creating the habit of taking your time doesn&rsquo;t come easy. In the beginning, I didn&rsquo;t even believe in why I should be doing that. But then I started to train my &ldquo;understanding-mindfulness muscle&rdquo; as I like to call it, unconsciously. That happened by reading books about philosophy, scrolling through analog versions of the Dutch &ldquo;Flow&rdquo; book and digital versions of things like <a href="https://www.theminimalists.com/">The Minimalists</a>, and foremost by writing down my thoughts in <a href="/posts/journaling-in-practice">my journal</a>.
I&rsquo;m adding the word &ldquo;unconsciously&rdquo; because I&rsquo;m not a good practicer and at moments, I still don&rsquo;t &ldquo;get&rdquo; it. But the more I read about the subject (or something that is vaguely related), the more I become susceptible to it. That&rsquo;s not so surprising, but it&rsquo;s a powerful tool to submerge yourself a bit deeper.</p>
<p>So let&rsquo;s try to grow a rush-break we can pull on at any time to stop thought-spinning and start true-watching.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 16 February 2018.
</p>
]]>
</description>
</item>
<item>
<title>2017 in books</title>
<link>https://brainbaking.com/post/2018/01/2017-in-books/</link>
<comments>https://brainbaking.com/post/2018/01/2017-in-books/#commento</comments>
<pubDate>Sat, 27 Jan 2018 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/01/2017-in-books/</guid>
<category domain="https://brainbaking.com/tags/journaling">journaling</category>
<category domain="https://brainbaking.com/tags/reading">reading</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/2017inbooks.png"/>
</p>
<p>Goodreads presented me with a neat overview on my read books in 2017 you can also <a href="https://www.goodreads.com/user/year_in_books/2017/5451893">take a look at</a>. The dull page statistics are of no interest to me, but the kind of books I&rsquo;ve read do tell a story that might be worth sharing.</p>
<p>When it comes to keeping track of what I read, Goodreads might be the best thing that happened to me yet. But I can&rsquo;t say that I&rsquo;m a consequent user of my own listage. I love browsing through books in libraries and bookshops, and that might mean a book or two gets added to my &ldquo;toread&rdquo; list. It might take up to two years before I actually start reading it. I am what you might call a &ldquo;chain reaction reader&rdquo;: someone who starts reading something, finds something related interesting to that and continues ot read on the same subject. At least that is what Goodreads tries to tell me.
2017 has sharpened my knowledge (as far as reading a book goes) on these rough categories: art, food, programming, philosophy. Oh yes, and I finally managed to finish Robin Hobb&rsquo;s Assassin&rsquo;s Fate. The meager 3 books I&rsquo;ve read on programming (they were all bad) and food (they were even worse) are not worth mentioning here, which reminds now me to focus more on those subjects in 2018.</p>
<h3 id="art">Art</h3>
<ul>
<li><a href="https://www.goodreads.com/book/show/22553690-art-before-breakfast">Art before breakfast, Danny Gregory</a></li>
<li><a href="https://www.goodreads.com/book/show/13450136-handboek-voor-de-kunstenaar">Handboek voor de kunstenaar, R. C. Smith</a></li>
<li><a href="https://www.goodreads.com/book/show/40168.The_Creative_License">The creative license, Danny Gregory</a></li>
<li><a href="https://www.goodreads.com/book/show/17899481-art-as-therapy">Art as therapy, Alain de Botton</a></li>
<li><a href="https://www.goodreads.com/book/show/627206.The_New_Drawing_on_the_Right_Side_of_the_Brain">Drawing at the right side of the brain, Betty Edwards</a></li>
<li><a href="https://www.goodreads.com/book/show/12635188-the-art-of-urban-sketching">The art of urban sketching, Gabriel Campanario</a></li>
<li><a href="https://www.goodreads.com/book/show/395233.The_Letters_of_Vincent_van_Gogh">The letters of Vincent van Gogh</a></li>
<li><a href="https://www.goodreads.com/book/show/7849839-your-artist-s-brain">Your artist&rsquo;s brain, Carl Purcell</a></li>
</ul>
<p>We discovered <a href="http://sketchbookskool.com/">Sketchbookskool</a> in 2017, so the presence of Danny&rsquo;s books are nothing unusual here. I love his style, from the images he draws to the narrative in his stories. Even the videos and his way to instruct you, as the beginner, to draw, is very compelling. I&rsquo;ve read &ldquo;Art before breakfast&rdquo; before &ldquo;The creative license&rdquo; and discovered afterwards that he recycles a lot of stuff - which is perfectly OK. If there is one &ldquo;Danny&rdquo; book I&rsquo;d enlist as my favorite, it would be the license.</p>
<p>But this list contains so many great books. Vincent&rsquo;s letters where very insightful but dragged on for too long. Urban sketching is an amazing reference guide but the other two winners are Betty Edwards and Alain de Botton. Betty convinced me even I could draw (also read <a href="/post/teaching-yourself-to-draw/">Teaching yourself to draw</a>) and Alain took me back to museums with a new pair of eyes.</p>
<h4 id="the-verdict">The verdict</h4>
<ol>
<li>Drawing at the right side of the brain</li>
<li>Art as therapy</li>
<li>The Creative License</li>
</ol>
<h3 id="philosophy">Philosophy</h3>
<ul>
<li><a href="https://www.goodreads.com/book/show/33403207-waar-geen-wil-is-is-een-weg">Waar geen wil is, is een weg, Henk Oosterling</a></li>
<li><a href="https://www.goodreads.com/book/show/867247.A_Book_of_Five_Rings">A book of five rings, Miyamoto Musashi</a></li>
<li><a href="https://www.goodreads.com/book/show/13086701-over-de-natuur-en-het-geluk">About nature and happiness, Epicurus</a></li>
<li><a href="https://www.goodreads.com/book/show/22605205-over-vrijheid">About freedom, Epictetus</a></li>
<li><a href="https://www.goodreads.com/book/show/13380059-the-wonderbox">The Wonderbox, Roman Krznaric</a></li>
<li><a href="https://www.goodreads.com/book/show/23419.The_Consolations_of_Philosophy">The consolations of philosophy, Alain de Botton</a></li>
<li><a href="https://www.goodreads.com/book/show/402843.Zen_Mind_Beginner_s_Mind">Zen mind, beginner&rsquo;s mind, Shunryu Suzuki</a></li>
<li><a href="https://www.goodreads.com/book/show/38210.The_Art_of_Happiness">The art of happiness, Dalai Lama XIV</a></li>
<li><a href="https://www.goodreads.com/book/show/163365.What_Should_I_Do_with_My_Life_">What should I do with my life? Po Bronson</a></li>
<li><a href="https://www.goodreads.com/book/show/6584140-29-gifts">29 Gifts, Cami Walker</a></li>
<li><a href="https://www.goodreads.com/book/show/10293969-cabin-fever">Cabin Fever, Tom M. Fate</a></li>
</ul>
<p>It&rsquo;s a mixed bag. Categorizing &ldquo;lifestyle philosophy&rdquo; (Po Bronson, Cami Walker) under the same denominator as classic philosophy works might be a stretch. The presence of bad reading material here frustrated me a bit as I&rsquo;m relatively new to the subject and it&rsquo;s difficult to get myself started which makes a letdown all the more painful. Oosterling, Walker and even the Dalai Lama are all losers here - maybe simply because I expected something else.</p>
<p>Musashi, Epicurus and Suzuki take on a leading position together with my new friend Alain de Botton. This guy is amazing and brings digestive material into my living room that makes me craving for more. Roman&rsquo;s Wonderbox is another excellent book that is tied to his and de Botton&rsquo;s <a href="https://www.theschooloflife.com/">School of Life</a>, devoted to developing emotional intelligence. Both books of the school teachers bundle works of classic philosophers, which at this point is more digestible for me than the work of the guys themselves. That is why I&rsquo;d rate them higher than Epicurus or Epictetus.</p>
<h4 id="the-verdict-1">The verdict</h4>
<ol>
<li>The Wonderbox</li>
<li>The consolations of philosophy</li>
<li>Zen mind, beginner&rsquo;s mind</li>
</ol>
<p>The Book of five rings gets an honorable mention but I can&rsquo;t ignore Suzuki&rsquo;s simplified explanation of Zen Buddhism that finally makes sense. It clears the clutter of all the mysticism and simply instructs to be here and know.</p>
<h3 id="toread-in-2018">Toread in 2018?</h3>
<p>Will this change my reading habit in 2018? I think it might. I&rsquo;m longing for more excellent cooking material to replace the letdowns in the past year, so I hope to sneak in at least 5 books on that subject. Otherwise, art and philosophy are still exciting and new for me so more of the same is definitely welcome. They are main recurring themes in my (reading) life, even when <a href="https://www.goodreads.com/user/year_in_books/2016/5451893">going back to 2016</a>.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 27 January 2018.
</p>
]]>
</description>
</item>
<item>
<title>Inventing - for the worse?</title>
<link>https://brainbaking.com/post/2017/12/inventing-for-the-worse/</link>
<comments>https://brainbaking.com/post/2017/12/inventing-for-the-worse/#commento</comments>
<pubDate>Sat, 30 Dec 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/12/inventing-for-the-worse/</guid>
<category domain="https://brainbaking.com/tags/craftsmanship">craftsmanship</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/craftheader.png"/>
</p>
<p>People have an irresistible urge to create. But we often mistake productivity with creativity with <strong>really</strong> creating. Homo creativus. But is this always a good thing? The best inventions in the world bring great sorrow to millions of people today. Then I started wondering, what if&hellip;</p>
<p>Electricity wasn&rsquo;t invented? Mass production wouldn&rsquo;t be possible. Everything you use, from your watch to your laptop, stove, to what you&rsquo;re wearing wouldn&rsquo;t be possible. Big grocery stores wouldn&rsquo;t exist. Small specialized shops and professions would reign over the endless army of paper pushers we know today. Wouldn&rsquo;t that be a great thing? Looking past the obvious famine problems and the lack of lights without matches, I would be pretty stoked about:</p>
<ul>
<li>The local tailor everybody knows. Your clothes fit and are exactly what you want. But it&rsquo;s very expensive and you can only afford three or four outfits. Another advantage?</li>
<li>The complete lack of anything &ldquo;made in China&rdquo; or &ldquo;plastic&rdquo;. That would include 3D printers and throwaway garbage.</li>
<li>Writing a book with ink.</li>
<li>Being a <strong>craftsman</strong> by using my hands without asking myself if I should job-hop to the next challenge.</li>
</ul>
<p>So many things nowadays are simply that: &ldquo;things&rdquo;. You use them, and if you&rsquo;re bored throw them away. The more I talk to people about anything, the more I&rsquo;m afraid the throwaway thing is becoming a philosophy: throw your job away if you&rsquo;re bored, throw your wife away if you&rsquo;re bored. It&rsquo;s already becoming a &ldquo;thing&rdquo; - pun intended. <a href="https://storyofstuff.org/">The story of stuff</a> does a better job at explaining this.
Stuff undoubtedly creates tension and makes people rethink what they&rsquo;re doing. That might not be bad at all, but we often jump to the wrong conclusions based on what we see or think to see on the other side.</p>
<p>We used to have less stuff and to care a lot more about the little things that we had. Most stuff was expensive so naturally you would take care of it and make sure it lasted a long time, or when it&rsquo;s broken make sure it&rsquo;s fixed instead of simply replacing it by something else. In that era, we weren&rsquo;t yet that disconnected with our possessions and these things were all made by expert craftsman.</p>
<h3 id="craftsman">Craftsman</h3>
<p>The word &ldquo;profession&rdquo; is barely used anymore. According to the dictionary, a profession is:</p>
<blockquote>
<p>a paid occupation, especially one that involves prolonged training and a formal qualification.</p>
</blockquote>
<p>Prolonged training isn&rsquo;t a matter of days or weeks but years. Most people don&rsquo;t work that long for the same employer anymore. True mastery seems to fade away. Highly specialized jobs still exist but are becoming the exception instead of the rule thanks to automatisation and globalization.</p>
<p>Another one, &ldquo;craftsmanship&rdquo;:</p>
<blockquote>
<p>the quality of design and work shown in something made by hand; artistry.</p>
</blockquote>
<p>or</p>
<blockquote>
<p>The skill in a particular craft</p>
</blockquote>
<p>where craft means</p>
<blockquote>
<p>an activity involving skill in making things by hand.</p>
</blockquote>
<p>The <strong>made by hand</strong> part is crucial here. The recent resurgence of &ldquo;things made by hand&rdquo; might prove the urge we humans have to create beautiful things by hand instead of letting machines do the job for us. Think Etsy and Pinterest for example. Human satisfaction is stripped away when an automated mold prints hundred of things within minutes, as is our meticulous care for those products: they now get tossed in the bin if we don&rsquo;t like them anymore.</p>
<p>The fancy word &ldquo;craftsmanship&rdquo; is sadly often abused thinking it might net you a nice job with a high wage if you spray it around your CV.</p>
<p><figure>
<a href="/img/craftsman.jpg" class="lbox">
<img loading="lazy" src="/img/craftsman.jpg" alt="craftsman at work in the Middle Ages" >
</a>
</figure>
Craftsman at work in the <a href="http://www.thomasmorecollege.edu/student-life/catholic-guilds/">Middle Ages</a></p>
<p>Creating something physical has been replaced by something digital: bolts and pieces by lines of code. You&rsquo;re still creating, but that feeling of the material disappeared. Apprenticeship also changed: instead of working and living for years at the bidding of your master, you now hopefully pick up some tips and tricks from a colleague before moving on to the next job. It&rsquo;s become much more implicit and that is definitely for the worse. Googling &ldquo;the lost art of mentoring&rdquo; nets me an astonishing amount of recent articles on cool websites like &ldquo;refresh leadership&rdquo;.</p>
<p>People feel disconnected with their work because of this. Band work is not suited for anyone (I highly doubt it&rsquo;s for anyone at all!), despite what someone might try to tell you. I bet a lot of those workers compensate the lack of creating by hobbies like cooking or painting. Every single being has this urge. Some might simply have given up.</p>
<p>However, not all is lost: we are starting to recognize the need for artisan professions instead of paperwork jobs. The <a href="http://manifesto.softwarecraftsmanship.org/">Manifesto of Software Craftsmanship</a> says it &ldquo;raises the bar&rdquo; by applying the following:</p>
<blockquote>
<p>Not only working software,<br/>
but also <strong>well-crafted</strong> software<br/><br/>
Not only responding to change,<br/>
but also steadily <strong>adding value</strong><br/><br/>
Not only individuals and interactions,<br/>
but also a <strong>community of professionals</strong><br/><br/>
Not only customer collaboration,<br/>
but also <strong>productive partnerships</strong></p>
</blockquote>
<p>I&rsquo;ve been in the software industry for more than 10 years and like I said before, sadly enough I have the feeling that most IT professionals calling themselves craftsman have no idea what implications of the words in the manifesto actually mean. It&rsquo;s frequently used as a commercial selling point rather than a way to elevate your own skills. But that is a whole other problem, the same thing is happening with flashy words like &ldquo;scrum&rdquo; and &ldquo;agile&rdquo;, becoming more and more meaningless.</p>
<h3 id="freedom">Freedom?</h3>
<p>Yes, we have more freedom to do what we want thanks to the rise of working a fixed amount of hours each week. But this seemingly abundance of extra free time also spawned hundreds of books about answering the question what to do with that time. It looks like we forgot to be satisfied with what we have. We are trying to solve problems that aren&rsquo;t there if only we were contented. The absence of a deity and the impulse to profess every natural occurrence nowadays only fuels this dissatisfaction.</p>
<p>Alain de Botton described this phenomena in his book &ldquo;Status Anxiety&rdquo;. Our free time gets gobbled up by trying to meet the implicit requirements of belonging to a group by comparing ourselves to how others are doing. Instead of giving in to our need to create, we go out and buy things to let others know we&rsquo;re doing at least as well as them. This makes you even more unhappy on the long run, but you won&rsquo;t notice it right away because climbing up a ladder where everyone can see you feels great.</p>
<p>I think it&rsquo;s time we look at the past and learn from habits of our ancestors. The key to unlocking your creative self - and your happiness - is not giving up on what you&rsquo;re doing now because others say so but giving in to that urge of creating and to stop comparing our actions.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 30 December 2017.
</p>
]]>
</description>
</item>
<item>
<title>I&#39;m jealous of my dog</title>
<link>https://brainbaking.com/post/2017/08/i-am-jealous-of-my-dog/</link>
<comments>https://brainbaking.com/post/2017/08/i-am-jealous-of-my-dog/#commento</comments>
<pubDate>Thu, 17 Aug 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/08/i-am-jealous-of-my-dog/</guid>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/woef.jpg"/>
</p>
<p>My dog, Miel (yes, like the French word for honey. It&rsquo;s a Golden Retriever, get the link?), loves to walk. He also likes playing a lot, but as soon as I put on my shoes or get near the garden gate, he starts to freak out, thinking it&rsquo;s that time again. Since I have no idea what is going on in is head, I said &ldquo;thinking&rdquo;, because we humans associate animals with our own behavior - because that&rsquo;s what we&rsquo;re familiar with. Have you ever walked a dog? Have you noticed the dog&rsquo;s &ldquo;state of mind&rdquo;? How would you notice such a thing? Pay attention to what your dog is doing and you&rsquo;ll know what I mean.</p>
<p>Miel is not thinking. He&rsquo;s walking. Sniffing. He&rsquo;s present in that very moment. <br/>
On the other hand, I&rsquo;m pondering something that happened to me today. I might be distracted. After a few blocks, I might think &ldquo;oh wow, now where was I&rdquo;. I might have missed the waving neighbor, the sunny weather or the absence of noisy cars. I am not present in that very moment at all - I&rsquo;m either in the past (&ldquo;why did that person say this to me&rdquo;) or in the future (&ldquo;I need to do this and that and that after I get back&rdquo;). Why is it so hard to be in the present, if Miel can do this so easily?</p>
<p><figure>
<a href="/img/mindfull.jpg" class="lbox">
<img loading="lazy" src="/img/mindfull.jpg" alt="Mind full-ness" >
</a>
</figure>
Image copyright socksofdoom</p>
<p>It seems that I&rsquo;m <a href="https://trudymorgancole.wordpress.com/2014/03/02/dogs-walks-and-mindfulness/">not the only one with that problem</a>. After taking an eight week long mindfulness course, it seems that I&rsquo;m still practicing mind-<strong>full</strong>ness instead of mindfulness. We humans are blessed and cursed with a thinking brain but luckily Buddhists have proven that it can be temporary shut down. There&rsquo;s only one way to achieve this state of mind: practice. I love reading about this subject and recently finished the extremely popular &ldquo;<a href="https://www.goodreads.com/book/show/402843.Zen_Mind_Beginner_s_Mind">zen mind, beginners mind</a>&rdquo; by Shunryu Suzuki. It&rsquo;s a very practical book that explains the basics of Zen-Buddhism. One major recurring subject is practicing versus studying the philosophy behind Zen. The more you read and know things about Zen, the more poisoned your mind is. So start doing and stop reading.</p>
<p>Miel isn&rsquo;t the only &ldquo;person&rdquo; (whoops) that loves his daily walk. Ever since we got the dog, I too started to enjoy breaking out of my comfortable living room, doing the usual nothing. Dog walking gives me an excuse to get up and walk, and to try to be in the moment, to try to notice the weather, to smell the air, to feel the raindrops and to simply walk. Failing implies getting up and doing it again. When I catch myself thinking about something or worrying, I friendly but firmly redirect myself to the present: walking. Most of the times, Miel does this for me with a pull of the leach. In that sense, it could be a bit like meditating. That&rsquo;s one of the reasons I like drawing so much: I can&rsquo;t do anything else but to study the subject, and start laying done line per line. Study it more closely, start seeing details within details as Tommy Kane would say. I usually need a few minutes to get myself into that (drawing-) mode and that&rsquo;s one of the reasons I am having difficulties drawing in urban regions where a lot of people distract me.</p>
<p>In one of the lessons in the mindfulness course, we had to do a walking meditation. That implied focusing on the contact of the earth and your foot, feeling where you land each foot and concentrating on walking alone. I like to do this when I&rsquo;m biking. You start to notice how your knee joints work, and where that heavy pushing on the petals is going when you cross a steep bridge. This sounds like it&rsquo;s easy but it&rsquo;s not: I&rsquo;d say those moments are rare for me. I usually catch myself thinking stuff about my work when I&rsquo;m biking to and from work a few minutes after attempting to concentrate on biking alone. But that&rsquo;s alright: I&rsquo;m learning from my dog.</p>
<p>I&rsquo;m grateful for my dog reminding me I need to &ldquo;take a walk&rdquo;, to &ldquo;clear my head&rdquo;. So why don&rsquo;t you clear your head when you&rsquo;re walking but fill it even more?</p>
<ul>
<li>Does it make you feel better?</li>
<li>Are the problems resolved when pondering them at that time?</li>
<li>Can&rsquo;t you focus on your dog instead of your &ldquo;stuff&rdquo;? He&rsquo;d appreciate it.</li>
</ul>
<p><figure>
<a href="/img/multitaskingsucks.jpg" class="lbox">
<img loading="lazy" src="/img/multitaskingsucks.jpg" alt="Multi tasking sucks" >
</a>
</figure>
Image copyright <a href="https://www.privatebarking.com/puplifting-quotes-multitasking-sucks/">privatebarking</a></p>
<p>The thinking most certainly still needs to be done but you&rsquo;ll make it yourself a lot easier if you think when you need to think and walk when you need to walk. It&rsquo;s called <strong>single tasking</strong> and we should all do it more often. The myth of multitasking that gets more work done is a very short sighted view on economical capitalism. Context switching costs precious time - even up to 20 minutes to get back into what you were doing. That is one of the main reasons you should not check your mail every hour but once in the morning and once in the evening. I&rsquo;m starting to resent people who cling to their iPhones, instead of focus sing on the person in front of them. It&rsquo;s all part of the same problem.</p>
<p>If you&rsquo;re having trouble, remember this: if your dog is playing, it&rsquo;s playing, not playing and managing his backlog. If your dog is eating, it&rsquo;s eating, not playing with his ball next to his supper. So keep that cellphone off the dinner table and try to mimic his behavior. <br/>
I know this sounds easy, but it takes a lifetime to fully master. I still wake up most days with too much scrambled thoughts about what happened yesterday and what will happen today, having difficulties letting go of them. It&rsquo;s so easy to <strong>get lost within your own thoughts</strong> and it does have it&rsquo;s purpose to do a &ldquo;thought walk&rdquo; and mix and mash ideas to get to another one. But it&rsquo;s also vital that you have a working STOP button.</p>
<p>I have to stop typing and think about that for a moment now.</p>
<p>What was I saying?</p>
<p>The common problem of noise in your head has not been solved just yet. In fact, it has only gotten worse. A lot worse. The garbage thinking problem spread like a disease, clinging onto everything in it&rsquo;s way inside me. It has reached my ears and my mind. I&rsquo;d like to make a distinction between &ldquo;head&rdquo; and &ldquo;mind&rdquo; as &ldquo;head&rdquo; might be a temporary problem, getting something to stick in your &ldquo;mind&rdquo; sounds a lot more definitive to me. Allow me to elaborate.</p>
<h3 id="pollution-in-my-ears">Pollution in my ears</h3>
<p>Are you also fed up with this noise generating world? The louder the better. You&rsquo;re only cool if you are able to stand the music beating your ears in your plugs at level 15 or higher. It&rsquo;s awesome to drill a hole in an exhaust pipe so your motor doesn&rsquo;t get unheard. Yelling usually provides you with the direct attention you need, whether at the checkout or in a meeting.
Does this sound familiar to you? I&rsquo;m not even talking about people who are highly sensitive or introverts vs extroverts, but in general. Just, in general, at every single level. Getting to work makes my body take more decibels than it used to thanks to the increased traffic full of ignorant people who like to listen to the (loud) radio and have the comfort of a leather chair instead of a bike. The absurd concept of open work spaces makes my day at work barely productive. A beginning headache by 3h PM is normal. Shopping for groceries in a mall or supermarket doesn&rsquo;t make my day any better as the non stop stream of commercials rolls out of speakers and mounted televisions. The end of an exhausting day marks watching television because my wife thinks that&rsquo;s the best way to relax. Don&rsquo;t forget to crank up that volume, otherwise you won&rsquo;t be able to follow that quiz.</p>
<p>At last, in bed. I greet the ever present buzz inside my mind and sigh.</p>
<p>Something has to be done. And so I did:</p>
<ol>
<li>When I&rsquo;m driving, the radio is <strong>always</strong> off. I love that bubble of silence.</li>
<li>Take your foot off the clutch if you have an engine that stops automatically at a red light. Ahhhh.</li>
<li>Get rid of everything that ticks and whirrs in your living room.</li>
<li>Bike around traffic even if that means a couple of minutes extra commute.</li>
<li>Try to use headphones that block out noise of others at work.</li>
<li>Turn off the TV.</li>
<li>Turn the TV back on after your wife gets angry.</li>
<li>Read somewhere else where there&rsquo;s no TV on.</li>
<li>Go back to the room with the TV because your wife is lonely.</li>
</ol>
<p>The above has only seen partial success. Traffic is everywhere, you can&rsquo;t bike around it that easily. Thanks to the nature of my job, as a software engineer working inside teams, I&rsquo;m constantly disturbed - headphones or not. However, we introduced a &ldquo;silent period&rdquo; of 1.5hrs twice a week in an attempt to reduce the general noise overhead. That does mean we need the cooperation of our colleagues&hellip;</p>
<h3 id="pollution-in-my-mind">Pollution in my mind</h3>
<p>Getting obsessed with something can prove to be dangerous too. Let&rsquo;s call it &ldquo;unhealthy&rdquo;. When I get excited about something, like fountain pens or more recently my reintroduction into Magic: the Gathering, I can get a bit too obsessed with it. Searching for the perfect pen, watching videos, looking around for the better shop, reading about what others think and say. Looking at what cards are played at tournaments, thinking about strategies, trying out different combinations inside my head. That sounds innocent, but can cause me to put all other things to hold. Suddenly, I lose interest in other things I was a lot more interested in, in the first place. Biking from and to work happens pseudo-automatically, pondering the right combination of killer combo cards to put into my deck. Oh, did I pass this street already? How time flies.</p>
<p>My mind saves all ongoing progress of different stuff and loads up one single program: Magic.</p>
<p>That&rsquo;ll mean I&rsquo;ll probably dream about it and talk about it until everyone thinks I&rsquo;m obsessed (at that point, I might very much well be).
Until something else comes along, Magic probably will get stored as ongoing progress and something else (completely) occupies my mind.</p>
<p>Sounds like mind-full-ness or mind-fool-ness to me. Every time I catch myself thinking &ldquo;I should meditate more and try to clear my head&rdquo;, I end up surfing to some Magic-related website again. The cards or the game aren&rsquo;t the problem, but my occupation with those temporary things is. And I&rsquo;m convinced the only solution will be to <strong>slow down and take a deep breath</strong>. The more I&rsquo;m upset with something like the repetitiveness of my work, the more I delve into that ever ready stream of happy Magic-thoughts. Yay!</p>
<p>Less thinking, more being.</p>
<h3 id="pollution-in-general">Pollution in general</h3>
<p>Think about the amount of images that burn in our retinas daily, the amount of unneeded refresh rates it has to take for your eyes to read a stupid Facebook page of a distant friend you&rsquo;re not even remotely interested in in the first place. The amount of things you have to do each day because they&rsquo;re part of a weird ritual made up by your local government or employer. The amount of noise you have to dig through in order to reach the data that is actually relevant to you in order to get your job done. The ridiculous amount of mails you send and receive each day because you think you have to or otherwise others won&rsquo;t find you that productive. The amount of times you have to say &ldquo;I know what you mean&rdquo; and &ldquo;really? How cool!&rdquo; to someone, when, in fact, that person is very irritating and you just want to go home. The amount of hours you spend watching a television show that could be spent walking your dog, drawing or reading instead.</p>
<p>The amount of hours you waste sitting in a chair thinking you could do something else right now. I might have a feeling of melancholy typing this, and you know that I might overreact, or not based on your situation, but you also know that time is better spent if you&rsquo;re in that very moment you&rsquo;re spending it. Maybe</p>
<p>Like bicycling instead of thinking about games. Or just trying to sincerely help others instead of complaining about noise and receiving positive feedback on your way out. Or actively engaging into a conversation when you&rsquo;re committing yourself to it instead of thinking about games. Or honestly saying that you&rsquo;re not interested and simply going home. That&rsquo;ll do.</p>
<p>I&rsquo;m still (not) working on a solution to this problem.
<br/>I&rsquo;ll probably figure it out just before I die.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 17 August 2017.
</p>
]]>
</description>
</item>
<item>
<title>A quick look at 6 fountain pens</title>
<link>https://brainbaking.com/post/2017/07/fountain-pens-first-look/</link>
<comments>https://brainbaking.com/post/2017/07/fountain-pens-first-look/#commento</comments>
<pubDate>Tue, 18 Jul 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/07/fountain-pens-first-look/</guid>
<category domain="https://brainbaking.com/tags/fountain pens">fountain pens</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/6pens.jpg"/>
</p>
<p>My recent addiction to fountain pens has reached new heights. I happened to talk about pens with a dear colleague and she asked if I also had pens with a flexible nib. Posing such a question usually requires some basic knowledge about types of nibs, and it turned out that her friend is another fountain pen enthusiast who owns a bunch of really neat looking (and writing) pens. I was very excited when she proposed to let me try some of his special nibs. As I did not want to keep these pens around for too long (they are expensive and not mine), I only got around to testing them for a couple of hours, so this is by no means an elaborate review, more of a quick look.</p>
<p>Pen enthusiasts could be roughly categorized as follows:</p>
<ol>
<li>The collector. Gotta catch &lsquo;em all&hellip;</li>
<li>The shower. The more expensive, the better. Look at my penz! Owns Mont Blancs.</li>
<li>The functional/workhouse user. Owns only a couple but uses it daily. Writes with a LAMY 2000.</li>
</ol>
<h3 id="what-i-am-looking-for-in-a-pen">What I am looking for in a pen</h3>
<p>I&rsquo;d consider myself to be part of the last category, but usually once the addiction kicks in you&rsquo;re converging to the first one. I&rsquo;m looking for a few &ldquo;holy grail&rdquo; fountain pens that do everything that I need:</p>
<ul>
<li>I want one pen to rule them all for writing.</li>
<li>A couple of pens for drawing. These need to be able to put out variable line widths and handle a lot of ink well.</li>
</ul>
<p>The first requirement could be tackled with a LAMY 2000, a Pilot custom 823 or a Platinum 3776. But the second requirement got me into the <strong><a href="https://www.nibs.com/content/sailor-specialty-nibs">sailor specialty nibs</a></strong>: they can be turned upside down to produce lush, broad strokes, and be used normally for fine strokes suitable for details or hatching.</p>
<p>And then Liesel, my colleague, gave me a Sailor Cross Concord and Naginata Togi to test. My hart skipped a beat. I&rsquo;ve read rumors about those nibs, rumors like limited or no supplies, difficulties of getting hold of those pens, and of course - the price (and don&rsquo;t forget import taxes). Be advised: I am not in any way an expert at fountain pens and this is a highly subjective matter.</p>
<p><figure>
<a href="/img/6pens-detail.jpg" class="lbox">
<img loading="lazy" src="/img/6pens-detail.jpg" alt="picture of the 6 pens" >
</a>
</figure>
</p>
<h3 id="the-pens---from-left-to-right">The pens - from left to right</h3>
<h4 id="conid-bulkfiller---titanium-nib">CONID Bulkfiller - Titanium nib</h4>
<p>The CONID is <a href="http://www.conidpen.com/index.cfm?fuseaction=makingof">actually made in Antwerp</a>, I didn&rsquo;t even know we Belgians had our own fountain pens! It&rsquo;s available as steel, titanium and gold nibs. The CONID has a special filling system that maximizes the ink capacity I&rsquo;ve ever seen (3ml!!). It&rsquo;s also a demonstrator and has a sleek modern design, especially with the titanium nib. The nib is quite springy and puts out a lot of ink while writing. I can&rsquo;t remember if this was a medium or fine nib but it wrote quite smooth with minimal feedback - not as buttery smooth as the Togi below but that might not be what you&rsquo;re looking for. I honestly think this could be an everyday powerhouse writer because of the ink capacity and the durability - it&rsquo;s a great alternative to the timeless LAMY 2000. It&rsquo;s also a bit of a geeky pen for fountain pen enthusiasts: it can be completely disassembled, like TWSBI pens.</p>
<p>This might not be the best choice if you&rsquo;re not writing on fountain pen friendly paper. And you will not if you&rsquo;re using it as your daily writer. I found the nib to be too broad for my liking - the springiness might be a disadvantage here - ink needs to dry longer compared to my cheap LAMY Al-Star with a fine nib. I know, comparing a 20 EUR pen with a 320 EUR is a bit ridiculous but LAMY nibs are very smooth and I like that for writing. You can see the slit in the picture from the breather hole to the top is quite broad.</p>
<h4 id="pilot-custom-heritage-912---po-nib">Pilot Custom Heritage 912 - PO nib</h4>
<p>The anti-broad pen for extremely fine writing. The PO nib works like a needle and produces very fine, very quick drying lines, especially useful for office paper. But needles have feedback: indeed, this nib is very scratchy. I found it to be too thin and too scratchy to write comfortably and I couldn&rsquo;t find a reason to write that small. Japanese fine nibs are already quite small, but my Pilot Metropolitan is smoother than this pen. At 200 EUR, you&rsquo;d need a very good reason to write that small. It can however also write upside down and produces smoother, somewhat thicker lines, a bit like the Cross Concord below, but the difference is not big enough for me to bother.</p>
<p>I do like the Custom Heritage 912 body though, it fits perfectly into my hand and writes well capped or uncapped. It&rsquo;s a bit boring compared to the CONID. The Pilot CON70 converted holds a good amount of ink and small nibs will obviously last longer.</p>
<h4 id="pilot-custom-heritage-912---music-nib">Pilot Custom Heritage 912 - Music nib</h4>
<p>The same well balanced body as the previous pen, so that&rsquo;s good. But this nib is a special stub: it has two slits and three tines to produce a consistent flow of ink - it&rsquo;s a very juicy writer and I liked it a lot. This stub is tipped: it still requires you to hold your pen ad the right angle to write but it&rsquo;s not as bad as my TWSBI ECO 1.1 stub. I&rsquo;m a leftie and hold pens at a slight angle so this will take some time to get used to.</p>
<p><figure>
<a href="/img/6pens-writing.jpg" class="lbox">
<img loading="lazy" src="/img/6pens-writing.jpg" alt="writing with the 6 pens" >
</a>
</figure>
</p>
<p>Purple: Pilot Music nib<br/>
Green: TWSBI ECO 1.1 stub</p>
<p>Music nibs are also fun to draw with: they keep up well with fast drawers and have some line variation as a downward stroke is broad but a horizontal stroke is thin. The Pilot music nib has a decent amount of feedback I couldn&rsquo;t get used to. However, one hour to test drive a pen is a very short amount of time. <a href="http://tina-koyama.blogspot.be/2015/03/epic-pen-search-and-discovery-part-6.html">Tina Koyama</a> reviewed the Platinum 3776 music nib for drawing and I agree with her: this is not <em>thé</em> pen for drawing if you also want to be able to produce fine lines. And it&rsquo;s a bit too broad for daily writing, the CONID felt snappier.</p>
<h4 id="sailor-naginata-togi-mf">Sailor Naginata Togi MF</h4>
<p>Next up: a specialty nib from Sailor, the Naginata Togi Medium Fine. I have to say, this is one of the smoothest pens I&rsquo;ve ever written with. My expectations were high but were also met in an instant. The Togi is even able to produce different thicknesses based on the angle you hold the pen at (see brown in photo above). It puts out a lot of ink while writing and it came with a Pro Gear body. The body is a bit on the short side, and compared to the Pilot custom Heritage, not that fitting for my hand. It&rsquo;s a bit thick capped and too small uncapped. The converter hold a pitiful amount of ink: I haven&rsquo;t tried how many pages you can write with it but I reckon it won&rsquo;t be a lot.</p>
<p>Take a look at the writing above the sketch of my dog where I compare the thickness of the Togi with the music nib. The pen is held at an angle of 45 degrees. It&rsquo;s an all-rounder and also suitable for drawing: the left foot comes from the Naginata Togi.</p>
<h4 id="sailor-cross-concord">Sailor Cross Concord</h4>
<p>Another specialty nib from Sailor. The <strong>cross</strong> in Cross Concord indicates a second nib on top of the main nib with a horizontal slit. The second slit guarantees a consistent ink flow required for the broad upside down strokes you&rsquo;re making with the concord but it does mean that it&rsquo;s a stiff nib.</p>
<p><figure>
<a href="/img/6pens-concord.jpg" class="lbox">
<img loading="lazy" src="/img/6pens-concord.jpg" alt="the cross concord" >
</a>
</figure>
</p>
<p>If you&rsquo;re looking for a unique fountain pen, this is it. It writes with (very) fine lines when in normal use with a lot of feedback - not as much as the PO nib but not exactly smooth, thanks to the downward faced beak shape of the nib. When turned upside down, however, you get a double broad line. Angling your pen means thinner strokes but still quite broad. It&rsquo;s a lot of fun to use for quick sketches. Details can be filled in with the fine line. This pen is one of those drawing pens I can imagine being in my pen case for daily use.</p>
<p><figure>
<a href="/img/6pens-drawing.jpg" class="lbox">
<img loading="lazy" src="/img/6pens-drawing.jpg" alt="drawing with the 6 pens" >
</a>
</figure>
</p>
<p>The black sketches come from the Cross Concord: look at the thickness of those strokes compared to the very fine hatches inside the foot on the right. It&rsquo;s as you can see luckily not as thick as my cheap Fude pen held at 45 degrees. The black writing on the top right page is from the Pilot PO nib and smaller than the fine Concord lines.</p>
<p>The problem with those nibs is the availability. These are hand crafted by Japanese experts and they are deeply back ordered. Importing from Japan could burn an even greater hole in your wallet: in Belgium import rates go as high as 50%!</p>
<blockquote>
<p>Mastery is in short supply nowadays, a consequence of our multi-tasking, bucket-listing world. A Microsoft study released this May claims the human attention span is now eight seconds, one second short of a goldfish. Disposable culture may feed the needs of the moment, but still leave the spirit hungry for something more. <span>Leigh Reyes</span></p>
</blockquote>
<h4 id="pilot-justus-95">Pilot Justus 95</h4>
<p>I spent too much time playing with the Sailor nibs and only tried a few sentences with this adjustable nib. You can turn the nib to it&rsquo;s soft or hard side as it providers more ore less flex. Compared to the Pilot Falcon nib, this feels like a nice but unneeded novelty. It&rsquo;s a very soft nib and will react to the slightest amount of pressure you put on it, a lot more than the CONID nib. When drawing, I disliked the amount of feedback when applying pressure to produce a thicker line. I&rsquo;m not a flexer when it comes to sketching so this will not be my everyday pen, and I cannot imagine myself using this daily as a workhorse, so it doesn&rsquo;t fit either category that would qualify for myself personally to buy an expensive fountain pen like this (312 USD at <a href="https://www.gouletpens.com/pilot-justus-95-fountain-pen-black-fine/p/PN60591">Goulet Pens</a>).</p>
<h3 id="conclusion">Conclusion</h3>
<p>I had a lot of fun testing these pens, thank you very much Filip and Liesel! The Sailors stay in my top wanted list, I can&rsquo;t get them out of my head. The Togi could even take up the role as an everyday writer if it would be fitted with a piston filler like the Realo body. I still need to try out the Naginata Fude and the Cross Point in order to make a decision (or maybe just get all three?). Now that I&rsquo;m writing this blog post and doing some research, I regret not having spent more time with the CONID. I just need to come up with an excuse to lend them again&hellip;</p>
<p>The steep prices of the pens should, in my view, be justified by their exceptional performance. If I can&rsquo;t feel a clear difference between an expensive nib and a cheap one, then I don&rsquo;t see a reason to boast with a golden nib and a cool brand.</p>
<h4 id="resources-for-drawing-penthusiasts">Resources for drawing penthusiasts</h4>
<ul>
<li><a href="http://tina-koyama.blogspot.be">Tina Koyama</a>&rsquo;s drawing blog</li>
<li><a href="http://www.parkablogs.com/">Teoh Yi Chie</a>&rsquo;s parka blog artist pen reviews</li>
<li><a href="https://www.penaddict.com/top-5-pens/">Pen Addict&rsquo;s top 5 pens</a></li>
<li><a href="http://www.leighreyes.com/">Leigh Reyes</a>&rsquo; blog</li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 18 July 2017.
</p>
]]>
</description>
</item>
<item>
<title>Journaling in practice</title>
<link>https://brainbaking.com/post/2017/07/journaling-in-practice/</link>
<comments>https://brainbaking.com/post/2017/07/journaling-in-practice/#commento</comments>
<pubDate>Mon, 10 Jul 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/07/journaling-in-practice/</guid>
<category domain="https://brainbaking.com/tags/journaling">journaling</category>
<category domain="https://brainbaking.com/tags/fountain pens">fountain pens</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/journalingpratice.jpg"/>
</p>
<p>If you&rsquo;re wondering why you should journal in the first place, then maybe it&rsquo;s a good idea to start reading <a href="/post/healing-creative-scars/">&lsquo;healing creative scars&rsquo;</a> and <a href="/post/a-samurai-learning-mindset/">&lsquo;a samurai learning mindset&rsquo;</a>.</p>
<p>There are hundreds of resources available on the Internet on how to journal, how to keep a bullet journal, how to index everything, how to getting things done and so forth. The following advice is something that <em>works for me</em> - it might not work for you at all. Don&rsquo;t worry, simply try something else. Journaling should be kept <strong>easy and fun</strong>, otherwise you won&rsquo;t be doing it daily and you won&rsquo;t gain the same amount of satisfaction and things might not get done at all (if that is what you&rsquo;re after).</p>
<h3 id="whats-in-it">What&rsquo;s in it</h3>
<p>That&rsquo;s fairly simple:</p>
<ul>
<li>Notes taken from class, thoughts, while reading a book, &hellip; This is loose text, mostly structured as a mind map, eventually accompanied by sketches.</li>
<li>Something I call a &ldquo;braindump&rdquo;: full sentences of things I&rsquo;m thinking or feeling right now.</li>
<li>Drawings.</li>
<li>Pictures, greeting cards, stamps, stickers, &hellip; (<em>scrapbooking</em>)</li>
<li>Lists of things to do, food to eat, things to research or buy or sell or &hellip;</li>
<li>&hellip;</li>
</ul>
<h4 id="one-journal-to-rule-them-all">One journal to rule them all</h4>
<p>Anything goes. A requirement for me in order to work with everything in one journal is that it&rsquo;s <strong>unlined</strong>. Otherwise I feel restricted and won&rsquo;t take as much notes as I intend to. Again: this might not be the case for you. <br/>
So yes, everything is in <strong>one journal</strong>. I used to keep sketchbooks separate from (Moleskine) journals because of the differences in paper, but binding your own book or buying something else than Moleskine fixes this problem: see &lsquo;about the paper&rsquo;. When I take a note, I just start writing where I left off - I might put a small line down to keep things separate when I feel like it. But I always date notes (I&rsquo;ve seen people use the time, I&rsquo;m happy with only the date for now.)</p>
<p>Keeping one notebook with me at all times beats having to hog a notebook, a sketchbook, another work related notebook and a family planning notebook. I know this might sound counterintuitive to you: &ldquo;but I how will I be able to find stuff later on?&rdquo;. Good question we&rsquo;ll answer later. A part of the answer is simply by re-reading. If you don&rsquo;t re-read what you&rsquo;ve written, nothing will ever happen with it. So, if you intent to simply write down thoughts in order to feel a temporary moment of relief, fine. But if you intent to change your life, that won&rsquo;t suffice.</p>
<h4 id="on-todo-items">On TODO items</h4>
<p><figure>
<a href="/img/todos.jpg" class="lbox">
<img loading="lazy" src="/img/todos.jpg" alt="TODO items" >
</a>
</figure>
</p>
<p>Speaking of GTD, if you&rsquo;re into <a href="http://gettingthingsdone.com/">David Allen</a>&rsquo;s mindset you can reserve one page for all your TODO items to tick off with a sticky note. That way it&rsquo;s easy to open up your journal on the current TODO page and quickly jot it down. If everything is ticked off or you&rsquo;re out of space, simply start a new page. Agree upon a convention of tick boxes for yourself, you&rsquo;ll be needing something like</p>
<ol>
<li>Open (TODO)</li>
<li>Done (tick off the open box or strike through!)</li>
<li>Rejected (Not needed anymore)</li>
<li>Reverted (Written down in a new list, or someone else will do this)</li>
</ol>
<p>If that&rsquo;s not enough one could imagine things like &ldquo;doing right now&rdquo;, something in between open and done, or &ldquo;will do someday but not now&rdquo;, something in between rejected and reverted. Those TODO lists are the only kind of &ldquo;special&rdquo; pages I have right now that give me instant access to what I should be doing between the notes and sketches. Some people dislike reserving a page for these kind of things and keep those lists in digital apps on their cellphones - fine, but you won&rsquo;t feel that spark of joy when actually physically ticking off that box. I&rsquo;m more of an analog person and as I journal anyway, why not integrate that?</p>
<blockquote>
<p>The palest ink is better than the best memory - Chinese proverb.</p>
</blockquote>
<h4 id="on-easily-spotting-ideas">On easily spotting ideas</h4>
<p>TODO items are definable things that need to get done within a certain time frame. Loose ideas that might or might not get executed will be translated (maybe in the next journal) into those concrete items, but before that I wanted to create something easily recognizable that catches my attention when I re-read the pages. To do that, I mostly draw simple light bulbs as an indication of an idea. Pretty original eh? Remember: do something that simply works for you. When I&rsquo;m in the mood, I might even color it! Look at that!</p>
<p><figure>
<a href="/img/idea.jpg" class="lbox">
<img loading="lazy" src="/img/idea.jpg" alt="woah, an Idea!" >
</a>
</figure>
</p>
<p>See what a bit of color does to where your eyes go to? That&rsquo;s one of the reasons I also try to vary in the inks I use - more on that later.</p>
<h4 id="on-ending-a-journal-or-year">On ending a journal (or year)</h4>
<p>There&rsquo;s this thing I simply call &ldquo;365&rdquo;. With each new year (or sometimes at the end of a notebook, when I feel like it), I make a 2-page spread mind map of things that kept me busy. It&rsquo;s more or less an analog <em>tag cloud</em> and it&rsquo;s extremely rewarding to make. You get to browse through previous journals, look at things you&rsquo;ve written down and actually managed to pull of, and take note of that in one or two words. That creates a thick cloud full of the things that defined you for the last year. It&rsquo;s actually quite incredible to look at. When I&rsquo;m done doing that, I try to underline the words that meant more to me than others.</p>
<p>Applying the <strong>retrospective</strong> principles from software development on your own personal life and writing down what made you glad, mad or sad actually helps you do something about that. Another trick that might work better for you is creating mind maps of things you&rsquo;ve already written down in the past - that way they grab your attention again. I like to call these <strong>meta-notes</strong>: notes about notes. Those are the best. Don&rsquo;t be shy to add notes to older pages, or to strike them through if that&rsquo;s how you feel about them. Remember that &ldquo;braindumps&rdquo; are momentary surveys: they might contain a lot of negative emotion. Don&rsquo;t get dragged away in that negative feeling again while re-reading! It&rsquo;s a tarp! Danny Gregory said in his Creative License that journals should contain happy thoughts only but I disagree - sometimes writing how you feel when you&rsquo;re upset helps to place that feeling in that moment. That said, those braindump pages are of little use to me afterwards.</p>
<blockquote>
<p>An attitude of gratitude brings opportunities.</p>
</blockquote>
<h4 id="about-the-paper">About the paper</h4>
<p><figure>
<a href="/img/kindsofjournals.jpg" class="lbox">
<img loading="lazy" src="/img/kindsofjournals.jpg" alt="different kinds of journals" >
</a>
</figure>
<br/>
Different kinds of journals: Magritte edition <a href="http://www.ludion.be/nl/home">Ludion.be</a>, the back of a black <a href="http://www.moleskine.com/en/">Moleskine</a>, a smaller <a href="http://www.paperblanks.com/">Paperblanks</a> silver Filigree, a yellow <a href="https://www.leuchtturm1917.de/">Leuchtturm</a> 1917 and a <a href="http://www.midori-japan.co.jp/md/en/">Midori</a> A5 notebook.</p>
<p>Do you use a <em>fountain pen</em>? Avoid the Moleskines and go for MD or Leuchtturm - they absorb the ink very well and there&rsquo;s almost no bleed-through. Do you want to use watercolor for sketching? There&rsquo;s a special Moleskine watercolor paper journal that soaks up a decent amount of water (25% cotton). The Paperblanks and Ludion books have thicker paper, the Moleskine has the thinnest paper. I always go for a creamy white color instead of bleached white that hurts the eyes and doesn&rsquo;t pair well with my preferred ink colors. If you intend to do a lot of scrapbooking (pasting stuff between pages), you might benefit from a heavier book that handles additional weight well.</p>
<p>Another minor thing to notice is the ability to put stuff away in the back pocket of some notebooks like Moleskine and Leuchtturm. I like carrying stamps and greeting cards with me in case I feel the sudden urge to write a letter and that&rsquo;s where they go until they&rsquo;re used. No big deal if it&rsquo;s not there: simply glue an envelope onto the back of the book:</p>
<p><figure>
<a href="/img/pocket.jpg" class="lbox">
<img loading="lazy" src="/img/pocket.jpg" alt="journals with or without pockets" >
</a>
</figure>
</p>
<p>Tucking some <em>post-its</em> in there also never hurts.</p>
<h3 id="how-to-search-in-it">How to search in it</h3>
<h4 id="step-1-page-numbers">Step 1: Page numbers</h4>
<p>Do you see the number on the bottom left of this note?</p>
<p><figure>
<a href="/img/pagenr.jpg" class="lbox">
<img loading="lazy" src="/img/pagenr.jpg" alt="pagenr" >
</a>
</figure>
</p>
<p>That&rsquo;s 113. Every page is numbered. Leuchtturm does this for me but not the way I want it: they number every page like most conventional books, but I number an &ldquo;open page&rdquo; (a span of two pages) as one page. That way, I can refer to a section of page in a book by using <strong>#(booknr)p(pagenr)(section)</strong>, for example #8p113a. There are four sections in my journals: A (upper left), B (down left), C (upper right), D (down right). Since I used to buy only Moleskines, the first thing I did was writing a page number on the bottom left of every (&ldquo;open&rdquo;) page, and as I&rsquo;m lazy, I don&rsquo;t want to write 200+ numbers. Another advantage of using the page numbering like that is that it keeps notes together as I tend to write or sketch a lot on the open pages on the same subject. So referencing is another tip, if you&rsquo;re re-reading you might think &ldquo;ah, I already wrote about this in #5p30b!&rdquo;.</p>
<h4 id="step-2a-use-an-appendix">Step 2a: Use an appendix</h4>
<p>In 1685, The British philosopher John Locke published a book called <a href="https://iiif.lib.harvard.edu/manifests/view/drs:13925922$1i">&ldquo;a new method of making common-place books&rdquo;</a>. A &ldquo;commonplace book&rdquo; was in essence a journal where one keeps famous quotes, parts of books one has read and reflects upon them. That&rsquo;s also a vital part of my journal, but my intent is to keep something much broader.<br/> He introduced a revolutionary indexing system to keep track of what one wrote that I tried out myself in several journals but ended op ditching all together. In essence, you reserve the last X pages (problem 1) to create a more modern tag-based indexing system. Refer to each page using your special page numbering system. But the problem is, as your journaling collection grows, multiple indexes might contain the word &ldquo;Japanese food&rdquo; and there&rsquo;s no global overview of the overview per book. Also, it&rsquo;s hard to lock in on one or two words per section. For instance, consider I wrote something about Japanese food in #1p01a. It&rsquo;s about sushi, which is rice, and about maki or other kinds of rolls. What tag am I going to pick? Japanese food? Rice? Maki? Sushi? Everything is the best possible answer, but that only increases the useless size of those last X pages.</p>
<h4 id="step-2b-digitalize-everything">Step 2b: Digitalize everything.</h4>
<p>After not finding my notes quick enough, I started exploring the possibilities of <a href="http://www.evernote.com">Evernote</a>. It&rsquo;s OCR does not work well on handwriting but that&rsquo;s okay: I can quickly add tags per scanned page myself. Below a few screenshots of my Evernote workstation:</p>
<p><figure>
<a href="/img/evernote1.jpg" class="lbox">
<img loading="lazy" src="/img/evernote1.jpg" alt="evernote" >
</a>
</figure>
</p>
<p><figure>
<a href="/img/evernote2.jpg" class="lbox">
<img loading="lazy" src="/img/evernote2.jpg" alt="evernote" >
</a>
</figure>
</p>
<p><figure>
<a href="/img/evernote3.jpg" class="lbox">
<img loading="lazy" src="/img/evernote3.jpg" alt="evernote" >
</a>
</figure>
</p>
<p>Every notebook has it&rsquo;s own digital notebook, and every page (remember my page numbering, that&rsquo;s 2 physical pages) is one scan and one note, titled with the page numbering system I explained earlier. In order to use Evernote&rsquo;s fast search system, you have two options:</p>
<ol>
<li>Write down notes below the scanned image. (those get indexed)</li>
<li>Use tags.</li>
</ol>
<p>I decided to go for the second one. The Evernote scanning app on Android has evolved quite nicely the last few years, it recognizes pages flawlessly and scans them quite well. There are however a few manual steps to be needed in order to get my system working:</p>
<ol>
<li>I want one note per page. Scanning one page with my cellphone and touching &ldquo;done&rdquo;, reopening the application and scanning the next page is very tedious. So I scan as much pages as possible, all crammed together in one note. Afterwards, I post process those notes on my Mac by cutting each image, creating a new note (CMD+X, CMD+N, type in the page number, tab, CMD+V).</li>
<li>I want the note to be easily readable without relying on tags - that&rsquo;s my backup. So another manual step, rotating the image, is sometimes needed.</li>
<li>The most painful one: go through everything note per note, re-read and try to figure out what&rsquo;s on it, and tag accordingly.</li>
</ol>
<p>Tags do have their advantage over plain text: I can see how much I&rsquo;ve written about self improvement with one click of the button as seen in the last screenshot.</p>
<p>This whole process takes up to 4 hours for one A5 notebook. I&rsquo;m okay with that: it usually takes 6 months up to a year for me to complete a journal anyway and it gives me the power to <strong>have access to all journals at all times</strong> with the Evernote app. When I quickly want to reference a cooking recipe, I can search for &ldquo;pancakes&rdquo; and immediately hit 3 or 4 notes. It does take a while to look at the scanned image to figure out where exactly I placed that particular piece of information - that&rsquo;s one downside of the system. But as I journal &ldquo;<em>organically</em>&rdquo;, meaning putting everything in the same place from pictures to drawings, my brain can find what I need on the scan pretty quickly, compared to pages full of text between lines.</p>
<h3 id="tools-of-the-trade">Tools of the trade</h3>
<h4 id="in-my-pencil-case">In my pencil case</h4>
<p>Some stuff I regularly use for journaling:</p>
<p><figure>
<a href="/img/pennenzak.jpg" class="lbox">
<img loading="lazy" src="/img/pennenzak.jpg" alt="my current pencil case" >
</a>
</figure>
</p>
<ul>
<li>A small scissor for scrapbooking</li>
<li>Pritt and tape with a lovely pattern</li>
<li>Fountain pens (Lamy EF, TWSBI 1.1 Stub, Metropolitan F, Sailor Fude) loaded with different colors.</li>
<li>Kuretake Water brushes</li>
<li>HB pencil, sharpener, kneading gum</li>
</ul>
<p>I love constantly changing what I carry in my case. The HB will be replaced with a 2B/4B, for drawing I like a softer edge. The kneading gum might disappear, using it less and less. A pocket knife is rather heavy and I only use the scissor so I might swap that out with something more comfortable. I recently trashed the pigment liners in favor of fountain pens with document ink like &ldquo;De Atramentis&rdquo;. Writing and drawing on different paper will give you a different feel: your taste for the paper and the pens will evolve so be prepared to experiment a lot - that&rsquo;s part of the fun!</p>
<p>My wife taught me to add some color after some pages are filled and the more I do that, the more I like browsing through the journal. Watercolor is still too heavy for most notebooks and I don&rsquo;t bother to bring colored pencils on location. That&rsquo;s a relaxing activity to do at home.</p>
<h4 id="for-the-gadget-freaks">For the gadget freaks</h4>
<p>This tiny thing is something I also use now and then:</p>
<p><figure>
<a href="/img/pogo.jpg" class="lbox">
<img loading="lazy" src="/img/pogo.jpg" alt="polaroid pogo" >
</a>
</figure>
</p>
<p>It&rsquo;s called a &ldquo;Polaroid Pogo&rdquo;, a pocket printer with Bluetooth that prints on small stickers. Excellent sticker quality but abysmal color quality. Instead of printing a picture and cutting &amp; pritt-ing it in my journal, I simply send a picture from my cellphone to the printer to immediately stick on the page. A part of the picture on the Evernote screenshots above is a Pogo sticker - it works well enough but the paper isn&rsquo;t cheap and is hard to find besides Amazon.</p>
<h4 id="note-taking-at-night">Note taking at night</h4>
<p>At night, my journal stays in my backpack. That way I won&rsquo;t forget to take it with me the next day. Also, note taking in bed with a pen is difficult because the ink flows along with gravity and I don&rsquo;t like to use a pencil for writing. The solution is fairly simple: there&rsquo;s a note block with a pencil on my bedside table. I scribble down stuff and forget about it. Every week, I collect those notes and decide what to do with them: throw it away or copy it over into my journal.</p>
<h4 id="more-notebook-pimping">More notebook pimping</h4>
<p>A Moleskine is actually rather boring. It&rsquo;s black (except if you&rsquo;re willing to spend even more on the limited editions). As I wanted my journals to be something that characterizes me and that makes me smile every time I grab them, I added something on the cover:</p>
<p><figure>
<a href="/img/journalcovers.jpg" class="lbox">
<img loading="lazy" src="/img/journalcovers.jpg" alt="some book covers" >
</a>
</figure>
</p>
<p>You can imagine the possibilities. It should - and will - fuel your creativity. Go with the flow, don&rsquo;t be too hard on yourself. Welcome to a wonderful journey.</p>
<h3 id="i-want-more">I want more!</h3>
<p>Here are some interesting links of people that helped inspire me:</p>
<ul>
<li><a href="https://dannygregorysblog.com/journals/">Danny Gregory&rsquo;s journals</a></li>
<li>Kim&rsquo;s <a href="https://www.tinyrayofsunshine.com/blog/bullet-journal-guide">Thorough Guide to the Bullet Journal System</a></li>
<li><a href="https://alexvermeer.com/life-areas/">Alex Vermeer&rsquo;s Life Areas</a> and <a href="https://alexvermeer.com/8760hours/">Year Reviews</a></li>
</ul>
<p>These more general blogs are also entertaining to browse through:</p>
<ul>
<li><a href="https://www.brainpickings.org/">Brain Pickings</a></li>
<li><a href="http://lifehacker.com/">Life Hacker</a></li>
</ul>
<p>These books I consider to have changed my life completely:</p>
<ul>
<li><a href="https://www.goodreads.com/book/show/8034188-where-good-ideas-come-from?from_search=true">Where Good Ideas Come From</a>, Steven Johnson</li>
<li><a href="https://www.goodreads.com/book/show/6899290-your-brain-at-work?ac=1&amp;from_search=true">Your Brain At Work</a>, David Rock</li>
<li><a href="https://www.goodreads.com/book/show/12921211-search-inside-yourself?ac=1&amp;from_search=true">Search Inside Yourself</a>, Chade-Meng Tan</li>
<li><a href="https://www.goodreads.com/book/show/4068964-lessen-in-levenskunst?ac=1&amp;from_search=true">Lessen in Levenskunst</a>, Wilfried van Craen</li>
<li><a href="https://www.goodreads.com/book/show/1636276.Learn_to_Power_Think?from_search=true">Learn to Power Think</a>, Caterina Rando</li>
<li><a href="https://www.goodreads.com/book/show/1633.Getting_Things_Done?ac=1&amp;from_search=true">Getting Things Done</a>, David Allen</li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 10 July 2017.
</p>
]]>
</description>
</item>
<item>
<title>Nuts about local nuts</title>
<link>https://brainbaking.com/post/2017/07/nuts-about-local-nuts/</link>
<comments>https://brainbaking.com/post/2017/07/nuts-about-local-nuts/#commento</comments>
<pubDate>Mon, 03 Jul 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/07/nuts-about-local-nuts/</guid>
<category domain="https://brainbaking.com/tags/cooking">cooking</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/pines.jpg"/>
</p>
<p>Remembering David Lebovitz' <a href="http://www.davidlebovitz.com/pine-nut-syndrome/">pine nut syndrome</a>, I started to take a closer look at packages of food we buy at the local supermarket. It&rsquo;s so easy to get completely focused on buying local vegetables but forgetting to look at the label when throwing something like pine nuts into the shopping cart. The worst thing is, most supermarkets don&rsquo;t care and don&rsquo;t offer an alternative. However, let&rsquo;s not panic just yet: this is slowly changing (but reached a plateau). Let&rsquo;s take a closer look at one of my favorite dishes: <strong>risotto</strong>.</p>
<p>What does a good risotto require?</p>
<ol>
<li>Olive oil.</li>
<li>Rice!</li>
<li>Garlic, onions.</li>
<li>Random <strong>star ingredient</strong>, as I call it - such as leeks or mushrooms.</li>
<li>A hard cheese, traditionally Parmesan.</li>
<li>Main condiment such as a (dried) stock</li>
<li>Pine nuts.</li>
</ol>
<h3 id="okay---im-from-belgium-now-what">Okay - I&rsquo;m from Belgium. Now what?</h3>
<p>Instead of swapping out ingredients for alternatives like butter for olive oil to make it more &ldquo;local&rdquo;, let&rsquo;s try to stick with the recipe and see how far we can get.</p>
<p>Olive oil. In most supermarkets easily available organically. Most olive oils come from Spain, Italy, Greece and Tunisia - in that order. That&rsquo;s 1000 to 2000km from Belgium. Italian olive oil is mostly sharp and pressed from green olives. A green olive comes from an early harvest. However, thanks to <a href="https://www.goodreads.com/book/show/38838.Olives">Morten&rsquo;s Olives book</a>, I became aware of a small scale production of exceptional French olive oil with a rich and complex taste originating in the North of the Provence, about 900km from where I live. The problem is, it&rsquo;s hard to get.</p>
<p>Rice. Difficult. Why? Cheap rice is from Asia, that&rsquo;s why. You can use short grained <strong>sushi</strong> rice for Italian risotto (feel free to leave a comment if you disagree) but there&rsquo;s a 13hr flight between Japan and Belgium, not exactly called <em>local</em>. Luckily, Italian rice is readily available, the brand &ldquo;Gallo&rdquo; is well known in all supermarkets. It&rsquo;s not cheap though, and not at all organic. Riso Gallo is one of the largest rice mills in Europe. That means I&rsquo;ll try to avoid buying from that supplier - why should I support a huge firm when I can (try to) help local farmers?<br/>
Other options are organic French rice from Camargue or Spanish rice from Deltebre. As you can see, it&rsquo;s starting to get difficult as these kinds of cereals are typically grown in wet and warm conditions, not near Belgium.</p>
<p>Garlic and onions, as the star vegetable, can be tackled with ease if you grow your own vegetables. If not, it&rsquo;s damn difficult if you don&rsquo;t pay attention to the labels! Organic onions are for sale in my local Carrefour and are from <strong>China</strong>. China! What the fuck? Non-organic onions are usually from the Netherlands. I don&rsquo;t think we need to argue here. Most people are unaware that garlic is a spring vegetable and can be stored in a dry and cool place for a long time. Don&rsquo;t buy this in winter, but stock up and simply ferment it before it&rsquo;s shooting.</p>
<p>The hard cheese might be a tough one if you insist on the Parmesan, which is a DOP: <strong>Denominazione di origine protetta</strong>. That means it&rsquo;s called only Parmesan if it&rsquo;s from a specific region Italy. But Belgium and the Netherlands <strong>are</strong> exceptionally good in making cheese, even hard and salty cheeses, like <a href="https://nl.wikipedia.org/wiki/Friese_nagelkaas">Friese Nagelkaas</a>. Of course we said we&rsquo;ll stick to the recipe but instead of using Pecorino, you can try very old Dutch sheep&rsquo;s cheese.<br/>
&lsquo;Mozzarella di bufala&rsquo;, one of the tastiest fresh Italian style cheeses, are almost always imported from Italy. But why? If you really bother to look, Belgium makes <a href="http://www.bufflardenne.be/">it&rsquo;s own mozzarella di bufala</a> (it shouldn&rsquo;t be called that because of the protective DOP label but who cares) and it&rsquo;s simply superior in taste. The only problem is that you&rsquo;ll have to drive to another shop - that might even be outside of your comfort zone.</p>
<figure>
<img src="/img/buffl.jpg"/> <figcaption>
<h4>Real local stuff, right here - if you look for it.</h4>
</figcaption>
</figure>
<h3 id="why-are-all-pine-nuts-from-china">Why are all pine nuts from China?</h3>
<p>When I shop at my local Carrefour, I have two options when buying pine nuts: the cheap &ldquo;1&rdquo; brand and the more expensive Carrefour brand. Both pine nuts are small and expensive, but nuts are always expensive. Looking at a supermarket like Bio Planet, they sell Italian pine nuts which are bigger, tastier and not that expensive compared to the Chinese counterparts. You could try to Google <a href="https://www.google.be/search?q=chinese+vs+italian+pine+nuts">&ldquo;Chinese vs Italian pine nuts&rdquo;</a> and you&rsquo;ll learn different species of nuts within the pine tree family. There are strangely enough a lot of blogs on this very subject.</p>
<p>So, about that risotto. The point isn&rsquo;t to keep it purely Italian, to only buy organic or local food, but the point is to <strong>know what you buy</strong>, and to make a thoughtful decision based on that. Instead of completely ignoring labels, prices and different markets, try to pay attention on your next shopping day and notice the small but very real differences for each product you load into the cart. You might not have the privilege of choice when it comes to a big price range difference - that&rsquo;s okay, just buy cheap Asian import rice. But know that there are tastier and healthier (not only limited to your own body!) alternatives.</p>
<blockquote>
<p>You can only start finding, if you know what to look for.</p>
</blockquote>
<p>It&rsquo;s a shame that people buy less and less responsible, but go out on restaurant more and still complain about their monthly (food) budget. In 1900, the average American spent about <a href="https://www.theatlantic.com/business/archive/2012/04/how-america-spends-money-100-years-in-the-life-of-the-family-budget/255475/">40%</a> of his monthly budget on food, compared to the 13% of 2003. That&rsquo;s 600 EUR if you earn 1500 EUR, compared to 200 EUR. Prices of course vary but it&rsquo;s a relative percentage and it does indicate <em>something</em>. I personally think you&rsquo;ll end up paying a lot more in medical bills later if you keep that percentage below 15%.</p>
<h3 id="reintroducing-domestic-science">Reintroducing domestic science</h3>
<figure>
<img src="/img/domestic.jpg"/> <figcaption>
<h4>Image copyright theparkschoolpreston.co.uk</h4>
</figcaption>
</figure>
<p>Instead of focusing on mathematics, linguistics and economics in schools, let&rsquo;s reintroduce household techniques as an integrated part of our youth&rsquo;s training course. Previously, one of the family members dedicated his/hers (usually the latter) time on grocery shopping, cooking, knowing what&rsquo;s good for you and what&rsquo;s not and knowing what grows in what season. Now, if you&rsquo;re lucky, you or your partner is interested in the subject or you simply like cooking and you&rsquo;ll end up with at least a piece of the puzzle. I was one of those people who had no general idea about seasons. Try gardening, it solves a lot of problems (but introduces new ones like snails).</p>
<p>The second part of my personal solution would be to <strong>get rid of supermarkets</strong>. I know this sounds insane and impossible in the volatile world we live in today, but instead of browsing through loads of garbage you might end up with something exceptional if you go to a market or speciality stores. This doesn&rsquo;t mean that the store can&rsquo;t be &ldquo;big&rdquo; or you won&rsquo;t find everything in the same place - chances are high you indeed won&rsquo;t. I used to resent the notion of having to do my weekly grocery shopping and now I look forward to it every single time. It took a long time before realizing I had to flip a switch in my head in order to achieve this mental state. Farmer&rsquo;s Markets are a great solution if you <strong>take the time</strong> to get to know the farmer. You&rsquo;ll learn how the wheat is milled and where the rye is grown.</p>
<p>Invest the time. You&rsquo;ll have to eat three times a day for the rest of your life. <br/>
Might as well be something nourishing.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 3 July 2017.
</p>
]]>
</description>
</item>
<item>
<title>Healing creative scars</title>
<link>https://brainbaking.com/post/2017/06/healing-creative-scars/</link>
<comments>https://brainbaking.com/post/2017/06/healing-creative-scars/#commento</comments>
<pubDate>Sun, 25 Jun 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/06/healing-creative-scars/</guid>
<category domain="https://brainbaking.com/tags/journaling">journaling</category>
<category domain="https://brainbaking.com/tags/self improvement">self improvement</category>
<category domain="https://brainbaking.com/tags/learning">learning</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/boekjesheader.png"/>
</p>
<p><a href="/post/journaling-in-practice/">Want to skip to the practical part?</a></p>
<h3 id="are-you-aware-of-your-problems">Are you aware of your problems?</h3>
<p>Once upon a time in a land not very far away (in fact, it&rsquo;s the very same we live in), a small boy and his Gameboy grew up. He didn&rsquo;t have many hobbies: gaming. He didn&rsquo;t have many friends. Playing outside is okay as long as the 4 AA batteries are fully charged and the sun isn&rsquo;t shining too bright and the playing is confined to one square meter. As the boy grew up, his taste for music didn&rsquo;t broaden: it narrowed. Teachers said he couldn&rsquo;t draw or run or swim properly, so he naturally assumed he couldn&rsquo;t draw or run or swim properly. Twenty years later, that boy who became a man still has a hard time unthinking he cannot draw or run or swim.</p>
<p>That is called a <strong>creative scar</strong> and can be very deadly. If someone ever says to you &ldquo;haha, you can&rsquo;t X&rdquo;, chances are that you&rsquo;ll tend to believe that person. Effects? Next time you&rsquo;ll think twice before doing X again. No way someone will laugh at you for doing something silly, right? So forget X, let&rsquo;s try Y instead. But why should you? Because one or two persons who have no idea what X is all about claim to know if you are good at it or not?</p>
<p>The problem gets worse if you are not aware that you have in facts such a scar. If you&rsquo;re not aware, then how on earth are you going to do something about it? The answer is you won&rsquo;t. You&rsquo;re stuck in the &ldquo;Unconsciously incompetent&rdquo; stage of competency. A diagram from <a href="https://en.wikipedia.org/wiki/Four_stages_of_competence">Wikipedia</a> might help to sketch the situation a bit:</p>
<p><figure>
<a href="/img/competences.png" class="lbox">
<img loading="lazy" src="/img/competences.png" alt="stages of competence" >
</a>
</figure>
</p>
<blockquote>
<p>Unconsciously incompetent: The individual does not understand or know how to do something and does not necessarily recognize the deficit.</p>
</blockquote>
<p>There are a lot like-minded diagrams or flow charts or resumes out there that try to tell you the same. The <strong>Shu</strong>, <strong>Ha</strong>, <strong>Ri</strong> learning principles of martial arts <a href="/post/a-samurai-learning-mindset">explained here</a> assume that you are willing to improve meaning you&rsquo;d already be in the consciously incompetent stage.</p>
<p>Okay, so how do you move from the bottom part of the pyramid all the way to the top? That&rsquo;s where <strong>self improvement</strong> comes into play.</p>
<h3 id="unlocking-your-consciousness">Unlocking your consciousness</h3>
<p>That boy how grew up to be a Nintendo fanboy has a blog and you&rsquo;re reading it. His music taste has broadened a lot, he&rsquo;s no longer a black and white thinker but started seeing shades of gray (50?). I do not know exactly when this all happened but I&rsquo;ll tell you it did not happen in a day or a week. It took me at least 7 years. In august 2010, I bought a cheap Moleskine notebook knock-off and started jotting down some notes. Those things typically included:</p>
<ol>
<li>Lists. I love lists. Your favorite (gameboy) game? Top 5 good food! What about movies? Birthday wanted lists etc etc.</li>
<li>Regrets. Too bad I don&rsquo;t have many friends to <a href="https://www.boardgamegeek.com/user/Jefklak">play boardgames</a> with.</li>
<li>Wishes. I&rsquo;d love to run 10km once. Wow, that seems highly unlikely, as I remember someone said I can&rsquo;t run. Still&hellip; Would be cool. Like to visit Japan someday. Or walk on the Great Wall of China, why not.</li>
<li>Brain dumps. A Momentary Lapse of Reason. How I feel on a given moment.</li>
</ol>
<p>Somehow, thanks to lots and lots and lots of writing, I started to become more aware of my own thoughts and feelings. In that time I read a lot of self help books - 9 out of 10 were junk, but I kept small summaries in my notebook. Somehow, some quotes or key giveaways still lingered in my extended analog memory, ready to be reread and executed. I always liked to write - otherwise I wouldn&rsquo;t be writing this article right here - but using a pen and ink to write down thoughts felt great. I finally had a way to track what I was doing or should be doing.</p>
<p>Of course concepts like <strong>journaling</strong> aren&rsquo;t new at all: Roman emperor and philosopher Marcus Aurelius wrote down how he should behave centuries ago. Great minds like Wittgenstein, John Locke and Seneca also loved writing. The medium was and is a great fit for rapid note taking - whether it&rsquo;s ideas or feelings, that doesn&rsquo;t really matter. As long as you do something with it afterwards. Or not - that&rsquo;s okay too.</p>
<p><figure>
<a href="/img/aurelius.jpg" class="lbox">
<img loading="lazy" src="/img/aurelius.jpg" alt="Aurelius" >
</a>
</figure>
</p>
<p>So I did not try to reinvent the wheel: I merely looked and copied what worked for me. That very same thing might not work for you at all - you might be one of those digital whizz kids that like to use Evernote or Google Keep. I&rsquo;m more of an analog guy: it enables me to sketch, write, make mind maps and paste pictures. But what should you do with your piece of work?</p>
<h3 id="the-quantified-self">The Quantified Self</h3>
<p>My favorite American Timothy Ferris has the answer to that. It&rsquo;s called &ldquo;quantify yourself&rdquo;: don&rsquo;t just gather data but also normalize it, tune it, change yourself, push yourself, re-gather data and analyze it further. Since the sudden increase in popularity on smart watches, it&rsquo;s rather easy for anyone to keep track of their health. Steps per day, sleep cycle, calories intake, you name it and your trusty watch will track it for you.
There&rsquo;s even a conference on <a href="http://quantifiedself.com/">Quantified Self</a> full of (technology) enthusiasts eager to share their experience with recording and adjusting stuff to make the world a better place.</p>
<p>But tracking itself isn&rsquo;t enough. Tim Ferris monitors his own body in extreme detail: after taking vitamins, before and after a workout, &hellip; Then he alters his daily routine. It&rsquo;s called modern self optimization. Tim is all about improving yourself and he even hosts an extreme successful podcast called the <a href="http://tim.blog/podcast/">Tim Ferris Show</a>. Subjects as &ldquo;<em>Maximizing Strength, Improving Mindset, and Becoming the Worlds Fittest Man</em>&rdquo; are not uncommon on the show, it&rsquo;s certainly worth checking out.
Tim is also a fan of &ldquo;morning pages&rdquo; in the morning: 5 minutes of writing in your journal before you do anything else. Except for getting out of bed (and maybe meditating) of course.</p>
<blockquote>
<p>It is possible to become world-class in just about anything in six
months or less. Armed with the right framework, you can seemingly
perform miracles, whether with Spanish, swimming, or anything
in between.</p>
</blockquote>
<p>David Allen&rsquo;s <a href="http://gettingthingsdone.com/">Getting Things Done</a>, or GTD, works more or less the same: there are clear differences between <strong>recording thoughts</strong> and <strong>executing them</strong>. When you surf to the webpage of GTD, you&rsquo;re greeted with this lovely quote from David himself:</p>
<blockquote>
<p>Your mind is for having ideas, not holding them.</p>
</blockquote>
<p>That is a powerful way of saying you should have a system that holds those ideas. In GTD, you re-read your captured ideas once or twice a week and decide what to do with them. Did you change your mind? Scratch those notes or throw away the loose page. Did you connect one idea with another, but is it still ripening like a nicely aged bottle of wine? Then connect them and add additional thoughts. But again, the key part is re-reading and re-prioritizing everything.
If something you think about involves work that is less than 10 minutes, you have the option to execute it right there instead of taking note of it.</p>
<p>Those notes in my journal set me on track to identify what I wanted to do the most and helped me actually realize them. I&rsquo;ll list some examples here because I like to list stuff, not because I like to brag what I did. Maybe I also do, but it&rsquo;s to show you what a person is capable of - if you have the willpower to sit through some emotional and physical pain.</p>
<ol>
<li>My P.E. teacher used to laugh at my pathetic attempts to run. Now I run 10km.</li>
<li>The only books I loved to read were fantasy to escape from this world. Now I run <a href="https://www.goodreads.com/user/show/5451893-wouter">a lot of non-fiction books</a> on any subject.</li>
<li>I decided that I should finally <a href="/post/post/teaching-yourself-to-draw/">learn to draw</a>.</li>
<li>After falling in love with <a href="http://www.redzuurdesem.be">sourdough bread</a>, I decided to follow a three year long night class to become a professional baker, and did an intensive internship, combined with my full-time job.</li>
</ol>
<p><figure>
<a href="/img/notes.png" class="lbox">
<img loading="lazy" src="/img/notes.png" alt="Aurelius" >
</a>
</figure>
</p>
<p>These examples might sound trivial to you, but mean the world to me. Everything wasn&rsquo;t a simple &ldquo;okay let&rsquo;s do that&rdquo; thought but came up organically by tracking what I was thinking on a given moment. When I notice I complain a lot about my bad drawing skills, I might - finally - do something about that.
<br/>Before journaling, I <em>simply had no idea</em>!</p>
<h3 id="serendipity">Serendipity</h3>
<p>One of the most influential (on a personal level) books I&rsquo;ve read is <a href="https://www.goodreads.com/book/show/8034188-where-good-ideas-come-from?ac=1&amp;from_search=true">Where good ideas come from</a> by Steven Johnson. One particular chapter struck me as very helpful. Steven talks about the <strong>collision of ideas</strong> by pairing them up &ldquo;by accident&rdquo;. It&rsquo;s called <em>serendipity</em>. Imagine going to the library with one or two books in your mind to search for. When you enter the library, a few books are displayed as &lsquo;new&rsquo; and you pick up one of them and start reading the cover. Browsing like that makes you connect the dots and eventually stumble upon new, interesting and exciting stuff. I usually go back home with other books than I intended to and never regret the decision after reading them.</p>
<p>The same is true for your bag of ideas that you call your journal. The more ideas that are compressed together on the A5 pages (in my case), the higher the chances that you&rsquo;ll come up with something new based on those ideas. Again, one clear requirement is re-reading what you&rsquo;ve written down. Some people like order and try to keep separate journals on ideas for the house, things from work and emotional thoughts. I am not one of those: I like my journals to be as <strong>organic</strong> as possible: let it grow, I say. I write whatever comes to me, and the next day the next thought is written down beside the previous one. Everything underneath each other. That might not work for you - just try some things and see what you like. Digital tools make tagging and searching a lot easier but require you to keep your cellphone closeby. I just happen to like fountain pens a lot more than cellphones.</p>
<p>Thanks to the serendipitous work of my journals, I got interested in a lot of subjects that I thought were not something for me. Let&rsquo;s take up another list:</p>
<ol>
<li>I like cooking. After a few journals, I like cooking and bread baking and fermenting and I&rsquo;m now a vegetarian.</li>
<li>I like drawing. After a few journals, I would like to know more about book binding, calligraphy and turning my own wooden fountain pen.</li>
<li>I like learning. Now I like teaching, philosophy and Buddhism.</li>
</ol>
<p>Thanks to a chain of new ideas and things to try out, you get to discover new ideas and things to try out. <strong>It&rsquo;s an adventure</strong>, and it never stops. <br/>
More on learning how to learn in the earlier <a href="/post/a-samurai-learning-mindset">samurai learning mindset</a> blog post.</p>
<h3 id="responsibility---for-yourself">Responsibility - for yourself</h3>
<p>Chances are you&rsquo;ve already heard from Christopher Avery&rsquo;s <a href="https://www.christopheravery.com/responsibility-process">Responsibility Process</a> (tm). I won&rsquo;t go into detail here but the model consists of different components that actually match the competency model I mentioned above: there&rsquo;s denial (you&rsquo;re not aware of any problems), there&rsquo;s justify/blame (you&rsquo;re aware but not willing to do something about it), there&rsquo;s obligation/shame (you&rsquo;re doing something about it because you have to) and finally there&rsquo;s responsibility. Writing down thoughts feels like stepping through that model - at least in the beginning, it does. You&rsquo;re not sure you&rsquo;re ready to admit that you might benefit from writing at all. But after your first or second small success you feel obliged to continue.</p>
<p>Nobody can help you like you can help yourself. And you can&rsquo;t help others, if you don&rsquo;t help yourself first. There is no Growing Smart Together if there is no Growing Smart Alone. It&rsquo;s your responsibility to get the best out of yourself - how you do it is up to you. I am happy with my secret weapon: journaling. It has proven to be extremely effective for the past seven years now. Marcus Aurelius wrote down:</p>
<blockquote>
<p>Being in contact with the God inside you, and serving him honestly.</p>
</blockquote>
<p>That&rsquo;s exactly what it feels like.</p>
<h3 id="in-practice">In practice</h3>
<p><figure>
<a href="/img/boekjes.jpg" class="lbox">
<img loading="lazy" src="/img/boekjes.jpg" alt="full journals" >
</a>
</figure>
</p>
<p>There are a lot of techniques involved in efficient journaling I like to save for a future blog post to be linked here. (Update: <a href="/post/journaling-in-practice/">it&rsquo;s here!</a>) But in practice, it all boils down to just starting to write. Do what works for you. If you decide to buy a journal, consider scanning in pages after it&rsquo;s full. I archive everything in Evernote but that requires tagging manually and soaks op a lot of hours. GTD is a nice way to keep track of things to do - if you&rsquo;re the kind of person who likes TODOs. I also like pasting pictures, doodling and sketching and even scrap-booking. Whatever that works.</p>
<p>Travel journals, details of book reviews, course summaries you&rsquo;ve followed, loose notes, gardening schemes, &hellip; It&rsquo;s all there waiting for you to discover. Have fun connecting the dots!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 25 June 2017.
</p>
]]>
</description>
</item>
<item>
<title>A samurai learning mindset</title>
<link>https://brainbaking.com/post/2017/06/a-samurai-learning-mindset/</link>
<comments>https://brainbaking.com/post/2017/06/a-samurai-learning-mindset/#commento</comments>
<pubDate>Tue, 20 Jun 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/06/a-samurai-learning-mindset/</guid>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/musashi.jpg"/>
</p>
<p>After reading the famed books <a href="https://www.goodreads.com/book/show/867247.A_Book_of_Five_Rings">The Book of five rings</a> By Miyamoto Musashi and the <a href="https://www.goodreads.com/book/show/364734.The_Life_Giving_Sword">Life-giving sword</a> By Yagyu Munenori, I started making connections between the teachings of the art of war and the teachings of any other craft. Yagyu clearly mentions the state of mind required to survive in battle can be used in any other profession to your advantage as well.</p>
<p>The back of the book states that &ldquo;every manager, seeker of life wisdom and practician of martial arts should use this&rdquo;. I have no clue why only a manager could benefit from the words written in 1643. Yagyū&rsquo;s work is much more zen-inspired than Musashi&rsquo;s and it does require you to see through some technical martial arts terms in order to see why one could leverage ideas from these Japanese sword experts to your own advantage, in the present - 2017.</p>
<h3 id="learning">Learning</h3>
<p>Let&rsquo;s start with different stages of learning. Musashi writes that only after he was 50, he finally fully understood the effective usage of two swords. He stopped dueling after 30 to settle and study, and to form his Individual School of Two Swords. He claims to have studied &ldquo;day and night&rdquo; for years, and that in order for you to fight well, you must think everything through. That sentence literally closes each section. Yagyū said:</p>
<blockquote>
<p>In order to become a true master, one must let go of everything he has learned and rise above.</p>
</blockquote>
<p>This looks like an interpretation of &ldquo;<a href="https://en.wikipedia.org/wiki/Shuhari">Shu - Ha - Ri</a>&rdquo;.</p>
<p><figure>
<a href="/img/ShuHaRi.png" class="lbox">
<img loading="lazy" src="/img/ShuHaRi.png" alt="ShuHaRi" >
</a>
</figure>
</p>
<p>In martial arts, there are 3 stages to learning mastery:</p>
<ol>
<li>shu - &ldquo;obey&rdquo; - follow the rules until they sink in. You have no idea why, or what you&rsquo;re doing. Like in cooking, you&rsquo;re strictly following a recipe. Like in learning to drive, you&rsquo;re shifting gears but you have to think on how to handle the shift stick.</li>
<li>ha - &ldquo;detach&rdquo; - breaking the rules. After following them, you contemplate on the rules and find loopholes and start to break them down.</li>
<li>ri - &ldquo;leave&rdquo; - there are no more techniques, everything has become intuition.</li>
</ol>
<p>The Shu-Ha-Ri concept may come from martial arts, but it seems to have found it&rsquo;s way to <a href="https://martinfowler.com/bliki/ShuHaRi.html">software development</a> according to Martin Fowler and Alistair Cockburn. They simply rephrase everything to be applicable to software development. You could go one step further and generalize it into learning <strong>any craft</strong>, not just martial arts or programming.</p>
<ol>
<li>I need clear steps in order to do something. I need context.</li>
<li>I am starting to understand the context and can do something myself.</li>
<li>It has become second nature and I don&rsquo;t think while I&rsquo;m doing it.</li>
</ol>
<p><a href="http://www.jazzadvice.com/clark-terrys-3-steps-to-learning-improvisation/">Clark Terry</a>&rsquo;s three steps of learning jazz are exactly the same:</p>
<ol>
<li>Imitate</li>
<li>Assimilate</li>
<li>Innovate</li>
</ol>
<p>The <a href="https://en.wikipedia.org/wiki/Dreyfus_model_of_skill_acquisition">Dreyfus model of skill acquisition</a> is another representative model that looks the same. Musashi&rsquo;s studying day and night manifests itself into learning 10.000 hours or roughly 10 years <strong>but with deliberate practice</strong>, not doing the same 10 years over again and again. Otherwise you will be stuck in the Shu step. Dreyfus' master level states:</p>
<blockquote>
<p>transcends reliance on rules, guidelines, and maxims</p>
</blockquote>
<p>Which is exactly what Ri means. The problem with masters is that it&rsquo;s very difficult for them to translate intuition into simple easy-to-digest rules for newcomers to the craft, as they are still stuck in the beginning of Shu. I like to have some context when starting out something new like drawing, not someone who says to me I should wax on and off without the why. But then again, I&rsquo;m not Japanese and I&rsquo;m very familiar with learning how to learn.</p>
<p>Musashi wrote down the rules for people who wish to study his martial arts, and I like the conciseness:</p>
<ol>
<li>Think about what&rsquo;s right and wrong.</li>
<li>Practice and develop.</li>
<li>Meet other general arts.</li>
<li>Know the basic principles of the crafts.</li>
<li>Understand the advantages and disadvantages of everything.</li>
<li>Study everything accurately.</li>
<li>Become aware of what is not obvious.</li>
<li>Give attention to small things.</li>
<li>Don&rsquo;t do useless things.</li>
</ol>
<h3 id="focusing">Focusing</h3>
<p>Both Musashi and Munenori talk about <strong>the rhythm</strong> in martial arts. Let&rsquo;s quote Miyamoto:</p>
<blockquote>
<p>Rhythm is something that occurs everywhere but are difficult to follow without practice. The rhythm is reflected in things. These are all harmonic rhythms.</p>
</blockquote>
<p>One has to study hard in order to learn to recognize the different rhythms - of enemy movement, of foot work, of anything. Rhythm is about <strong>reacting to the present</strong> and nothing more. It reminded me of <a href="https://zenhabits.net/focus-book/">Leo Babauta&rsquo;s Focus</a>. It of course touches on Buddhism. In essence, seeing the rhythm requires you to be present in the very moment and to ignore everything else. Only then you can react fast enough to the position of your enemy&rsquo;s sword.</p>
<p>If I think about software engineering, I can acknowledge that focusing (on one task) is a very important skill that requires a lot of discipline (let&rsquo;s call it willpower). If I do not have the strength to focus on one thing, a couple of problems usually occur:</p>
<ul>
<li>I cannot relate to any problem I&rsquo;ve solved before to be able to match this one. Pattern matching is extremely important in software development, as in martial arts: recognizing movement, reacting accordingly.</li>
<li>I cannot fix one thing and move on, but I keep on seeing things that have to be improved upon. I&rsquo;ll start <a href="https://www.techopedia.com/definition/15511/yak-shaving">shaving a yak</a>.</li>
<li>Most importantly, I cannot learn actively and thus will never move up from shu all the way to ri.</li>
</ul>
<h3 id="contemplating">Contemplating</h3>
<blockquote>
<p>Understand the advantages and disadvantages of everything.</p>
</blockquote>
<p>In order to move from Ha to Ri, you must not only practice a lot but also understand the why and the how. Yagyū Munenori calls it <strong>seeing the possibilities and intentions</strong>. There are maybe a hundred sword positions but only one will help you win. After learning something, contemplating on what you&rsquo;ve learned allows you to unlock it&rsquo;s greater potential. Plato and Aristotle were great Western thinkers and share this vision with their Eastern counterparts. Especially Yagyū talks a lot about the like mindedness of buddhism and martial arts.</p>
<p>One thing that struck me: masters in martial arts usually became priests after their bloody careers. Warriors seek advice in deeper understanding of everything and they find it with buddhism masters. The greatest export product of Japan is not the dazzling skill of the sword from masters like Musashi, but the enlightening mindset of zen. Why else would a warrior seek advice with a monk, and not a monk seek advice with a warrior? Why else would masters like Yagyū Munenori keep on making comparisons between martial arts and zen?</p>
<p>I am convinced that in order for you to get your skill level to the next level, you must contemplate on what you have learned. Stop practicing and developing (rule #2) and don&rsquo;t forget understanding (rule #5) and becoming aware (rule #7). Of course all those rules are intertwined within another.</p>
<blockquote>
<p>One cannot be a devoted master in the arts as long as one is attached to his different skills.</p>
</blockquote>
<p>
By <a href="/about">Wouter Groeneveld</a> on 20 June 2017.
</p>
]]>
</description>
</item>
<item>
<title>Development principles in cooking</title>
<link>https://brainbaking.com/post/2017/06/development-principles-in-cooking/</link>
<comments>https://brainbaking.com/post/2017/06/development-principles-in-cooking/#commento</comments>
<pubDate>Fri, 09 Jun 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/06/development-principles-in-cooking/</guid>
<category domain="https://brainbaking.com/tags/cooking">cooking</category>
<category domain="https://brainbaking.com/tags/development">development</category>
<category domain="https://brainbaking.com/tags/principles">principles</category>
<description>
<![CDATA[
<p>A lot of people seem to think I&rsquo;m the kind of chef who uses loads and loads of ingredients, combining and layering without thinking twice. We were having a discussion about what to cook for dinner this evening. It&rsquo;s <a href="http://www.evavzw.be/donderdag-veggiedag">&lsquo;donderdag veggiedag&rsquo;</a>, an initiative from the Belgian EVA VZW to eat a vegetarian meal each thursday, and since I&rsquo;m a vegetarian, it&rsquo;s generally accepted that I should know a lot of good recipes.</p>
<blockquote>
<p>Friend: &ldquo;So, what&rsquo;s for dinner today, something veggie?&quot;<br/>
Me &ldquo;Uhm, act-&quot;<br/>
Friend: &ldquo;Nevermind, you always cook super complicated stuff, right, I can&rsquo;t do that.&quot;<br/>
(conversation continues about something else)</p>
</blockquote>
<p>That got me thinking. Do I think of myself as a &lsquo;complicated&rsquo; chef (sounds cooler than cook)?</p>
<h2 id="complex-to-simple">Complex to simple</h2>
<p>The answer is: I don&rsquo;t. I think I used to. When I started cooking for myself 10 years ago, I did my best to live up to my father&rsquo;s expectations to prepare intricate meals with lots of different steps to prepare. But as I had no idea what I was doing, I continually failed at creating something decent. I did not hesitate to create my own Thai curry paste, without even knowing what the required ingredients where. I bought a bag of 2 kilo dried hot peppers from the local asian market without even knowing I would ever use 4 of those peppers. I read and loved cookbooks like Yottam Ottolenghi&rsquo;s <a href="https://www.goodreads.com/book/show/8086216-plenty?ac=1&amp;from_search=true">Plenty</a> but couldn&rsquo;t keep up with the staggering amount of fresh herbs required for each recipe.</p>
<p>Years passed. My cooking behaviour changed. I started to get the hang of it. I learned to learn about cooking, the <strong>meta-cooking</strong>, the &lsquo;deep stuff&rsquo;. I got into fermenting, creating simple things myself, creating everything myself and knowing what I&rsquo;m doing and why I&rsquo;m doing it. I started being addicted to food related (the why) books and stopped reading cookbooks (the how).</p>
<p>So, my style evolved, as it usually does when you&rsquo;re doing something for quite some time with <strong>deliberate practice</strong>, with <strong>attention to detail</strong>.
Today, after that weird discussion ending, it actually hit me: you can apply several software development principles to (my) cooking style(s).</p>
<h3 id="kiss-keep-it-simple-stupid">KISS: Keep It Simple, Stupid!</h3>
<p>Instead of throwing every herb and spice you have at something, be more picky. Think about what will go well with that one ingredient. Is pepper really needed here? Should you even add cheese, doesn&rsquo;t that hide the taste of your main ingredient? <strong>Keep it simple</strong>.</p>
<p>I made something really simple for dinner: tortilla&rsquo;s. That would require something nice spreadable and some topping. I bought some local (another thing to focus on) buffalo mozzarella from the Ardennes and still had a cooked beetroot. BAM.</p>
<p>Well, not really. I added a fermented shallot to create a sour tang and - of course - some salt. Because it had to be spreadable and because I happen to love olive oil, that was also added.</p>
<p><figure>
<a href="/img/yagni1.png" class="lbox">
<img loading="lazy" src="/img/yagni1.png" alt="YAGNI" >
</a>
</figure>
</p>
<p>Three ingredients. (Salt and oil doesn&rsquo;t count as an ingredient in my kitchen)
That&rsquo;s it.</p>
<p>Okay, I&rsquo;m lying, fermenting a shallot requires a week of undevoted attention. (It actually does not&hellip;) I like <strong>layering simple things</strong> to create something complex, but still in essence, simple.</p>
<p>I made something really simple this morning: a REST API. <br/>
I made something really simple this evening: a beetroot spread.</p>
<p><strong>You Aint Gonna Need It</strong> (YAGNI) is a variant of KISS. You won&rsquo;t be needing those nuts in a pesto if you&rsquo;re using a lot in pasta, you won&rsquo;t taste that anyway combined with the hard cheese. I&rsquo;ve found it a lot better if you toast the nuts whole and add them to the meal as a finisher, instead of grinding them in the pesto. Leave out the nuts when making a pesto as pizza base, that&rsquo;s going to be expensive and you won&rsquo;t be tasting it.</p>
<p>Less is more, right?</p>
<h3 id="dry-dont-repeat-yourself">DRY: Don&rsquo;t Repeat Yourself!</h3>
<p>Using a lot of the same tasting ingredients can ruin the whole meal. Simple examples are something too sour (lemon and too much acidity) or too sweet (strawberries with honey and sugar). Of course, fervent sweet lovers will disagree on this one. But it&rsquo;s a handy rule when combining ingredients.</p>
<p>Don&rsquo;t add too much vinegar and a lot of lemon.<br/>
Don&rsquo;t add loads of pepper combined with chilli.</p>
<p>Peter Reinhart&rsquo;s sacred <a href="https://www.goodreads.com/book/show/68648.American_Pie?ac=1&amp;from_search=true">Quest for the Best pizza</a> let him to believe you should use a very limited amount of core ingredients on your pizza, let&rsquo;s say 4. You can include the sauce as one of those ingredients, or not - that&rsquo;s up to you. But don&rsquo;t exceed that number or you risk the chance of tasting &ldquo;pizza&rdquo; in general and not &ldquo;smoked bell pepper&rdquo; and &ldquo;mozzarella&rdquo;. I used to throw as much stuff on the pizza base as I could - one wouldn&rsquo;t want to be hungry afterwards, right? The crust couldn&rsquo;t even get baked well because of all the moisture.</p>
<p>I think you can extrapolate any general programming principle to cooking principles if you&rsquo;re a bit creative.</p>
<p>That said, I still don&rsquo;t have a clue of what I&rsquo;m doing when cooking because each time you try to create something, you end up with something else but you&rsquo;ve also been on a journey. <a href="http://mobile.seriouseats.com/2011/10/the-food-lab-the-science-of-risotto.html">Food Lab</a> might help me create a better risotto but in the end you&rsquo;re the one who has to buy and cook the rice&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 9 June 2017.
</p>
]]>
</description>
</item>
<item>
<title>Are you handing over enough when inspiring someone?</title>
<link>https://brainbaking.com/post/2017/05/handing-over-enough-when-inspiring/</link>
<comments>https://brainbaking.com/post/2017/05/handing-over-enough-when-inspiring/#commento</comments>
<pubDate>Tue, 30 May 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/05/handing-over-enough-when-inspiring/</guid>
<category domain="https://brainbaking.com/tags/inspiring">inspiring</category>
<category domain="https://brainbaking.com/tags/giving">giving</category>
<description>
<![CDATA[
<p>The other day, I was having a discussion with a friend and colleague about reaching out to others. He had an idea on combining patterns learned from the enterprise software development world (clean code, TDD, domain driven design, you name it) with patterns learned from the gaming development world (rapid prototyping, getting stuff done, intensive usage of frameworks like Unity). An excellent idea if you ask me. But he was hesitant - others might not be that interested in taking time to write unit tests in their game.</p>
<p>That&rsquo;s called an assumption. So I proposed to write small blog posts in <a href="https://gohugo.io/">hugo</a> using Markdown and GitHub pages. Very lightweight, only one command away from generating concise entries. This might take 10 minutes of your time per week.
So he nodded. &ldquo;Hm-hmm&rdquo;. And we started talking about something else.</p>
<p>At that point I had two choices:</p>
<ol>
<li>Interrupt the conversation and push further.</li>
<li>Ignore it for now and take a mental note do do something with it later.</li>
</ol>
<p>Often enough I&rsquo;ve hit a brick wall with option one. It&rsquo;s annoying for the other person to constantly be interrupted and I wouldn&rsquo;t make myself very popular. I do have that nasty habit and I&rsquo;m working on that.
But let&rsquo;s return to option two for now.</p>
<p>I forgot about the discussion and moved on.
But taking mental notes is like async AJAX calls: they do return, but you don&rsquo;t know when. That&rsquo;s when it hit me: why don&rsquo;t I email him some details on how to quickly start a blog? Would that be appropriate or not? In any case he&rsquo;s free to delete the email - no harm done. But if he decides to do something with it, all the better. The step from no blog and no experience in Hugo is smaller when a friendly push in the right direction has been given.</p>
<p><figure>
<a href="/img/sharing.png" class="lbox">
<img loading="lazy" src="/img/sharing.png" alt="giving" >
</a>
</figure>
</p>
<p>One could say &ldquo;what have you to gain? Why do you care?&rdquo; And I don&rsquo;t - I&rsquo;m not a game developer, but I do care - a bit - about the subject. I do care - a lot - about my friend and his personal growth. <a href="/post/teaching-kids-how-to-program/">Show your work</a>, remember?
I love to inspire others on things that I&rsquo;m passionate about myself. And sharing is caring. I would love to receive an email with loose ends like this from someone I talked to.</p>
<p>So my decision to throw some info over the wall has been made. I&rsquo;m eager to find out if the seed has been planted and nurtured. We&rsquo;ll have to see. I will not be disappointed if it has not - giving and expecting something in return is not giving. I love giving. Altruism must have originated from the egocentric self, some believe. I would not count myself to be part of that group.
The Japanese encounter a lot of stress if they are given a gift: it has to be matched in value to give something back which has the same value: not less (shame) or more. It&rsquo;s like trying to buy presents for your family at Christmas: a sometimes horrifying experience. You do not know the value of the gift you&rsquo;ll be given and you&rsquo;ll have to guess how much to spend to give.</p>
<p>Of course, handing out information - which should be free in the first place - is not the same as handing out something physical.</p>
<p><a href="http://www.rd.com/true-stories/inspiring/5-stories-that-celebrate-the-spirit-of-giving/">True giving</a> is expecting nothing in return.
<a href="https://www.themindfulword.org/2014/joy-of-giving/">True giving</a> is wanting nothing in return!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 30 May 2017.
</p>
]]>
</description>
</item>
<item>
<title>How to teach kids to program</title>
<link>https://brainbaking.com/post/2017/05/teaching-kids-how-to-program/</link>
<comments>https://brainbaking.com/post/2017/05/teaching-kids-how-to-program/#commento</comments>
<pubDate>Thu, 25 May 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/05/teaching-kids-how-to-program/</guid>
<category domain="https://brainbaking.com/tags/techorama">techorama</category>
<description>
<![CDATA[
<p>Jessica Ellis gave a lot of great tips on how to teach kids to program at <a href="https://techorama2017.sched.com/event/9M8g/the-skills-gap-how-to-inspire-our-kids-to-study-computer-science?iframe=no&amp;w=100%25&amp;sidebar=yes&amp;bg=no">Techorama 2017</a> in Antwerp. She has ben an active teacher in the <a href="http://tkplabs.org">tkplabs.org</a> society and introduced something clever called &ldquo;barbecoding&rdquo;. In an attempt to create an appealing programming camp for boys and girls, she successfully combined food and science. She shared her story in an hour and I did my best to extract the most important principles as I thought it might be a great idea to apply that to our team in my daily work as a software developer.</p>
<p>Why would those principles only apply to kids?</p>
<h3 id="1-do-hard-things-and-have-food">1. Do Hard Things (and have food)</h3>
<p>Don&rsquo;t treat people as you categorize them. Do hard things, even if you think they are not capable of doing something like that. Don&rsquo;t label them as &ldquo;smart&rdquo; - the brain will become wired for failure and they&rsquo;ll be scared to make mistakes.
The food part is especially interesting as I&rsquo;ve read in some management book years ago one concept called <strong>&ldquo;do food&rdquo;</strong>. Bring (home made) food to a meeting - it immediately breaks all ice, effectively. Since then, I constantly rely on homemade cakecups to ease other&rsquo;s minds. It really does work and it&rsquo;s a lot of fun to make.</p>
<h3 id="2-work-in-a-group-failing-in-a-group--failing-alone">2 Work in a group (failing in a group &gt; failing alone)</h3>
<p>Pairing and mob programming can be done with kids and enables them to learn faster (from each other instead of only from the teacher or themselves). It&rsquo;s also less bad to try and fail: at least you&rsquo;ve failed together then.
I successfully used mob programming as a teaching instrument at work. It makes the problem less daunting for someone who isn&rsquo;t eager to speak for a group.</p>
<h3 id="3-be-surprised-laugh-a-lot">3 Be Surprised (laugh a lot)</h3>
<p>Life is full of surprises. Be genuine.
Stop taking everythig seriously. Something I love to do: inspire others to laugh more - at themselves, at me, at the situation we&rsquo;re in. And then get to work.</p>
<h3 id="4-feel-powerful-never-say-you-cant-do-anything">4. Feel Powerful (never say you can&rsquo;t do anything)</h3>
<p>This is extremely difficult for grownups and I still can&rsquo;t wrap my head around the why. &ldquo;Oh but I can&rsquo;t do it as good as you&rdquo; or &ldquo;you are the expert, I wouldn&rsquo;t be able to do such a thing&rdquo; or &ldquo;no, I can&rsquo;t do that, I&rsquo;m not smart enough&rdquo; are sentences I hear on the workfloor every single day. And that&rsquo;s very very saddening because I&rsquo;m not smarter than anyone else - in fact, I&rsquo;m convinced I know less than they do - I just manage to get away with it.</p>
<p>Recognizing talent and mentoring them to become teachers themselves is something I have to do more often - that means less work for me.</p>
<h3 id="5-show-your-work">5. Show Your Work</h3>
<p>Reminded me of Austin Kleon&rsquo;s <a href="http://austinkleon.com/show-your-work/">show your work</a> - a lovely book that inspires to put stuff out there, like this very blog or my &ldquo;bad&rdquo; drawings. I love to show my work, but grownups tend to think someone shows their work because he or she wants everyone to know how great they are.
Maybe. But foremost, they might want feedback. And get better. And that means, they need your help. So stop that train of negative thinking and start helping. Stop saying &ldquo;my work is redundant, it&rsquo;s nothing, it&rsquo;s not showable, nobody would like it&rdquo; and start putting stuff out there.</p>
<h3 id="6-unplug--learn-without-a-computer">6. Unplug &amp; learn without a computer</h3>
<p>Computational thinking can also be learned with the help of post-its, some yarn, a thread and some markers. Your cognitive process picks up things a lot faster if your body is <strong>doing stuff</strong> instead of yawning at a computer screen. Get up and move. Pair more strictly: set a timer and require everyone to physically move.</p>
<p>It was very inspiring to see what Jessica and her team of teachers (15 year olds by the way!) managed to do. I know I&rsquo;ll be trying to incorporate the rules stated above in my daily work, even if I&rsquo;m not directly working with kids.</p>
<p>Or maybe I am&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 25 May 2017.
</p>
]]>
</description>
</item>
<item>
<title>Teaching yourself to draw</title>
<link>https://brainbaking.com/post/2017/02/teaching-yourself-to-draw/</link>
<comments>https://brainbaking.com/post/2017/02/teaching-yourself-to-draw/#commento</comments>
<pubDate>Wed, 01 Feb 2017 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/02/teaching-yourself-to-draw/</guid>
<description>
<![CDATA[
<p>Inspired by Noah Bradley&rsquo;s <a href="https://medium.com/i-m-h-o/dont-go-to-art-school-138c5efd45e9#.aul09q3wr">Don&rsquo;t go to art school</a> blog at Medium.com.</p>
<p>Drawing and art in general has always been something I didn&rsquo;t quite grasp or try to understand. I was a software development guy, a technical guy, used to writing code, looking at text, spending days and years in text editors others call IDE&rsquo;s. Software development and art aren&rsquo;t that different actually: they both require an open mindset and an extreme creative approach at solving problems. That&rsquo;s one of the reasons I became interested in drawing.
Another is to get some color into my journals. I&rsquo;ve been journaling for about 7 years now and it&rsquo;s been my most important tool in life. It helps me understand myself, collect and execute ideas and to keep the chaos in the world and my mind contained. Writing pages isn&rsquo;t a problem, doodling either, but the page never really pops. Sketching is something I like to do now and then but after hearing things like &ldquo;you can&rsquo;t draw at all!&rdquo; my motivation completely disappears.</p>
<h3 id="how-to-really-master-a-skillhttpwwwmakeuseofcomtag10000-hour-rule-wrong-really-master-skill"><a href="http://www.makeuseof.com/tag/10000-hour-rule-wrong-really-master-skill/">How to really master a skill</a>?</h3>
<ul>
<li>Deliberate practice</li>
<li>Getting down the pyramid chain: <br/>teaching &gt; practicing &gt; group discussion &gt; reading &gt; lecture</li>
<li>&ldquo;10.000 hours&rdquo; (it&rsquo;s an average, I know)</li>
<li>Quantify yourself by using a <strong>feedback loop</strong></li>
</ul>
<h3 id="my-feedback-loop-is-this-very-blog">My Feedback loop is this very blog.</h3>
<p>It should be that simple. I intent to learn to draw within a year, without enrolling in a traditional school. To be successful, I will turn to books, online courses, experts in art by visiting expo&rsquo;s/museums, experts in art by going to short term workshops, and above all: by lot&rsquo;s of practicing. Noah states that $10k could be spent wisely within one year. I have no idea how much it will cost me but my intention is to keep it as low as possible.</p>
<p>Each learning &lsquo;session&rsquo; will be another blog post. I have a general idea on what I like (ink, watercolor, anything physical, journals) and what I don&rsquo;t like (acrylic paint, anything digital) but since there is so much I don&rsquo;t know, this might change during the course of the coming year. Since Pinterest is so inspiring I&rsquo;d like to upload as much of the artwork as possible. Sharing via pins makes it easier for people to try it themselves.</p>
<p>Take a look at my Pinterest profile by clicking on the icon on the bottom of the page.
If you&rsquo;re looking for all blog posts about learning to draw, check out the <strong>'<a href="/tags/teaching-yourself-to-draw/">Teaching yourself to draw</a>' tag</strong>.</p>
<p>Are you familiar with the frustrated feeling you get while visting an art supply store and staring at all the equipment but having no idea what does what? That&rsquo;s me. So, I figured&hellip;</p>
<h3 id="start-with-the-beginning">Start with the beginning.</h3>
<p><a href="http://snow-and-rose.com/nl/workshop/">Snow&amp;Rose workshop: Illustrative techniques</a> was my entrypoint. It&rsquo;s a 10-week (once a week) workshop to cover the basics of drawing illustrative creatures, flowers, landscape, anything. No realistic drawing, no up-front knowledge required and each week it covers another medium:</p>
<ol>
<li>charcoal and pencil</li>
<li>bistre, reedpen</li>
<li>pastel</li>
<li>aquarel</li>
<li>acrylic paint</li>
<li>aquarellable colorpencils</li>
<li>ecoline</li>
<li>ink with fineliners</li>
<li>collage/scrapbooking</li>
<li>mixed media</li>
</ol>
<p>Price is 390 EUR. As it&rsquo;s only once a week, it creates the perfect opportunity for me to practice drawing &ldquo;stuff&rdquo; between the lessons and to experiment a bit with the different mediums.</p>
<p>These are some christmas-themed cards I made with cheap pastels during the third lesson:</p>
<p><a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749442493529/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749442493506/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749442493510/" target="_blank" title="Pinterest pin"></a>
</p>
<p>It starts out very simple, as you can see. I&rsquo;m still having difficulties buying the right equipment. The pastels used above are very hard and grainy, and don&rsquo;t contain a lot of pigment. That is clearly visible in the gameboy one on the far left: the brown paper shouldn&rsquo;t be that visible. Small steps, small steps&hellip;</p>
<h3 id="but-i-suck-at-drawing">But I suck at drawing!</h3>
<p>So do I.</p>
<p>Each week (this sounds like a promise I&rsquo;ll have to make to myself) I&rsquo;ll post a new blog post summarizing what I&rsquo;ve learned about drawing, art ant painting. Hopefully, after 52 posts, others who are thinking about making the step won&rsquo;t be that intimidated as I am right now. I&rsquo;ve already felt that looking too much at work of others (in Pinterest for example) completely demotivates me. You&rsquo;ll always find someone who completely outperforms you. It&rsquo;s not about their work, it&rsquo;s about your own, and <strong>the progress you make</strong>, however small that might be. If it&rsquo;s going forward, it&rsquo;s going forward. There is no hardwired limit on where to go to. Let&rsquo;s just keep on trying, failing, getting up and trying again! It looks like 2017 is going to be an interesting year for me.</p>
<h3 id="week-1">Week 1</h3>
<p>As you might already have read, I started the drawing adventure with a 10-week &lsquo;illustrative techniques&rsquo; course. It sounds complicated but it wasn&rsquo;t really: it&rsquo;s more of a gentle introduction in different mediums (pencil, ink, acrylic paint, &hellip;) than a crash course in drawing techniques. I didn&rsquo;t know then that to draw illustrations, you still have to be able to draw. (I&rsquo;m reading &ldquo;drawing at the right side of the brain&rdquo; and I know better now). But still, thse drawings might be fun to look at or to compare to the other weeks.</p>
<p><a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749443972926/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749443972958/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749443972977/" target="_blank" title="Pinterest pin"></a>
</p>
<p>These are all random drawings I did between the lessons to get myself familiar with a pencil. That sounds awful, doesn&rsquo;t it? Who uses pencils anyway. The left scan contains some color: that&rsquo;s an experiment. The brown is <strong>bistre</strong>, something we had to work with in the second class. The other colors are very cheap <strong>pastels</strong>.</p>
<p>So, what did I learn this week:</p>
<ol>
<li>Bistre can be a bit of a mess. You absolutely cannot wait, edges will form and it&rsquo;ll be worse than watercolor.</li>
<li>Expensive tools <strong>are</strong> better than cheap ones. Pastels are softer and contain a lot more pigment than the ones you can find in sale bins.</li>
<li>I know the difference between a <strong>HB</strong> and a <strong>B4</strong> pencil. I know how to sharpen one. Yay.</li>
<li>These drawings look like doodles because they are a lot like doodles. I like drawing that but I have the feeling I&rsquo;m missing a lot background info (will be continued&hellip;)</li>
<li>Patience looks like an important skill to aid me in learning how to draw.</li>
<li><strong>Do not look at the work of others!</strong></li>
</ol>
<p>I warned you:</p>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/568720259163636687/" target="_blank" title="Pinterest pin"></a>
<p>This also is bistre.
Ouch.</p>
<h2 id="week-2">Week 2</h2>
<p>After the illustration course, I&rsquo;m not ashamed to admit I completely dropped the pencil out of the game. It creates lines easy to remove and that means I&rsquo;m working on a drawing forever. I need something to commit myself to. That something is called ink.</p>
<p>It also seems that I already have stuff to get ink on a paper: pens. Ballpoint pens. Black, blue, whatever. Just simple pens you use to write with - the cheaper, the better. I came across <strong>Danny Gregory</strong>&rsquo;s work <a href="https://dannygregorysblog.com/books/art-before-breakfast/">Art before breakfast</a> and <a href="http://www.dannygregory.com/author">The Creative Licence</a> (buy the latter one if you can). These are very inspirational books that get you kickstarted drawing from zero by learning how to see, explaning negative space and other simple techniques. It doesn&rsquo;t go into detail, it simply helps you get drawing.</p>
<p>And Danny is a fan of ink + watercolor. I immediately fell in love and knew that was what I wanted. So yes, put that pencil back where it belongs. I started trying to draw what I see:</p>
<p><a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749443972993/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749443973015/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749443973029/" target="_blank" title="Pinterest pin"></a>
</p>
<p>It looks a lot brighter than <a href="/post/drawing-week-01">week 1</a>. After drawing with a pen a few times, it felt better and better. I tried to copy Danny&rsquo;s style a bit by giving it some (water)color but that might be too much new stuff within a few weeks.</p>
<p>I&rsquo;m particulary fond of the yellow post-it note: an impression of my left foot while waiting for my wife to finish shopping. I keep pen &amp; paper with me at all times: that&rsquo;s a healthy habit I developed 7 years ago when starting journaling.
The first foot trace was a complete disaster by the way.</p>
<p>So, what did I learn this week:</p>
<ol>
<li>Pen &gt; pencil.</li>
<li>Danny Gregory rocks. He has tons of books and is co-founder of the <a href="http://sketchbookskool.com/">Sketchbook Skool</a>. Once I knew that, I enrolled in the &ldquo;beginning&rdquo; kourse.</li>
<li>I like sketching more than doodling.</li>
<li>&ldquo;Seeing&rdquo; is incredibly hard: I constantly mess up proportions.</li>
<li>Adding watercolor seems to add a lot of dimension.</li>
</ol>
<p>Let&rsquo;s take a look at what Danny does:</p>
<p><a data-pin-do="embedPin" href="https://www.pinterest.com/pin/381609768399365667/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/233976143118067754/" target="_blank" title="Pinterest pin"></a>
</p>
<p>Awesome.</p>
<h2 id="week-3">Week 3</h2>
<p>I wanted to continue my quest of finding my own style within ink and watercolor boundaries. After the amazing discovery of <a href="https://www.skillshare.com">Skillshare.com</a>, I switched to using Artline fineliners. I also have some Steadlers but hardly notice any difference between different felt tip pens if they have the same thickness. I found a short course by Shirish Deshpande on drawing with ink and creating some contrast and texture. The drawings in the videos are amazing and I tried to copy them to my best abilities:</p>
<p><a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749443973054/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749443973073/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749443973094/" target="_blank" title="Pinterest pin"></a>
</p>
<p>The ink flowing from a technical pen is much more intense than a standard ballpoint pen as seen in <a href="/post/drawing-week-02">week 2</a>. I like that a lot. It also enables me to be much more precise and that is something that I tend to do a lot. I usually draw (too) small and try to cram in as much details as possible. The thinner the felt tip pen, the better for me. (Although I borked a 005 one, those guys are very sensitive!).</p>
<p>During the snow &amp; rose course, the lesson with the fineliners suited me the most, and now I have that same feeling. I finally give (cross-)hatching a shot and it really looks a lot better. Thanks Shirish, for building up my confidence in drawing with ink!</p>
<p>So, what did I learn this week:</p>
<ol>
<li>Intensity of ink matters.</li>
<li>Contrast is extermely important and gives your drawing an &ldquo;oomph&rdquo;</li>
<li>I learned the &ldquo;hatching&rdquo;, &ldquo;stipling&rdquo;, and &ldquo;random&rdquo; technique.</li>
<li>Fineliners &gt; ballpoint pens &gt; pencils (sensing a trend here, fountain pen coming up)</li>
</ol>
<p>Let&rsquo;s take a look at what Shirish does with his pens (and added colored ink):</p>
<p><a data-pin-do="embedPin" href="https://www.pinterest.com/pin/394698354817739793/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/364299057333088725/" target="_blank" title="Pinterest pin"></a>
</p>
<p>He usually doesn&rsquo;t color with watercolor but with (diluted) colored ink. I have yet to try that.</p>
<h2 id="week-4">Week 4</h2>
<p>As I&rsquo;m slowly getting a tiny bit better at drawing things I see, I still don&rsquo;t have a fundamental basis to rely on. Until I&rsquo;ve read &ldquo;<a href="http://drawright.com/">Drawing at the right side of the brian</a>&rdquo; from Betty Edwards. Everything I&rsquo;ve read in there came as a complete revelation to me. She explains how you should &ldquo;look&rdquo; at things, what is important to look out for when realisticly drawing and how values/tones work. It&rsquo;s an amazing book and I&rsquo;m very glad I&rsquo;ve added it to my toread list (a few years ago, I finally got around to actually reading it.)</p>
<p>Can you spot the difference between the portraits below?</p>
<p><a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749447642788/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749447642793/" target="_blank" title="Pinterest pin"></a>
</p>
<p>Yes, I am well aware that the second portrait still looks like crap but come on, at least it shows highlights, it has a decent contour and my skull isn&rsquo;t &ldquo;chopped off&rdquo;. Both drawings took me 45 minutes. I&rsquo;d say that&rsquo;s a definitive improvement here.</p>
<p>Other exercises in the books concentrate on hands, interiour, chairs, &hellip;:</p>
<p><a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749447642796/" target="_blank" title="Pinterest pin"></a>
<a data-pin-do="embedPin" href="https://www.pinterest.com/pin/308707749447642801/" target="_blank" title="Pinterest pin"></a>
</p>
<p>Everything is done with a pencil. My preference is starting to lean towards 2B and 4B instead of HB.</p>
<p>So, what did I learn this week: (these are some quick oneliners that summarize each important chapter in the book)</p>
<ol>
<li>Draw (shared) edges of stuff: call them contours.</li>
<li>Draw spaces between stuff: call it negative space.</li>
<li>Draw relationships between stuff: call them angles and proportions.</li>
<li>Draw lights and shadows on stuff: call them tonal differences.</li>
<li>Do not draw the appearance of stuff: call it &ldquo;the gestalt&rdquo;.</li>
</ol>
<p>The last point is an interesting one. It&rsquo;s also called &ldquo;making it come together&rdquo; and is usually achieved by simply focusing on the other 4 points.</p>
<p>Doing these exercises gave me a real boost in confidence and motivated me to draw even more. I even started enjoying the use of a pencil - soft shading is nice and not doable with a pen!</p>
<p>Read more on how to draw better in Jen Review&rsquo;s <a href="https://www.jenreviews.com/how-to-draw-better/">How to Draw Better</a> blog post.</p>
<script async defer src="//assets.pinterest.com/js/pinit.js"></script>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 February 2017.
</p>
]]>
</description>
</item>
<item>
<title>Unit testing in Legacy Projects: VB6</title>
<link>https://brainbaking.com/post/2016/12/vb6-unit-testing/</link>
<comments>https://brainbaking.com/post/2016/12/vb6-unit-testing/#commento</comments>
<pubDate>Tue, 27 Dec 2016 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2016/12/vb6-unit-testing/</guid>
<category domain="https://brainbaking.com/tags/unit testing">unit testing</category>
<category domain="https://brainbaking.com/tags/VB6">VB6</category>
<description>
<![CDATA[
<p>Thanks to the <a href="https://ihadthisideaonce.com/2015/05/13/postmodern-vb6-a-quick-start-with-simplyvbunit/">Postmodern VB6</a> article I&rsquo;ve found on the internetz, I decided to give <a href="simplyvbunit.sourceforge.net">SimplyVBUnit</a> a try. My job requires sporadic visual basic 6 code changes in the big legacy project we&rsquo;re converting to C#. It&rsquo;s an administrative system bound to Belgium laws so as you can imagine they change every few months and the old software still has to be complaint to those crazy new rules. As a result, we sometimes dabble in VB6 code. It feels more like drowning, really.</p>
<p>Unit testing is what keeps me from rage-quitting on every project. The SimplyVBUnit syntax is quite nice if you&rsquo;re used to writing NUnit tests: they also work with <code>Assert.That</code> for instance:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-vb" data-lang="vb"><span style="color:#728e00">Public</span> <span style="color:#728e00">Sub</span> <span style="color:#d35400">MyTestMethod_WithSomeArg_ShouldReturn45</span>
<span style="color:#728e00">Dim</span> <span style="color:#434f54">isType</span> <span style="color:#728e00">As</span> <span style="color:#00979d">Boolean</span>
<span style="color:#434f54">isType</span> <span style="color:#728e00">=</span> <span style="color:#434f54">MyTestMethod</span>(<span style="color:#434f54">arg1</span>)
<span style="color:#434f54">Assert</span>.<span style="color:#434f54">That</span> <span style="color:#434f54">isType</span>, <span style="color:#434f54">Iz</span>.<span style="color:#434f54">EqualTo</span>(<span style="color:#434f54">45</span>)
<span style="color:#728e00">End</span> <span style="color:#728e00">Sub</span>
</code></pre></div><p><figure>
<a href="../simplyvbunit.png" class="lbox">
<img loading="lazy" src="../simplyvbunit.png" alt="simply vb unit screenshot" >
</a>
</figure>
</p>
<p>The test code is very readable thanks to the <a href="https://nunit.org/index.php?p=documentation">NUnit</a> influence on SimplyVBUnit. The package is very easy to install, but there are a few gotcha&rsquo;s.
You need to create a separate VBP file (Visual Basic Project) which acts as your UnitTest project with a reference to the SimplyVBUnit package. That&rsquo;s easy enough, but it&rsquo;s a project. That means it can&rsquo;t reference other projects! Our software is basically one large project with heaps of muddy code. Compiling the EXE and referencing that one is not an option for us. That leaves us with a few alternatives:</p>
<ul>
<li>Package the test runner and the dependency in your production code. (Hmmm&hellip;)</li>
<li>Create a DLL project and move the test code to the DLL. This requires another build step in our already-too-long-manual-deployment procedure. Nope.</li>
<li>Create a group (vbg), include both projects, and include modules/forms/class modules to be tested in the unit test project as an existing file. This means both projects will include the same source files. SourceSafe actually notices this if you have a file checked out and will ask you to update the &ldquo;other&rdquo; file in the second project.</li>
</ul>
<p>The group makes it possible to open everything at once. Unit tests live in a subfolder. This is our vbg file:</p>
<pre><code>VBGROUP 5.0
Project=program.vbp
StartupProject=UnitTests\UnitTests.vbp
</code></pre><p>Utilizing two projects in one group means switching between both as a startup project. One could use the group to develop and start tests but the vbps for debugging or so. It&rsquo;s all still fairly new for us so we&rsquo;ll see where this will end.
Unit tests are useless if they aren&rsquo;t run (automatically). At this moment we try to avoid coding anything in VB6 at all. If we do, we run the tests manually. At least some parts of the code are tested without bootstrapping the whole application and plowing through various forms to get to the part where you actually changed something&hellip;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 27 December 2016.
</p>
]]>
</description>
</item>
<item>
<title>Migrating from Extjs to React gradually</title>
<link>https://brainbaking.com/post/2016/01/react-in-extjs/</link>
<comments>https://brainbaking.com/post/2016/01/react-in-extjs/#commento</comments>
<pubDate>Tue, 26 Jan 2016 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2016/01/react-in-extjs/</guid>
<category domain="https://brainbaking.com/tags/javascript">javascript</category>
<category domain="https://brainbaking.com/tags/extjs">extjs</category>
<category domain="https://brainbaking.com/tags/react">react</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Migrating%20from%20Extjs%20to%20React%20gradually.jpg"/>
</p>
<p>We were looking for a few alternatives to our big ExtJS 4 application. Since it&rsquo;s not that easy to completely migrate from one front-end framework to the next, a possible solution would be to start developing new parts in another framework. There&rsquo;s a lot of domain logic spread in Ext views and controllers - which shouldn&rsquo;t be there, we are well aware of that. Let&rsquo;s call it &ldquo;legacy&rdquo; :-)</p>
<p>The application right now uses Extjs as UI and C# as backend, and lets ext do the loading of the views/controllers (living in app.js like most ext applications). There&rsquo;s no ecosystem set up like modern javascript applications - build systems like Grunt, Gulp, node package managers, Browserify, &hellip; are all not used. We do use sencha command to minify stuff. To be able to develop new modules without having to worry about extjs, one of the possibilities would be to use iframes. That enables us to (scenario) test the module using it&rsquo;s own routing. It&rsquo;s wrapped inside an Extjs view with an iframe:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#728e00">Ext</span>.<span style="color:#728e00">define</span>(<span style="color:#7f8c8d">&#39;App.view.utilities.desktop.ReactWindow&#39;</span>, {
<span style="color:#728e00">extend</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;Ext.form.Panel&#39;</span>,
<span style="color:#728e00">alias</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;widget.App_view_utilities_desktop_ReactWindow&#39;</span>,
<span style="color:#728e00">bodyPadding</span><span style="color:#728e00">:</span> <span style="color:#8a7b52">5</span>,
<span style="color:#728e00">width</span><span style="color:#728e00">:</span> <span style="color:#8a7b52">600</span>,
<span style="color:#728e00">layout</span><span style="color:#728e00">:</span> {
<span style="color:#728e00">type</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;vbox&#39;</span>,
<span style="color:#728e00">align</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;stretch&#39;</span>
},
<span style="color:#728e00">initComponent</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">me</span> <span style="color:#728e00">=</span> <span style="color:#728e00">this</span>;
<span style="color:#728e00">var</span> <span style="color:#728e00">dynamicPanel</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Ext</span>.<span style="color:#728e00">Component</span>({
<span style="color:#728e00">autoEl</span><span style="color:#728e00">:</span> {
<span style="color:#728e00">tag</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;iframe&#39;</span>,
<span style="color:#728e00">style</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;border: none&#39;</span>,
<span style="color:#728e00">src</span><span style="color:#728e00">:</span> <span style="color:#728e00">me</span>.<span style="color:#728e00">url</span>
},
<span style="color:#728e00">flex</span><span style="color:#728e00">:</span> <span style="color:#8a7b52">1</span>
});
<span style="color:#728e00">Ext</span>.<span style="color:#728e00">apply</span>(<span style="color:#728e00">me</span>, {
<span style="color:#728e00">title</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;React&#39;</span>,
<span style="color:#728e00">defaults</span><span style="color:#728e00">:</span> {
<span style="color:#728e00">labelWidth</span><span style="color:#728e00">:</span> <span style="color:#8a7b52">120</span>
},
<span style="color:#728e00">items</span><span style="color:#728e00">:</span> [<span style="color:#728e00">dynamicPanel</span>]
});
<span style="color:#728e00">me</span>.<span style="color:#728e00">callParent</span>();
}
});
</code></pre></div><p>When the module is triggered in the main app, we simply add the panel to the desktop:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#728e00">this</span>.<span style="color:#728e00">addPanel</span>(<span style="color:#728e00">Ext</span>.<span style="color:#728e00">create</span>(<span style="color:#7f8c8d">&#39;App.view.utilities.desktop.ReactWindow&#39;</span>, {
<span style="color:#728e00">url</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;react/mod/someurl/&#39;</span>
}));
</code></pre></div><p>Our app structure in the GUI folder would be something like this:</p>
<p>[GUI]<br/></p>
<ul>
<li>global.asax<br/></li>
<li>default.aspx<br/>
**** [app] -&gt; extjs<br/>
**** [react] -&gt; reactjs<br/></li>
</ul>
<p>That&rsquo;s simple enough. But how would one be able to open new Ext panels from within the React sub-application? That would be done via custom events thrown to the parent window. Catching these is just a matter of adding this to some controller in Extjs:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#728e00">window</span>.<span style="color:#728e00">addEventListener</span>(<span style="color:#7f8c8d">&#39;react&#39;</span>, <span style="color:#728e00">function</span>(<span style="color:#728e00">e</span>) {
<span style="color:#728e00">me</span>.<span style="color:#728e00">onReactEvent</span>(<span style="color:#728e00">e</span>.<span style="color:#728e00">detail</span>, <span style="color:#728e00">e</span>);
});
</code></pre></div><p>The <code>detail</code> property is part of a custom event, thrown in a react component. This below might be some cell component, taken from the <a href="https://facebook.github.io/fixed-data-table/">fixed-data-table</a> example:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#00979d">class</span> <span style="color:#728e00">MyLinkCell</span> <span style="color:#00979d">extends</span> <span style="color:#728e00">React</span>.<span style="color:#728e00">Component</span> {
<span style="color:#728e00">clicked</span>(<span style="color:#728e00">e</span>) {
<span style="color:#00979d">const</span> <span style="color:#728e00">el</span> <span style="color:#728e00">=</span> <span style="color:#728e00">e</span>.<span style="color:#728e00">target</span>;
<span style="color:#00979d">const</span> <span style="color:#728e00">eventObj</span> <span style="color:#728e00">=</span> {
<span style="color:#7f8c8d">&#39;detail&#39;</span><span style="color:#728e00">:</span> {
<span style="color:#7f8c8d">&#39;type&#39;</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;downloadlink&#39;</span>,
<span style="color:#7f8c8d">&#39;url&#39;</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;react/some/detail/url&#39;</span>
}
};
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#39;clicked - &#34;react&#34; event thrown:&#39;</span>);
<span style="color:#728e00">console</span>.<span style="color:#728e00">dir</span>(<span style="color:#728e00">eventObj</span>);
<span style="color:#728e00">if</span>(<span style="color:#728e00">window</span>.<span style="color:#728e00">parent</span>) {
<span style="color:#728e00">window</span>.<span style="color:#728e00">parent</span>.<span style="color:#728e00">dispatchEvent</span>(<span style="color:#728e00">new</span> <span style="color:#728e00">CustomEvent</span>(<span style="color:#7f8c8d">&#39;react&#39;</span>, <span style="color:#728e00">eventObj</span>));
}
}
<span style="color:#728e00">render</span>() {
<span style="color:#00979d">const</span> {<span style="color:#728e00">rowIndex</span>, <span style="color:#728e00">field</span>, <span style="color:#728e00">data</span>} <span style="color:#728e00">=</span> <span style="color:#728e00">this</span>.<span style="color:#728e00">props</span>;
<span style="color:#00979d">const</span> <span style="color:#728e00">link</span> <span style="color:#728e00">=</span> <span style="color:#728e00">data</span>[<span style="color:#728e00">rowIndex</span>][<span style="color:#728e00">field</span>];
<span style="color:#728e00">return</span> (
<span style="color:#728e00">&lt;</span><span style="color:#728e00">Cell</span><span style="color:#728e00">&gt;</span>
<span style="color:#728e00">&lt;</span><span style="color:#728e00">a</span> <span style="color:#728e00">onClick</span><span style="color:#728e00">=</span>{<span style="color:#728e00">this</span>.<span style="color:#728e00">clicked</span>} <span style="color:#728e00">href</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#39;#&#39;</span><span style="color:#728e00">&gt;</span>{<span style="color:#728e00">link</span>}<span style="color:#728e00">&lt;</span><span style="color:#a61717">/a&gt;</span>
<span style="color:#728e00">&lt;</span><span style="color:#a61717">/Cell&gt;</span>
);
}
}
</code></pre></div><p>Of course this is more or less the same when for instance using Angular2 instead of React, the custom event is part of the JS standard, see <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events">Creating and triggering events</a> from MDN.</p>
<p>To be able to use source maps in conjunction with Browserify/Watchify, I had to tweak some parameters in package.json: <code>watchify index.js --verbose -d -t babelify --sourceMapRelative . --outfile=bundle.js</code></p>
<p>Things we still need to research:</p>
<ul>
<li>How well does React compare to Angular2 in terms of components? For instance react doesn&rsquo;t include <a href="http://www.kriasoft.com/react-routing/">routing</a> by default. We&rsquo;ll need to rewrite some already-extjs-custom components in the target framework.</li>
<li>How should we include the build ecosystem (npm, gulp/grunt/browserify, &hellip;) into our C# build solution and Teamcity build? Will <a href="http://reactjs.net/">http://reactjs.net/</a> help for instance?</li>
<li>Can we use <a href="http://reactjs.net/">http://reactjs.net/</a> to render serverside components?</li>
<li>Which build tool should we use? We&rsquo;re being overwhelmed by choice: bower/npm as package manager, I&rsquo;ve seen stuff like <a href="http://www.christianalfoni.com/articles/2015_10_01_Taking-the-next-step-with-react-and-webpack">Webpack in conjunction with React</a>, &hellip; The list is huge if you&rsquo;ve not kept up with the JS technology news.</li>
</ul>
<p>One of the things we liked a lot was typescript or ES6 and the ability to use <code>=&gt; ()</code> and promises. Enabling this requires a transpiler or a polyfill like <a href="https://babeljs.io/">Babel JS</a>, but maybe this as a build step in sencha command will also ease some pain we&rsquo;re having with the current Ext code.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 26 January 2016.
</p>
]]>
</description>
</item>
<item>
<title>Webdriver Exception Handling</title>
<link>https://brainbaking.com/post/2015/01/webdriver-exception-handling/</link>
<comments>https://brainbaking.com/post/2015/01/webdriver-exception-handling/#commento</comments>
<pubDate>Wed, 14 Jan 2015 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2015/01/webdriver-exception-handling/</guid>
<category domain="https://brainbaking.com/tags/unit testing">unit testing</category>
<category domain="https://brainbaking.com/tags/CSharp">CSharp</category>
<category domain="https://brainbaking.com/tags/webdriver">webdriver</category>
<category domain="https://brainbaking.com/tags/scenario testing">scenario testing</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Webdriver%20Exception%20Handling.jpg"/>
</p>
<p>As the previous post indicated, we&rsquo;re trying to stabilize our scenario tests created with WebDriver. One of the things we did was trying to capture as much data as possible if something goes wrong. Something like a typical <code>ElementNotFoundException</code>, or the less common <code>StaleElementException</code> (detached from DOM after evaluation) - these things can be hard to trace if you don&rsquo;t run the tests locally. We also stumbled upon the &ldquo;it works on my machine&rdquo; problem - tests succeeding on one development machine but not on the other - mostly related due to timing issues.</p>
<p>So, what should you do when something goes wrong?</p>
<ul>
<li>capture what happened! (screenshot)</li>
<li>capture what happened! (exception stacktrace logging)</li>
<li>capture what happened! (serverside logging)</li>
</ul>
<p>WebDriver has a <code>GetScreenshot()</code> method you can use to dump an image to a file on exception. We used a bit of pointcut magic using PostSharp to automagically handle every exception without manually having to write each <code>try { }</code> clause.</p>
<pre><code> WebDriver().GetScreenshot().SaveAsFile(fileName + &quot;.png&quot;, ImageFormat.Png);
</code></pre>
<p>After saving the image, we also capture the exception and some extra serverside logging:</p>
<pre><code> File.WriteAllText(fileName + &quot;.txt&quot;,
&quot;-- Resolved URL: &quot; + ScenarioFixture.Instance.ResolveHostAndPort() + Environment.NewLine +
&quot;-- Actual URL: &quot; + ScenarioFixture.Instance.Driver.Url + Environment.NewLine +
&quot;-- Exception Message: &quot; + ex.Message + Environment.NewLine +
&quot;-- Stacktrace: &quot; + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine +
&quot;-- Service log: &quot; + Environment.NewLine + ReadServiceLogFromDeployedApp());
</code></pre>
<p>Because the webservice is deployed somewhere else (scenario tests run againsst the nightly build IIS webserver), we need to access the logfiles using a ´GET´ call, done with RestSharp:</p>
<pre><code> private static string ReadServiceLogFromDeployedApp()
{
var restClient = new RestClient(ScenarioFixture.Instance.ResolveHostAndPort());
var restRequest = new RestRequest(&quot;log/servicelog.txt&quot;);
restRequest.AddHeader(&quot;Content-Type&quot;, &quot;text/plain&quot;);
restRequest.AddHeader(&quot;Accept&quot;, &quot;text/plain&quot;);
var response = restClient.Execute(restRequest);
return response.Content;
}
</code></pre>
<p>Now, to easily access those files (the screenshot and the written log for each failing test), we wrap the exception in another exception containing a direct link to both files. That enables every developer to simply browse to the failing test on our CI env (teamcity) and simply click on the link!</p>
<p>To be able to do that, combined with the pointcut, implement the <code>OnException()</code> hook and call the above code:</p>
<pre><code>[Serializable]
[ScenarioExceptionAspect(AttributeExclude = true)]
public class ScenarioExceptionAspect : OnMethodBoundaryAspect
{
public override void OnException(MethodExecutionArgs args)
{
var exceptionFileName = Directory.GetCurrentDirectory() + @&quot;/&quot; + WebDriverExceptionHandler.Handle(args.Exception);
exceptionFileName = exceptionFileName.Replace(@&quot;C:&quot;, @&quot;file://teamcity/c$&quot;);
exceptionFileName = exceptionFileName.Replace(@&quot;\&quot;, @&quot;/&quot;);
throw new Exception(&quot;Scenario test failed&quot;
+ Environment.NewLine
+ &quot; -- Screenshot: &quot; + exceptionFileName + &quot;.png&quot;
+ Environment.NewLine
+ &quot; -- Log: &quot; + exceptionFileName + &quot;.txt&quot;, args.Exception);
}
}
</code></pre>
<p>This introduces one more problem: what if you want to trigger an exception, something like <code>ExpectedException(typeof(InvalidArgumentException))</code>? We&rsquo;ll still end up in our aspect and we&rsquo;ll take a screenshot and dump everything. We fixed this by taking a peek at the live stacktrace. I know it&rsquo;s far from ideal, but it serves it&rsquo;s purpose and works pretty well for the moment.</p>
<pre><code> private static bool ExpectedSomeException(StackTrace trace)
{
const int arbitraryMaxDepthToLookForAttribs = 5;
for (var stackElements = 1; stackElements &lt;= arbitraryMaxDepthToLookForAttribs; stackElements++)
{
if (AnyExpectedExceptionInAttribute(trace, stackElements))
{
return true;
}
}
return false;
}
private static bool AnyExpectedExceptionInAttribute(StackTrace trace, int stackElements)
{
var callingMethod = trace.GetFrame(stackElements).GetMethod();
var anyExpectedExceptionAttrib = callingMethod.GetCustomAttributes(typeof(ExpectedExceptionAttribute), true).Any();
return anyExpectedExceptionAttrib;
}
</code></pre>
<p>Every instance of a new <code>StackTrace</code> element will contain all stack data from that point on, so create one in the onException method, otherwise remember to look &ldquo;deeper&rdquo; or further into the stack itself. Yes we could solve that using recursion instead of with an arbitrary number of elements inside a for loop, but we were trying to solve something else and this stood in the way so naturally the reaction was to not invest too much time.</p>
<p>What&rsquo;s the outcome? This:</p>
<blockquote>
<p>Test(s) failed. System.Exception : Scenario test failed
&ndash; Screenshot: file://teamcity/c$/buildagents/buildAgentOne/work/10dbfc9caad025f8/Proj/ScenarioTests/bin/Debug/ex-15-01-14-15-56-02.png
&ndash; Log: file://teamcity/c$/buildagents/buildAgentOne/work/10dbfc9caad025f8/Proj/ScenarioTests/bin/Debug/ex-15-01-14-15-56-02.txt
&mdash;-&gt; System.Exception : Root menu could not be opened after 10 tries?
at Proj.ScenarioTests.ScenarioExceptionAspect.OnException(MethodExecutionArgs args) in c:\buildagents\buildAgentOne\work\10dbfc9caad025f8\Proj\Proj.ScenarioTests\ScenarioExceptionAttributeHandler.cs:line 36
&hellip;</p>
</blockquote>
<p>
By <a href="/about">Wouter Groeneveld</a> on 14 January 2015.
</p>
]]>
</description>
</item>
<item>
<title>Unit Testing Extjs UI with Siesta</title>
<link>https://brainbaking.com/post/2014/12/unit-testing-extjs-ui/</link>
<comments>https://brainbaking.com/post/2014/12/unit-testing-extjs-ui/#commento</comments>
<pubDate>Tue, 23 Dec 2014 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2014/12/unit-testing-extjs-ui/</guid>
<category domain="https://brainbaking.com/tags/unit testing">unit testing</category>
<category domain="https://brainbaking.com/tags/javascript">javascript</category>
<category domain="https://brainbaking.com/tags/extjs">extjs</category>
<category domain="https://brainbaking.com/tags/siesta">siesta</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Unit%20Testing%20Extjs%20UI%20with%20Siesta.jpg"/>
</p>
<h3 id="webdriver--js-heavy-frameworks">WebDriver &amp; js-heavy frameworks</h3>
<p>Writing scenario tests for javascript-heavy UI webpages can be really difficult. It gets complicated pretty quickly if you&rsquo;re using a lot of async calls or a lot of javascript-heavy UI components. On our current project, we use Extjs as the UI layer in a single-page aspx page to bootstrap our Extjs app. Extjs is a (heavyweight) javascript framework for creating windows, panels, grids, buttons, menus, &hellip; like you&rsquo;re used to when using client/server desktop applications. You define components on a view, behavior on a controller, and data and the way it&rsquo;s loaded on the model.</p>
<p>The problem with Javascript-heavy frameworks like this is that if your team does not have a lot of experience using JS in general, it can get extremely messy and cluttered. Which it did, coupled with a lot of regression (a misplaced &ldquo;;&rdquo; could break an entire part of the application), we needed an automated way to catch up with those bugs.
Since I have a lot of experience with WebDriver, we started using it to write scenario tests when the application is deployed. A test should emulate customer behavior: click on a menu, expect a window to be opened, fill in a form and expect something else to happen. It&rsquo;s not isolated but tests everything together.</p>
<p>WebDriver is great, but since a lot of javascript events are happening in the background it&rsquo;s very difficult to write a easily usable DSL to manipulate the UI. One has to wait for ajax calls to finish, for DOM elements to appear or disappear, and so on. Tests became instable and failed sometimes, even sometimes on the CI build but never on your development environment. It takes more and more time to find &amp; fix those things.</p>
<h3 id="a-possible-solution-siesta">A possible solution: Siesta</h3>
<p><a href="http://www.bryntum.com/products/siesta/">Siesta</a> is a product from Bryntum especially written to unit test Extjs applications, focussing on the UI. Sounds nice, so we decided to check it out as a possible alternative to WebDriver. As the website states:</p>
<blockquote>
<p>Siesta is a JavaScript unit testing tool that can help you test any JavaScript code and also perform testing of the DOM and simulate user interactions. The tool can be used together with any type of JavaScript codebase jQuery, Ext JS, NodeJS, Dojo, YUI etc. Using the API, you can choose from many types of assertions ranging from simple logical JS object</p>
</blockquote>
<p>Sounds good, right?</p>
<p>The setup isn&rsquo;t too difficult, after a few hours of fiddling I managed to bootstrap our Extjs application using this index.js file:</p>
<p>var Harness = Siesta.Harness.Browser.ExtJS;</p>
<pre><code> Harness.configure({
title : 'Test Suite',
loaderPath : {
'Ext': '../extjs',
'Ext.ux': '../extjs/ux',
'MyApp': '../app'
},
preload : [
// version of ExtJS used by your application
'../extjs/resources/css/ext-all.css',
'../resources/css/workb.css',
// version of ExtJS used by your application
'../extjs/ext-all-debug.js',
'./app-vars.js',
{
text: &quot;Ext.Loader.setConfig({ 'Ext': '../extjs', 'Ext.ux': '../extjs/ux', 'MyApp': '../app' })&quot;
},
'../extjs/overrides/javascript-overrides.js',
'../extjs/overrides/PFW-overrides.js',
'../app/app.js'
]
});
Harness.start(
'tests/001_sanity.t.js',
'tests/002_window.t.js'
);
</code></pre>
<p>Some pitfalls: <code>loaderPath</code> isn&rsquo;t evaluated in the preload so you have to reset it with <code>Ext.Loader.setConfig()</code> and I had to alter our app.js file. Our directory structure looks like this:</p>
<p>root
&ndash; app
&ndash; extjs
&mdash;- ux
&ndash; siesta
&mdash;- tests</p>
<p>So you have to watch out for relative paths like <code>appFolder</code> in app.js:</p>
<pre><code>Ext.application({
name: 'MyApp',
appFolder: (_siesta ? '../' : '') + 'app',
</code></pre>
<p>After that, you can start writing tests. Looking at the examples, the test flow looks a lot like our current WebDriver tests (wait for rows present, wait x seconds, click on this, do that). Here&rsquo;s a simple test to create a view and check if the grid has some rows:</p>
<pre><code>StartTest(function(t) {
t.diag(&quot;Creating some window&quot;);
var view = Ext.create('MyApp.view.SomeOverview', {
renderTo: Ext.getBody() // required
});
var grid = view.down(&quot;grid&quot;);
t.chain(
{ waitFor : 'rowsVisible', args : grid }
);
});
</code></pre>
<p><figure>
<a href="../siesta.png" class="lbox">
<img loading="lazy" src="../siesta.png" title="The Siesta view test in action">
</a>
<figcaption>The Siesta view test in action</figcaption>
</figure>
</p>
<p>Siesta also comes with it&rsquo;s downsides though.</p>
<ul>
<li>JS Test code is really messy. Chaining, async calls, ugly data setup for stores, &hellip; A simple test can get complicated fast and requires advanced JS knowledge not everybody in our team has.</li>
<li><code>waitFor</code> exposes the same problems we have with our current WebDriver tests, so it&rsquo;s not that much of an improvement</li>
<li>Test data setup cannot be reused from our backend integration tests (we use the builder pattern there to create data in the DB)</li>
<li>Creating a view to test doesn&rsquo;t test the controller and vice versa. Still too low level for us.</li>
</ul>
<p>The biggest problem is that it&rsquo;s still more an integration/unit test than a scenario test and quite tightly coupled to your implementation. Since our implementation is far from perfect, Siesta is not the optimal solution for us. For example, we create stores inside our views and load them in <code>initComponent()</code>. No way to provide a stub store with some dummy data. We&rsquo;d have to refactor 200+ views to create tests. Of course tests should be written before the implementation&hellip;</p>
<p>If you would like to know more about Siesta or JS BDD testing, take a look at</p>
<ul>
<li><a href="http://pivotallabs.com/sencha-touch-bdd-part-5-controller-testing/">Pivotallabs blog post</a></li>
<li><a href="http://www.bryntum.com/docs/siesta/#!/guide/siesta_getting_started">Siesta API doc: Getting started</a></li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 23 December 2014.
</p>
]]>
</description>
</item>
<item>
<title>.NET Memory management VS JVM Memory management</title>
<link>https://brainbaking.com/post/2014/10/memory-management-vs-java/</link>
<comments>https://brainbaking.com/post/2014/10/memory-management-vs-java/#commento</comments>
<pubDate>Fri, 24 Oct 2014 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2014/10/memory-management-vs-java/</guid>
<category domain="https://brainbaking.com/tags/memory management">memory management</category>
<category domain="https://brainbaking.com/tags/CLR">CLR</category>
<category domain="https://brainbaking.com/tags/.NET">.NET</category>
<category domain="https://brainbaking.com/tags/JVM">JVM</category>
<description>
<![CDATA[
<p>Memory management is something to keep in mind when deploying and running applications on top of the JVM. Parameters like <code>Xmx</code> and <code>Xms</code> are things to juggle with when it comes to finding the perfect balance between too much memory hogging (at app startup) and too little, especially if you&rsquo;re working with heavy duty entity mapping frameworks like Hibernate (and you&rsquo;re not so good at writing fast HQL).
When we bumped into an <code>OutOfMemoryException</code> in .NET, I got an Xmx flashback and started searching on how to do the same with the CLR.</p>
<p>Turns out you can&rsquo;t.</p>
<p>You can&rsquo;t set max heap size in .Net unless you host the CLR yourself in a process. (<a href="http://stackoverflow.com/questions/301393/can-i-and-do-i-ever-want-to-set-the-maximum-heap-size-in-net">source</a>)
To control the memory allocations of CLR including the max heap size, you need to use the hosting api to host the clr and specifically use the &ldquo;Memory manager interfaces&rdquo;, some starter info can be found here <a href="http://msdn.microsoft.com/en-us/magazine/cc163567.aspx">MSDN Magazine, column CLR Inside Out : CLR Hosting APIs</a></p>
<p>The heap does indeed keep growing until it can&rsquo;t grow any more. (Obviously this is &ldquo;after attempting to recover memory through GC, grow the heap&rdquo;.) Basically there isn&rsquo;t nearly as much tuning available in the .NET GC as in Java. You can choose the server GC or the client one, and I think there&rsquo;s an option for turning on/off the concurrent GC (I&rsquo;ll find links in a minute) but that&rsquo;s basically it.</p>
<p>See also:</p>
<ul>
<li><a href="http://www.atalasoft.com/cs/blogs/rickm/archive/2008/05/14/choosing-the-right-garbage-collector-settings-for-your-application-net-memory-management-part-4.aspx">Choosing the right garbage collector for your .NET Application</a></li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 24 October 2014.
</p>
]]>
</description>
</item>
<item>
<title>Faking domain logic</title>
<link>https://brainbaking.com/post/2014/09/faking-domain-logic/</link>
<comments>https://brainbaking.com/post/2014/09/faking-domain-logic/#commento</comments>
<pubDate>Tue, 23 Sep 2014 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2014/09/faking-domain-logic/</guid>
<category domain="https://brainbaking.com/tags/domain driven design">domain driven design</category>
<category domain="https://brainbaking.com/tags/CSharp">CSharp</category>
<category domain="https://brainbaking.com/tags/code smells">code smells</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Faking%20domain%20logic.jpg"/>
</p>
<p>Sometimes, life is just a little bit more difficult than you imagined the day before. Sometimes, you have to work on a legacy codebase with custom frameworks rooted so deeply you&rsquo;re having lot&rsquo;s of trouble trying to build around them. To make it a bit more concrete, here&rsquo;s an example: imagine a separate DLL for interfaces and a separate DLL for the implementation. This decision was made because we use NHibernate as a data mapper and not to write beautiful domain driven design code. As a result, writing domain logic methods on our &ldquo;domain&rdquo; objects is impossible because we have three implementations.</p>
<p>There are a few solutions. The first would be the classic solution, called a &ldquo;service layer&rdquo; where you simply dump random &ldquo;domain&rdquo; logic. Done.</p>
<p>Then there&rsquo;s a slightly better solution involving abstract classes. But it makes things more complicated, and it&rsquo;s not always allowed to inherit from those classes. Besides, in which DLL should you put them? Dependency Entanglement. Welcome to hotel Cali&mdash; erm, DLL Hell.</p>
<p>So, option number three: use extensions on those interfaces.</p>
<pre><code> public interface IVacancy
{
public string Description { get; set; }
}
</code></pre>
<p>would have these implementations:</p>
<pre><code> public class FulltimeVacancy : IVacancy
{
public string Description { get { // ... }; set { field = value; }}
}
public class HalftimeVacancy : IVacancy
{
public string Description { get { // ... }; set { field = value; }}
}
</code></pre>
<p>If I&rsquo;d want to implement something like <code>RetrieveLocation()</code> based on for example google maps and other properties, I can place the entry point in an extension class:</p>
<pre><code> public static class IVacancyExtensions
{
public static string RetrieveLocation(this IVacancy vacancy)
{
// do your thing
}
}
</code></pre>
<p>Using the right namespace imports, I&rsquo;m able to call the above method on any concrete implementation of <code>IVacancy</code>, regardless of it&rsquo;s (DLL) location. Now, why would I want to keep code like this as close to the original object as possible? this has multiple reasons:</p>
<ul>
<li>It makes code easier to read &amp; refactor.</li>
<li>It reduces the chance of duplication in another service layer, as people often hit &ldquo;CTRL+SPACE&rdquo; to find a method from an object or a piece of logic, and don&rsquo;t go looking in service classes.</li>
<li>It makes code easier to discuss (since it&rsquo;s also easier to read).</li>
<li>It&rsquo;s isolated and thus easier to test.</li>
<li>It avoids a lot of <a href="http://martinfowler.com/bliki/CodeSmell.html">other code smells</a> (deserves it&rsquo;s own article).</li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 23 September 2014.
</p>
]]>
</description>
</item>
<item>
<title>Custom Webdriver Page Factories</title>
<link>https://brainbaking.com/post/2014/09/custom-webdriver-page-factories/</link>
<comments>https://brainbaking.com/post/2014/09/custom-webdriver-page-factories/#commento</comments>
<pubDate>Mon, 22 Sep 2014 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2014/09/custom-webdriver-page-factories/</guid>
<category domain="https://brainbaking.com/tags/unit testing">unit testing</category>
<category domain="https://brainbaking.com/tags/java">java</category>
<category domain="https://brainbaking.com/tags/CSharp">CSharp</category>
<category domain="https://brainbaking.com/tags/webdriver">webdriver</category>
<category domain="https://brainbaking.com/tags/scenario testing">scenario testing</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Custom%20Webdriver%20Page%20Factories.jpg"/>
</p>
<p>The problem: Webdriver elements returned by <code>driver.FindElement()</code> are too generic. There&rsquo;re the <code>Text</code>, <code>SendKeys()</code> and <code>Click()</code> methods/properties (depending your on C#/Java implementation). The solution is to simply wrap all elements inside custom HTML objects which contain specific methods like <code>ShouldContainValue</code> or <code>Type</code> (okay, that&rsquo;s a one-to-one mapping with <code>SendKeys()</code>, but it&rsquo;s a lot less technical!). Instead of</p>
<pre><code> [FindsBy(How = How.CssSelector, Using = &quot;.ux-desktop-taskbar-startbutton&quot;)]
private IWebElement startButton;
[FindsBy(How = How.CssSelector, Using = &quot;.other&quot;)]
private IWebElement whatever;
</code></pre>
<p>You&rsquo;d find code like</p>
<pre><code> [FindsBy(How = How.CssSelector, Using = &quot;.ux-desktop-taskbar-startbutton&quot;)]
private HTMLSubmitButton startButton;
[FindsBy(How = How.CssSelector, Using = &quot;.other&quot;)]
private HTMLInputBox whatever;
</code></pre>
<p>In java, this is not that difficult. Normally all fields annotated with FindsBy are filled in via reflection with <code>PageFactory.InitElements()</code>. (warning: this creates proxies and does not yet actually do the lookup in the DOM tree. This is a good thing, as filling the fields usually happens inside the constructor of a page object.). <code>initElements</code> returns the filled page, you can do a few things from there:</p>
<ul>
<li>postprocess the page and decorate your fields</li>
<li>create your own page factory and create your own fields, wrapped around the webdriver proxies</li>
</ul>
<p>In C#, you&rsquo;re in trouble - the class is sealed, and the proxy classes are internal. Creating your own factory is possible, but produces fuzzy code:</p>
<pre><code>internal class PageFactory
{
private PageFactory()
{
}
private static By FindsByAttributeToBy(FindsByAttribute attribute)
{
return (By) typeof (FindsByAttribute).GetProperty(&quot;Finder&quot;, BindingFlags.NonPublic | BindingFlags.Instance).GetValue(attribute);
}
public static void InitElements(IWebDriver driver, object page)
{
foreach (FieldInfo field in FindAllFieldsAndProperties(page.GetType()))
{
Attribute[] findsByAttribs = Attribute.GetCustomAttributes(field, typeof (FindsByAttribute), true);
if (findsByAttribs.Length &gt; 0)
{
var findsByAttribute = (findsByAttribs[0] as FindsByAttribute);
if (field.FieldType == typeof (IWebElement))
{
field.SetValue(page, FindElement(driver, FindsByAttributeToBy(findsByAttribute)));
}
else if (typeof (IEnumerable).IsAssignableFrom(field.FieldType))
{
field.SetValue(page, FindElements(driver, FindsByAttributeToBy(findsByAttribute)));
}
}
}
}
private static IWebElement FindElement(IWebDriver driver, By by)
{
// warning: create WebProxyElement instead of directly doing a lookup
return driver.FindElement(by);
}
private static IReadOnlyCollection&lt;IWebElement&gt; FindElements(IWebDriver driver, By by)
{
// warning: create WebListProxyElement instead of directly doing a lookup
return driver.FindElements(by);
}
private static IEnumerable&lt;FieldInfo&gt; FindAllFieldsAndProperties(Type type)
{
var list = new List&lt;FieldInfo&gt;();
list.AddRange(type.GetFields(BindingFlags.Instance | BindingFlags.Public));
for (; type != (Type) null; type = type.BaseType)
{
list.AddRange(type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic));
}
return list;
}
}
</code></pre>
<p>If you have a keen eye, you notice a few things:</p>
<ul>
<li>caching of the attribute wouldn&rsquo;t work anymore. The default C# WebDriver implementation is fuzzy and I didn&rsquo;t want to copypaste code I won&rsquo;t use.</li>
<li>proxying won&rsquo;t work anymore, you&rsquo;d have to use reflection to instantiate internal classes.</li>
<li>reflection has been used to fetch the <code>By</code> instance of the <code>FindsByAttribute</code>. Yay.</li>
</ul>
<p>The above solution is too complex to solve a simple thing. Instead of a custom page factory, in C# we now use extension methods on <code>IWebElement</code>. Another possibility would to create wrapper objects on-the-fly but you&rsquo;d still have to map the &ldquo;raw&rdquo; web elements on page objects.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 22 September 2014.
</p>
]]>
</description>
</item>
<item>
<title>Bye autotools hello Scons</title>
<link>https://brainbaking.com/post/2014/03/scons-building/</link>
<comments>https://brainbaking.com/post/2014/03/scons-building/#commento</comments>
<pubDate>Wed, 26 Mar 2014 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2014/03/scons-building/</guid>
<category domain="https://brainbaking.com/tags/C&#43;&#43;">C&#43;&#43;</category>
<category domain="https://brainbaking.com/tags/python">python</category>
<category domain="https://brainbaking.com/tags/build ecosystem">build ecosystem</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Bye%20autotools%20hello%20Scons.jpg"/>
</p>
<p>Remember this?</p>
<ul>
<li><code>./configure</code></li>
<li><code>make</code></li>
<li><code>make install</code></li>
</ul>
<p>That&rsquo;s not so bad, as long as you have the right compiler and linker flags configured, depending on the target OS. The real problem, however, is trying to figure out how to alter something if you didn&rsquo;t write the <code>Makefile</code> yourself. Or if you in fact did write it, but it was some time ago. Two days. No, four hours.</p>
<h3 id="the-problem">The problem</h3>
<p>Try to study the autoconf and automake flow diagram, explained <a href="http://en.wikipedia.org/wiki/GNU_build_system">on Wikipedia: the GNU build system</a>. Headache coming up? Suppose we would like to use these &hellip; uhm, &ldquo;thingies&rdquo;, for a simple C++ project.</p>
<p>First, let me define simple:</p>
<ul>
<li>It has some (shared) library dependencies</li>
<li>The source lives in <code>src</code></li>
<li>Since it&rsquo;s obviously written the TDD way, the tests live in <code>test</code></li>
</ul>
<p>Onward, to the <code>Makefile</code> creation station!
This is a sample file, from the <a href="https://code.google.com/p/googletest/source/browse/trunk/make/Makefile">Google Test Makefile</a>:</p>
<pre><code>GTEST_DIR = ..
USER_DIR = ../samples
CPPFLAGS += -isystem $(GTEST_DIR)/include
CXXFLAGS += -g -Wall -Wextra -pthread
TESTS = sample1_unittest
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
$(GTEST_DIR)/include/gtest/internal/*.h
all : $(TESTS)
clean :
rm -f $(TESTS) gtest.a gtest_main.a *.o
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest_main.cc
gtest.a : gtest-all.o
$(AR) $(ARFLAGS) $@ $^
gtest_main.a : gtest-all.o gtest_main.o
$(AR) $(ARFLAGS) $@ $^
sample1.o : $(USER_DIR)/sample1.cc $(USER_DIR)/sample1.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1.cc
sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc \
$(USER_DIR)/sample1.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc
sample1_unittest : sample1.o sample1_unittest.o gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
</code></pre>
<p>This first builds the gtest_main.a binary, to be able to link that with our test after the source (sample1.o) has been is built. The syntax is clumsy, simple files require me to have a deep knowledge how flags and linking work, and I don&rsquo;t want to specify everything in one block.</p>
<p>As esr in his blog post <a href="http://esr.ibiblio.org/?p=3089">Scons is full of win today</a> said, it&rsquo;s a maintenance nightmare. What to do?</p>
<p>There are a few alternatives which aim to cover everything autotools does, such as <code>QMake</code> from Trolltech or <code>CMake</code> (that actually generates Makefiles. You&rsquo;re not helping, CMake!). Or, one could go for <a href="http://scons.org/">Scons</a>.</p>
<h3 id="build-your-software-better">build your software, better.</h3>
<p>Scons starts with a single <code>SConstruct</code> file, which acts as the makefile. You can bootstrap the default build target using the <code>scons</code> command. (cleaning with <code>scons --clean</code>). The big deal here is that the contents of that file is simply python (2.7, I know)!</p>
<p>Want to write a utility function to gather all your <code>cpp</code> files? Fine, go ahead, <code>def mystuff():</code> (you do know this already exists, right? Use <code>Glob()</code>) Want to unit test these, and include them? Done. Want to split up everything per source directory? Use <code>SConscript</code> files and include these from within your root <code>SConstruct</code> using <code>SConscript('file', 'envVarToExport')</code>.</p>
<p>This is my blueprint construct file:</p>
<pre><code>env = Environment(CXX = 'g++')
gtest = env.SConscript('lib/gtest/SConscript', 'env')
src = env.SConscript('src/SConscript', 'env')
out = env.SConscript('test/SConscript', 'env gtest src')
# output is an array with path to built binaries. We only built one file - run it (includes gtest_main).
test = Command( target = &quot;testoutput&quot;,
source = str(out[0]),
action = str(out[0]) )
AlwaysBuild(test)
</code></pre>
<p>Things to note:</p>
<ul>
<li>Scons works with <a href="http://www.scons.org/doc/2.3.1/HTML/scons-user.html#chap-environments">Environments</a> which can be shared and cloned (see below)</li>
<li>You can share variables with the second parameter</li>
<li>Executing after a build also works, passing in the result of conscripts.</li>
<li>Ensure to always build your test with <code>AlwaysBuild()</code></li>
</ul>
<p>This is the conscript which builds google test:</p>
<pre><code>Import('env')
env = env.Clone(CPPPATH = './:./include')
env.Append(CXXFLAGS = ['-g', '-Wall', '-Wextra', '-pthread'])
gtest = env.Library(target = 'gtest', source = ['src/gtest-all.cc', 'src/gtest_main.cc'])
Return('gtest')
</code></pre>
<p>Things to note:</p>
<ul>
<li>Fetch the shared variables with <code>Import()</code> and return stuff with <code>Return()</code> (it&rsquo;s a function)</li>
<li>specify flags all you want.</li>
<li>Building something? <code>Program()</code>, <code>Library()</code> or <code>SharedLibrary()</code>.</li>
</ul>
<p>Source:</p>
<pre><code>Import('env')
env = env.Clone(CPPPATH = './')
src = env.Library(target = 'wizards', source = Glob('*.cc'))
Return('src')
</code></pre>
<p>Things to note:</p>
<ul>
<li><code>Glob()</code> auto-reads all files in the current dir.</li>
</ul>
<p>And finally, test, linking both source and google test:</p>
<pre><code>Import('env', 'gtest', 'src')
env = env.Clone()
env.Append(LIBPATH = ['#lib/gtest', '#src'])
env.Append(LIBS = [gtest, src])
out = env.Program(target = 'wizards_unittests', source = Glob('*.cc'))
Return('out')
</code></pre>
<p>Things to note:</p>
<ul>
<li>Use the hashtag <code>#</code> to point to the root dir where the <code>SConstruct</code> file resides.</li>
<li>Linking is as simple as providing <code>LIBS</code> and the right path.</li>
</ul>
<p>So where does that leave us? Yes there&rsquo;s still &ldquo;syntax&rdquo; to be learned, even if you&rsquo;re a seasoned python developer; you need to know which function to use for what, that&rsquo;s what the excellent <a href="http://www.scons.org/doc/2.3.1/HTML/scons-user.html">scons doc</a> is for. I know it made my life a lot easier while trying to do something simple and this is only the tip of the iceberg. Scons is relatively popular according to Stack Overflow, the documentation is excellent and if all else fails you can write your own garbage in a full-fledged dynamic language.</p>
<p>The only really irritating bit is the python 2.7 dependency, so don&rsquo;t forget to use <a href="https://pypi.python.org/pypi/virtualenv">virtualenv</a>.</p>
<h1 id="in-practice">In practice</h1>
<p>The section below contains practical snippets used by myself in some point in the past, commented in Dutch. Feel free to grab a piece.</p>
<ol>
<li><a href="http://www.scons.org/wiki/FrontPage">SCons Wiki Frontpage</a></li>
<li><a href="http://www.scons.org/doc/HTML/scons-man.html#lbAF">Single HTML Manpage</a></li>
<li><a href="http://www.scons.org/doc/0.96.90/HTML/scons-user/a3061.html">SCons Construction Variables</a> om bvb de compiler te specifiëren.</li>
</ol>
<h3 id="separating-sconstruct-and-sconscript">Separating SConstruct and SConscript</h3>
<p>Why? <a href="http://www.scons.org/doc/2.1.0/HTML/scons-user/c3356.html">http://www.scons.org/doc/2.1.0/HTML/scons-user/c3356.html</a></p>
<p>Defining a build output, duplicating source files, etc. For example, in a <code>SConstruct</code> file:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#434f54">SConscript</span>(<span style="color:#7f8c8d">&#39;SConscript&#39;</span>, <span style="color:#434f54">variant_dir</span><span style="color:#95a5a6">######&#39;build&#39;, duplicate0)</span>
</code></pre></div><p>This is an example file to build and run some GTest in <code>SConscript</code>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#728e00">def</span> <span style="color:#d35400">Glob</span>( <span style="color:#434f54">pattern</span> <span style="color:#95a5a6">###### &#39;*.*&#39;, dir &#39;.&#39; ):</span>
<span style="color:#728e00">import</span> <span style="color:#434f54">os</span><span style="color:#728e00">,</span> <span style="color:#434f54">fnmatch</span>
<span style="color:#434f54">files</span> <span style="color:#728e00">=</span> []
<span style="color:#728e00">for</span> <span style="color:#728e00">file</span> <span style="color:#728e00">in</span> <span style="color:#434f54">os</span><span style="color:#728e00">.</span><span style="color:#434f54">listdir</span>( <span style="color:#434f54">Dir</span>(<span style="color:#728e00">dir</span>)<span style="color:#728e00">.</span><span style="color:#434f54">srcnode</span>()<span style="color:#728e00">.</span><span style="color:#434f54">abspath</span> ):
<span style="color:#728e00">if</span> <span style="color:#434f54">fnmatch</span><span style="color:#728e00">.</span><span style="color:#434f54">fnmatch</span>(<span style="color:#728e00">file</span>, <span style="color:#434f54">pattern</span>) :
<span style="color:#434f54">files</span><span style="color:#728e00">.</span><span style="color:#434f54">append</span>( <span style="color:#434f54">os</span><span style="color:#728e00">.</span><span style="color:#434f54">path</span><span style="color:#728e00">.</span><span style="color:#434f54">join</span>( <span style="color:#728e00">dir</span>, <span style="color:#728e00">file</span> ) )
<span style="color:#728e00">return</span> <span style="color:#434f54">files</span>
<span style="color:#95a5a6"># construction variables: http://www.scons.org/doc/0.96.90/HTML/scons-user/a3061.html</span>
<span style="color:#434f54">env</span> <span style="color:#95a5a6">###### Environment(CXX &#39;g++&#39;,</span>
<span style="color:#434f54">CPPPATH</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#39;../:./include&#39;</span>)
<span style="color:#95a5a6"># add to library search path env.Append(LIBPATH = [&#39;/usr/local/lib/&#39;])</span>
<span style="color:#95a5a6"># add to libraries link path env.Append(LIBS = [&#39;SDL_image&#39;,&#39;GL&#39;])</span>
<span style="color:#434f54">env</span><span style="color:#728e00">.</span><span style="color:#434f54">Append</span>(<span style="color:#434f54">CPPFLAGS</span> <span style="color:#728e00">=</span> [<span style="color:#7f8c8d">&#39;-isystem ./include&#39;</span>])
<span style="color:#434f54">env</span><span style="color:#728e00">.</span><span style="color:#434f54">Append</span>(<span style="color:#434f54">CXXFLAGS</span> <span style="color:#728e00">=</span> [<span style="color:#7f8c8d">&#39;-g&#39;</span>, <span style="color:#7f8c8d">&#39;-Wall&#39;</span>, <span style="color:#7f8c8d">&#39;-Wextra&#39;</span>, <span style="color:#7f8c8d">&#39;-pthread&#39;</span>])
<span style="color:#434f54">env</span><span style="color:#728e00">.</span><span style="color:#434f54">SharedLibrary</span>(<span style="color:#434f54">target</span> <span style="color:#95a5a6">###### &#39;gtest_main.dll&#39;, source [&#39;../src/gtest-all.cc&#39;])</span>
<span style="color:#95a5a6"># after that, we should link with gtest_main</span>
</code></pre></div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 26 March 2014.
</p>
]]>
</description>
</item>
<item>
<title>Metaprogramming instead of duplication</title>
<link>https://brainbaking.com/post/2014/03/metaprogramming-convention-dry/</link>
<comments>https://brainbaking.com/post/2014/03/metaprogramming-convention-dry/#commento</comments>
<pubDate>Fri, 14 Mar 2014 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2014/03/metaprogramming-convention-dry/</guid>
<category domain="https://brainbaking.com/tags/CSharp">CSharp</category>
<category domain="https://brainbaking.com/tags/java">java</category>
<category domain="https://brainbaking.com/tags/metaprogramming">metaprogramming</category>
<category domain="https://brainbaking.com/tags/reflection">reflection</category>
<category domain="https://brainbaking.com/tags/unit testing">unit testing</category>
<category domain="https://brainbaking.com/tags/mocking">mocking</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Metaprogramming%20instead%20of%20duplication.jpg"/>
</p>
<p>So&hellip; What&rsquo;s up with all that duplication in your unit tests? Let&rsquo;s take a look at a very recognizable pattern when for instance using <code>RhinoMock</code> in <code>C#</code>:</p>
<pre><code> [TestInitialize]
public void SetUp()
{
dbConfigurationMock = MockRepository.GenerateMock&lt;IDbConfiguration&gt;();
mountPointLoaderMock = MockRepository.GenerateMock&lt;IMountPointLoader&gt;();
userEnvironmentFactoryMock = MockRepository.GenerateMock&lt;IUserEnvironmentFactory&gt;();
userEnvironmentLoaderMock = MockRepository.GenerateMock&lt;IUserEnvironmentLoader&gt;();
// ...
</code></pre>
<p>We agreed to suffix each instance variable with &lsquo;Mock&rsquo; if it&rsquo;s a mock. That way, when you scroll down to an actual test case, it&rsquo;s clear to everyone what&rsquo;s what: mocks, stubs, actual implementations, and so forth. So why should I repeat myself again and again but initializing a bunch of mocks using <code>GenerateMock</code>?</p>
<p>In Java using Mockito, the <code>@Mock</code> annotation automagically instantiates a mock for you, provided you annotated your test class with <code>@RunWith(MockitoJUnitRunner.class)</code>. I would like to apply this pattern to MSTest but there&rsquo;s not a single hook to be found where I can plug in my initialization code. Thanks a bunch.</p>
<p>Example taken from <a href="http://docs.mockito.googlecode.com/">Mockito docs</a></p>
<pre><code>public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Mock private UserProvider userProvider;
private ArticleManager manager;
</code></pre>
<p>Now, this &ldquo;problem&rdquo; is easily solved with a bit of metaprogramming and an abstract class:</p>
<ul>
<li>
<p>Loop over (private) fields</p>
</li>
<li>
<p>Filter out suffixed with &lsquo;Mock&rsquo;</p>
</li>
<li>
<p>Initialize.</p>
<pre><code>public abstract class AbstractTestCase
{
[TestInitialize]
public void CreateMocksBasedOnNamingConvention()
{
this.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(x =&gt; x.Name.EndsWith(&quot;Mock&quot;)).All(InitMock);
}
private bool InitMock(FieldInfo field)
{
field.SetValue(this, MockRepository.GenerateMock(field.FieldType, new Type[]{}));
return true;
}
}
</code></pre>
</li>
</ul>
<p>Very easy with <code>LINQ</code>. The question is - is metaprogramming or reflection in this case &ldquo;allowed&rdquo;? Do you think this is &ldquo;bad&rdquo; (because it&rsquo;s implicit), or is the convention of suffixing your fields with &lsquo;Mock&rsquo; good enough? The base test case could also be named something like <code>MockInitializingTestCase</code> if that makes you feel better.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 14 March 2014.
</p>
]]>
</description>
</item>
<item>
<title>Enhancing the builder pattern with closures</title>
<link>https://brainbaking.com/post/2013/11/builders-dsl/</link>
<comments>https://brainbaking.com/post/2013/11/builders-dsl/#commento</comments>
<pubDate>Thu, 14 Nov 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/11/builders-dsl/</guid>
<category domain="https://brainbaking.com/tags/closures">closures</category>
<category domain="https://brainbaking.com/tags/groovy">groovy</category>
<category domain="https://brainbaking.com/tags/CSharp">CSharp</category>
<category domain="https://brainbaking.com/tags/javascript">javascript</category>
<category domain="https://brainbaking.com/tags/java">java</category>
<category domain="https://brainbaking.com/tags/functional programming">functional programming</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Enhancing%20the%20builder%20pattern%20with%20closures.jpg"/>
</p>
<p>This post is inspired by Venkat Subramaniam&rsquo;s <a href="http://www.devoxx.be/dv13-venkat-subramaniam.html">Devoxx 2013 talk Thinking Functional Style</a>. See downloads at <a href="http://www.agiledeveloper.com/downloads.html">agiledeveloper.com</a> which has a rather cool Groovy example.</p>
<h3 id="classic-builders">Classic builders</h3>
<p>For years, I&rsquo;ve been using the builder pattern to quickly create new objects to be inserted into the database or to inject our domain objects with the required data. We started with so called &ldquo;Object Mothers&rdquo;, static methods which simply create and fill up an object, passing in a huge amount of parameters. That quickly became very cumbersome to work with. Most of the time, the code will look like this, whether it&rsquo;s C# or Java doesn&rsquo;t really matter:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#728e00">public</span> <span style="color:#728e00">class</span> <span style="color:#434f54">UserBuilder</span>
<span style="color:#728e00">{</span>
<span style="color:#728e00">private</span> <span style="color:#434f54">UserType_V1_0</span> <span style="color:#434f54">type</span> <span style="color:#728e00">=</span> <span style="color:#434f54">UserType_V1_0</span><span style="color:#728e00">.</span><span style="color:#434f54">Administrator</span><span style="color:#728e00">;</span>
<span style="color:#728e00">private</span> <span style="color:#434f54">string</span> <span style="color:#434f54">code</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;code&#34;</span><span style="color:#728e00">;</span>
<span style="color:#728e00">public</span> <span style="color:#434f54">User_V1_0</span> <span style="color:#d35400">Build</span><span style="color:#728e00">()</span>
<span style="color:#728e00">{</span>
<span style="color:#434f54">User_V1_0</span> <span style="color:#434f54">user</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">User_V1_0</span><span style="color:#728e00">(</span><span style="color:#434f54">code</span><span style="color:#728e00">,</span> <span style="color:#7f8c8d">&#34;name&#34;</span><span style="color:#728e00">,</span> <span style="color:#434f54">type</span><span style="color:#728e00">,</span> <span style="color:#7f8c8d">&#34;id&#34;</span><span style="color:#728e00">,</span> <span style="color:#7f8c8d">&#34;campusId&#34;</span><span style="color:#728e00">,</span> <span style="color:#00979d">true</span><span style="color:#728e00">);</span>
<span style="color:#728e00">return</span> <span style="color:#434f54">user</span><span style="color:#728e00">;</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">public</span> <span style="color:#434f54">UserBuilder</span> <span style="color:#d35400">WithCode</span><span style="color:#728e00">(</span><span style="color:#434f54">string</span> <span style="color:#434f54">code</span><span style="color:#728e00">)</span>
<span style="color:#728e00">{</span>
<span style="color:#728e00">this</span><span style="color:#728e00">.</span><span style="color:#434f54">code</span> <span style="color:#728e00">=</span> <span style="color:#434f54">code</span><span style="color:#728e00">;</span>
<span style="color:#728e00">return</span> <span style="color:#728e00">this</span><span style="color:#728e00">;</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">public</span> <span style="color:#434f54">UserBuilder</span> <span style="color:#d35400">WithType</span><span style="color:#728e00">(</span><span style="color:#434f54">UserType_V1_0</span> <span style="color:#434f54">type</span><span style="color:#728e00">)</span>
<span style="color:#728e00">{</span>
<span style="color:#728e00">this</span><span style="color:#728e00">.</span><span style="color:#434f54">type</span> <span style="color:#728e00">=</span> <span style="color:#434f54">type</span><span style="color:#728e00">;</span>
<span style="color:#728e00">return</span> <span style="color:#728e00">this</span><span style="color:#728e00">;</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">}</span>
</code></pre></div><p>Used this way:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"> <span style="color:#434f54">var</span> <span style="color:#434f54">user</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">UserBuilder</span><span style="color:#728e00">()</span>
<span style="color:#728e00">.</span><span style="color:#434f54">withCode</span><span style="color:#728e00">(</span><span style="color:#7f8c8d">&#34;AB&#34;</span><span style="color:#728e00">)</span>
<span style="color:#728e00">.</span><span style="color:#434f54">Build</span><span style="color:#728e00">();</span>
</code></pre></div><p>Okay, what&rsquo;s happening here?</p>
<ul>
<li>Builder objects have <code>withX()</code> methods, returning <code>this</code> to be able to chain, to fill up every required variable</li>
<li>default values are provided, so we&rsquo;re not obliged to call every method if we&rsquo;re only interested in one field.</li>
<li>At the end of the chain, we call <code>Build()</code>, which returns our object.</li>
</ul>
<h3 id="enhanced-builders">Enhanced builders</h3>
<p>I&rsquo;ve never given it much thought, but yes, there are some problems with this implementation (as with everything). The most important one being, can you reuse your instantiated builder? No? Yes? We never assign it, but we <strong>could</strong> if we really wanted to. Since we&rsquo;re <strong>mutating the builder</strong>, you are definatly getting into trouble.</p>
<p>Using a lambda to pass in the work on our builder might solve this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#728e00">public</span> <span style="color:#728e00">class</span> <span style="color:#434f54">UserBuilder</span>
<span style="color:#728e00">{</span>
<span style="color:#728e00">private</span> <span style="color:#434f54">UserType_V1_0</span> <span style="color:#434f54">type</span> <span style="color:#728e00">=</span> <span style="color:#434f54">UserType_V1_0</span><span style="color:#728e00">.</span><span style="color:#434f54">Administrator</span><span style="color:#728e00">;</span>
<span style="color:#728e00">private</span> <span style="color:#434f54">string</span> <span style="color:#434f54">code</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;code&#34;</span><span style="color:#728e00">;</span>
<span style="color:#728e00">private</span> <span style="color:#d35400">UserBuilder</span><span style="color:#728e00">()</span>
<span style="color:#728e00">{</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">private</span> <span style="color:#434f54">User_V1_0</span> <span style="color:#d35400">Build</span><span style="color:#728e00">()</span>
<span style="color:#728e00">{</span>
<span style="color:#728e00">return</span> <span style="color:#728e00">new</span> <span style="color:#434f54">User_V1_0</span><span style="color:#728e00">(</span><span style="color:#434f54">code</span><span style="color:#728e00">,</span> <span style="color:#7f8c8d">&#34;name&#34;</span><span style="color:#728e00">,</span> <span style="color:#434f54">type</span><span style="color:#728e00">,</span> <span style="color:#7f8c8d">&#34;id&#34;</span><span style="color:#728e00">,</span> <span style="color:#7f8c8d">&#34;campusId&#34;</span><span style="color:#728e00">,</span> <span style="color:#00979d">true</span><span style="color:#728e00">);</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">public</span> <span style="color:#728e00">static</span> <span style="color:#434f54">User_V1_0</span> <span style="color:#d35400">Build</span><span style="color:#728e00">(</span><span style="color:#434f54">Func</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">UserBuilder</span><span style="color:#728e00">,</span> <span style="color:#434f54">UserBuilder</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">block</span><span style="color:#728e00">)</span>
<span style="color:#728e00">{</span>
<span style="color:#434f54">var</span> <span style="color:#434f54">builder</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">UserBuilder</span><span style="color:#728e00">();</span>
<span style="color:#434f54">block</span><span style="color:#728e00">(</span><span style="color:#434f54">builder</span><span style="color:#728e00">);</span>
<span style="color:#728e00">return</span> <span style="color:#434f54">builder</span><span style="color:#728e00">.</span><span style="color:#434f54">Build</span><span style="color:#728e00">();</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">public</span> <span style="color:#434f54">UserBuilder</span> <span style="color:#d35400">WithCode</span><span style="color:#728e00">(</span><span style="color:#434f54">string</span> <span style="color:#434f54">code</span><span style="color:#728e00">)</span>
<span style="color:#728e00">{</span>
<span style="color:#728e00">this</span><span style="color:#728e00">.</span><span style="color:#434f54">code</span> <span style="color:#728e00">=</span> <span style="color:#434f54">code</span><span style="color:#728e00">;</span>
<span style="color:#728e00">return</span> <span style="color:#728e00">this</span><span style="color:#728e00">;</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">public</span> <span style="color:#434f54">UserBuilder</span> <span style="color:#d35400">WithType</span><span style="color:#728e00">(</span><span style="color:#434f54">UserType_V1_0</span> <span style="color:#434f54">type</span><span style="color:#728e00">)</span>
<span style="color:#728e00">{</span>
<span style="color:#728e00">this</span><span style="color:#728e00">.</span><span style="color:#434f54">type</span> <span style="color:#728e00">=</span> <span style="color:#434f54">type</span><span style="color:#728e00">;</span>
<span style="color:#728e00">return</span> <span style="color:#728e00">this</span><span style="color:#728e00">;</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">}</span>
</code></pre></div><p>Used this way:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"> <span style="color:#434f54">var</span> <span style="color:#434f54">user</span> <span style="color:#728e00">=</span> <span style="color:#434f54">UserBuilder</span><span style="color:#728e00">.</span><span style="color:#434f54">Build</span><span style="color:#728e00">(</span><span style="color:#434f54">_</span> <span style="color:#728e00">=&gt;</span>
<span style="color:#434f54">_</span><span style="color:#728e00">.</span><span style="color:#434f54">WithCode</span><span style="color:#728e00">(</span><span style="color:#7f8c8d">&#34;AB&#34;</span><span style="color:#728e00">)</span>
<span style="color:#728e00">.</span><span style="color:#434f54">withType</span><span style="color:#728e00">(</span><span style="color:#434f54">UserType_V1_0</span><span style="color:#728e00">.</span><span style="color:#434f54">NursingStaff</span><span style="color:#728e00">));</span>
</code></pre></div><p>Notice that using the character <code>_</code> is a convention if there&rsquo;s only one parameter for the lambda, it could also be called &ldquo;builder&rdquo; but we still need to use this, as <code>block(builder)</code> passes in the temp created builder. What did we solve?</p>
<ul>
<li>The actual builder instance is bound within the <code>Build()</code> scope. You&rsquo;ll never be able to assign it when using the static method.</li>
<li>One might say, we reduced some redundancy in the implementation by eliminating the need to call the final <code>Build()</code> method, but it&rsquo;s simply being moved.</li>
</ul>
<h3 id="supercharged-builders">Supercharged builders</h3>
<p>In Groovy (the devoxx example), we can cleverly use the <code>.delegate</code> mechanism to eliminate the need to chain at all. Groovy also reduces the syntax noise a bit (brackets, semicolons). We could create a <code>Build</code> method like this:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"> <span style="color:#728e00">public</span> <span style="color:#728e00">static</span> <span style="color:#434f54">User_V1_0</span> <span style="color:#d35400">Build</span><span style="color:#728e00">(</span><span style="color:#434f54">block</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#728e00">new</span> <span style="color:#434f54">UserBuilder</span><span style="color:#728e00">().</span><span style="color:#434f54">with</span> <span style="color:#434f54">block</span><span style="color:#728e00">;</span>
<span style="color:#95a5a6">// does the same as cloning the block, assigning it with .delegate and executing it.
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">}</span>
</code></pre></div><p>Used this way:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"> <span style="color:#434f54">UserBuilder</span><span style="color:#728e00">.</span><span style="color:#434f54">Build</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">Code</span> <span style="color:#7f8c8d">&#34;AB&#34;</span> <span style="color:#95a5a6">// Same as Code(&#34;AB&#34;);
</span><span style="color:#95a5a6"></span> <span style="color:#434f54">Type</span> <span style="color:#434f54">UserType_V1_0</span><span style="color:#728e00">.</span><span style="color:#434f54">NursingStaff</span>
<span style="color:#728e00">}</span>
</code></pre></div><p>How does this work?</p>
<ul>
<li>The <code>Code()</code> method does not exist in our block closure, but we assign a delegate to it: our temp lexically scoped <code>UserBuilder</code> instance - that&rsquo;s where the method lives. When the code is executed, Groovy first looks for a method within the block, and then tries to fetch it via the delegate.</li>
</ul>
<p>For more information on groovy delegates, see the <a href="http://groovy.codehaus.org/Delegation+Pattern">Groovy documentation: Delegation Pattern</a>. This works thanks to the late binding of the language and won&rsquo;t statically typed languages such as C#. You might be able to come close using <code>LINQ</code> expression trees, but that requires a lot of effort to write a simple DSL.</p>
<h3 id="leveraging-this-principle-to-dsls">Leveraging this principle to DSLs</h3>
<p>In Javascript, you can also manage to do something like that using <code>.prototype</code> and <a href="http://brainbaking.com/wiki/code/javascript/inheritance">prototypal inheritance</a> and <code>apply()</code> to dynamically bind the <code>this</code> context (see <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply">Function.prototype.apply MDN</a>).</p>
<p>Of course, builders are completely redundant in JS. Just create a <code>JSON</code> object using <code>{ key: value }</code>. Done. But this principle might be interesting for things like creating a &ldquo;mailer&rdquo; - as in the devoxx 2013 example:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">mailerPrototype</span> <span style="color:#728e00">=</span> {
<span style="color:#728e00">from</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;from&#34;</span>); },
<span style="color:#728e00">to</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;to&#34;</span>); },
<span style="color:#728e00">sub</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;sub&#34;</span>); },
<span style="color:#728e00">body</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;body&#34;</span>); },
<span style="color:#728e00">send</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;sending...&#34;</span>); }
};
<span style="color:#728e00">var</span> <span style="color:#728e00">mailer</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {};
<span style="color:#728e00">mailer</span>.<span style="color:#728e00">mail</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>(<span style="color:#728e00">block</span>) {
<span style="color:#95a5a6">// .prototype magic happens inside Object.create()
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">block</span>.<span style="color:#728e00">apply</span>(<span style="color:#728e00">Object</span>.<span style="color:#728e00">create</span>(<span style="color:#728e00">mailerPrototype</span>));
}
<span style="color:#95a5a6">// this still sucks, I don&#39;t want to use &#39;this.&#39;, can use chaining...
</span><span style="color:#95a5a6"></span><span style="color:#728e00">mailer</span>.<span style="color:#728e00">mail</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">from</span>(<span style="color:#7f8c8d">&#34;me@gmail.com&#34;</span>);
<span style="color:#728e00">this</span>.<span style="color:#728e00">to</span>(<span style="color:#7f8c8d">&#34;you@gmail.com&#34;</span>);
<span style="color:#728e00">this</span>.<span style="color:#728e00">sub</span>(<span style="color:#7f8c8d">&#34;this is my subject&#34;</span>);
<span style="color:#728e00">this</span>.<span style="color:#728e00">body</span>(<span style="color:#7f8c8d">&#34;hello&#34;</span>);
<span style="color:#728e00">this</span>.<span style="color:#728e00">send</span>();
});
</code></pre></div><p><code>You'll still need </code>this.`, sadly. This is not needed in Groovy:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">mailer</span>.<span style="color:#728e00">mail</span> {
<span style="color:#728e00">from</span> <span style="color:#7f8c8d">&#34;me@gmail.com&#34;</span>
<span style="color:#728e00">to</span> <span style="color:#7f8c8d">&#34;you@gmail.com&#34;</span>
<span style="color:#728e00">sub</span> <span style="color:#7f8c8d">&#34;this is my subject&#34;</span>
<span style="color:#728e00">body</span> <span style="color:#7f8c8d">&#34;hello&#34;</span>
<span style="color:#728e00">send</span>()
}
</code></pre></div><p>`
Now <strong>that</strong> looks readable. To be able to create something like that, a language has to:</p>
<ul>
<li>have functions as first-class citizens.</li>
<li>have a clean syntax, to be able to reduce a lot of noise (CoffeeScript can get this done for JS for instance)</li>
<li>have late binding or duck typing</li>
</ul>
<p>That said, going back to Java 7 is going to be a major pain in the ass. No, I do not want to create usesless interfaces! (Tip: use <code>Function</code> and <code>Predicate</code> from <a href="https://code.google.com/p/guava-libraries/">Google Guava</a>).</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 14 November 2013.
</p>
]]>
</description>
</item>
<item>
<title>Integration Testing with SQLite</title>
<link>https://brainbaking.com/post/2013/11/integration-testing-sqlite/</link>
<comments>https://brainbaking.com/post/2013/11/integration-testing-sqlite/#commento</comments>
<pubDate>Mon, 04 Nov 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/11/integration-testing-sqlite/</guid>
<category domain="https://brainbaking.com/tags/unit testing">unit testing</category>
<category domain="https://brainbaking.com/tags/sql">sql</category>
<category domain="https://brainbaking.com/tags/CSharp">CSharp</category>
<category domain="https://brainbaking.com/tags/sqlite">sqlite</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Integration%20Testing%20with%20SQLite.jpg"/>
</p>
<p>On previous projects I&rsquo;ve worked on, development PCs came with a local version of the database scheme. Each DB change also got rolled out to those computers, which enabled us developers to fool around without breaking anything on the development (or test) environment. This is another step closer to happiness, at least for our proxy customers who didn&rsquo;t have to reinsert their test data every time we flushed something from a table. Sometimes though, there&rsquo;s some lame excuse for not having a local database installed:</p>
<ul>
<li>We have a lot of stored procedures and it&rsquo;s too hard to duplicate them locally</li>
<li>We worked like this for years, why would I want a local DB?</li>
<li>But then my data is out of sync!</li>
<li>I tried doing that but my manager says I should focus on delivering content</li>
<li>Blah blah blah</li>
</ul>
<p>Installing an Oracle XE runtime on your machine might include working around some issues which can take up some time but it&rsquo;s time well invested, compared to multiple developers connecting to one shared database. In any case, there&rsquo;s another possibility: an <strong>in-memory database</strong>, such as <a href="http://www.sqlite.org/">SQLite</a>. This does still require you to keep the upgrade scripts synced, but also enables you to get rid of a lot of annoying things like <em>foreign key constraints</em> for testing purposes.</p>
<h3 id="integrating-sqlite-with-net">Integrating SQLite with .NET</h3>
<p>Simply use <a href="http://system.data.sqlite.org/index.html/doc/trunk/www/index.wiki">System.data.SQLite</a>. For each OleDb object, there&rsquo;s an equivalent SQLite one in the correct namespace. The only problem is, some of them don&rsquo;t share an abstract object so you&rsquo;ll have to come up with an anti-corruption layer yourself. Create a connection using this connection string:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c#" data-lang="c#"><span style="color:#728e00">private</span> <span style="color:#434f54">SQLiteConnection</span> <span style="color:#434f54">SqLiteDbConnection</span>()
{
<span style="color:#728e00">return</span> <span style="color:#728e00">new</span> <span style="color:#434f54">SQLiteConnection</span>()
{
<span style="color:#434f54">ConnectionString</span> = <span style="color:#7f8c8d">&#34;Data Source=:memory:;Version=3;New=True;DateTimeFormat=Ticks&#34;</span>,
<span style="color:#434f54">Flags</span> = <span style="color:#434f54">SQLiteConnectionFlags</span>.<span style="color:#434f54">LogAll</span>
};
}
<span style="color:#728e00">public</span> <span style="color:#728e00">void</span> <span style="color:#434f54">SetupDb</span>()
{
<span style="color:#728e00">using</span> (<span style="color:#00979d">var</span> <span style="color:#434f54">connection</span> = <span style="color:#434f54">SqLiteDbConnection</span>())
{
<span style="color:#434f54">connection</span>.<span style="color:#434f54">Open</span>();
<span style="color:#00979d">var</span> <span style="color:#434f54">transaction</span> = <span style="color:#434f54">connection</span>.<span style="color:#434f54">BeginTransaction</span>();
<span style="color:#00979d">var</span> <span style="color:#434f54">sqLiteCommand</span> = <span style="color:#728e00">new</span> <span style="color:#434f54">SQLiteCommand</span>()
{
<span style="color:#434f54">Connection</span> = (<span style="color:#434f54">SQLiteConnection</span>) <span style="color:#434f54">connection</span>,
<span style="color:#434f54">CommandType</span> = <span style="color:#434f54">CommandType</span>.<span style="color:#434f54">Text</span>,
<span style="color:#434f54">CommandText</span> = <span style="color:#434f54">GetSchemaCreateSql</span>()
};
<span style="color:#434f54">sqLiteCommand</span>.<span style="color:#434f54">ExecuteNonQuery</span>();
<span style="color:#434f54">transaction</span>.<span style="color:#434f54">Commit</span>();
}
}
</code></pre></div><p>You need to pay attention to the <code>DateTimeFormat</code> substring in the connection string as SQLite is &ldquo;dynamically typed&rdquo;, compared to Oracle. This means it stores dates exactly the same as chars, otherwise you might encounter an error like <code>&quot;string was not recognized as a valid DateTime&quot;</code> when executing a select statement.</p>
<p><strong>Watch out with closing the DB Connection</strong> using an in-memory DB; as this completely resets everything. As soon as you open a connection, you can execute create table commands (read your stored DDL file and do it in bulk).
Your anti-corruption layer between the abstract DB Connection and SQLite/OleDB should expose a few methods. It should be able to query (with or without parameters or providing a <code>DbCommand</code>) and possibly stored procedures. This is what I&rsquo;ve come up with:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C#" data-lang="C#"><span style="color:#728e00">public</span> <span style="color:#728e00">interface</span> <span style="color:#434f54">IdbConnection</span>
{
<span style="color:#00979d">object</span> <span style="color:#434f54">QueryProcedure</span>(<span style="color:#00979d">string</span> <span style="color:#434f54">procedure</span>, <span style="color:#434f54">IDictionary</span>&lt;<span style="color:#00979d">string</span>, <span style="color:#00979d">object</span>&gt; <span style="color:#434f54">parameters</span>, <span style="color:#00979d">string</span> <span style="color:#434f54">outputParameter</span>);
<span style="color:#434f54">DbParameter</span> <span style="color:#434f54">CreateParameter</span>(<span style="color:#00979d">string</span> <span style="color:#434f54">field</span>, <span style="color:#00979d">object</span> <span style="color:#728e00">value</span>);
<span style="color:#434f54">DbCommand</span> <span style="color:#434f54">CreateCommand</span>(<span style="color:#00979d">string</span> <span style="color:#434f54">query</span>);
<span style="color:#434f54">DataSet</span> <span style="color:#434f54">Query</span>(<span style="color:#434f54">DbCommand</span> <span style="color:#434f54">command</span>);
<span style="color:#434f54">DataSet</span> <span style="color:#434f54">Query</span>(<span style="color:#00979d">string</span> <span style="color:#434f54">query</span>);
}
</code></pre></div><p>Depending on the implementation, it&rsquo;ll return an <code>SQLiteCommand</code> or an <code>OleDbCommand</code> instance.</p>
<h3 id="creating-integration-tests-using-record-objects">Creating integration tests, using Record objects</h3>
<p>To be able to quickly insert junk in an in-memory table, I came up with a simple object-table mapping which uses reflection to scan for each property of an object, and map that property to a column in a table. Normally you would simply use your domain objects and issue a <code>save()</code> or <code>persist()</code> call using for instance <code>NHibernate</code> but we didn&rsquo;t have anything like that and this was easy to setup.</p>
<p>Create an object for each table in your unit test project, extending <code>DatabaseInsertable</code>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C#" data-lang="C#"><span style="color:#728e00">public</span> <span style="color:#728e00">abstract</span> <span style="color:#728e00">class</span> <span style="color:#434f54">DatabaseInsertable</span>
{
<span style="color:#728e00">protected</span> <span style="color:#728e00">abstract</span> <span style="color:#00979d">string</span> <span style="color:#434f54">GetTable</span>();
<span style="color:#728e00">public</span> <span style="color:#728e00">override</span> <span style="color:#00979d">string</span> <span style="color:#434f54">ToString</span>()
{
<span style="color:#00979d">var</span> <span style="color:#434f54">fieldDict</span> = <span style="color:#434f54">FieldDictionary</span>();
<span style="color:#00979d">var</span> <span style="color:#434f54">fields</span> = <span style="color:#7f8c8d">&#34;(&#34;</span> + <span style="color:#00979d">string</span>.<span style="color:#434f54">Join</span>(<span style="color:#7f8c8d">&#34;,&#34;</span>, <span style="color:#434f54">fieldDict</span>.<span style="color:#434f54">Keys</span>) + <span style="color:#7f8c8d">&#34;)&#34;</span>;
<span style="color:#00979d">var</span> <span style="color:#434f54">values</span> = <span style="color:#7f8c8d">&#34;(&#34;</span> + <span style="color:#00979d">string</span>.<span style="color:#434f54">Join</span>(<span style="color:#7f8c8d">&#34;,&#34;</span>, <span style="color:#434f54">fieldDict</span>.<span style="color:#434f54">Values</span>) + <span style="color:#7f8c8d">&#34;)&#34;</span>;
<span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;insert into &#34;</span> + <span style="color:#434f54">GetTable</span>() + <span style="color:#434f54">fields</span> + <span style="color:#7f8c8d">&#34; values &#34;</span> + <span style="color:#434f54">values</span>;
}
<span style="color:#728e00">public</span> <span style="color:#728e00">void</span> <span style="color:#434f54">Save</span>()
{
<span style="color:#434f54">DbConnection</span>.<span style="color:#434f54">Instance</span>.<span style="color:#434f54">CreateCommand</span>(<span style="color:#434f54">ToString</span>()).<span style="color:#434f54">ExecuteNonQuery</span>();
}
<span style="color:#728e00">private</span> <span style="color:#434f54">Dictionary</span>&lt;<span style="color:#00979d">string</span>, <span style="color:#00979d">string</span>&gt; <span style="color:#434f54">FieldDictionary</span>()
{
<span style="color:#00979d">var</span> <span style="color:#434f54">dictionary</span> = <span style="color:#728e00">new</span> <span style="color:#434f54">Dictionary</span>&lt;<span style="color:#00979d">string</span>, <span style="color:#00979d">string</span>&gt;();
<span style="color:#728e00">foreach</span> (<span style="color:#00979d">var</span> <span style="color:#434f54">info</span> <span style="color:#728e00">in</span> <span style="color:#728e00">this</span>.<span style="color:#434f54">GetType</span>().<span style="color:#434f54">GetFields</span>())
{
<span style="color:#728e00">if</span> (<span style="color:#434f54">info</span>.<span style="color:#434f54">GetValue</span>(<span style="color:#728e00">this</span>) != <span style="color:#728e00">null</span>)
{
<span style="color:#434f54">dictionary</span>.<span style="color:#434f54">Add</span>(<span style="color:#434f54">info</span>.<span style="color:#434f54">Name</span>, <span style="color:#7f8c8d">&#34;&#39;&#34;</span> + <span style="color:#434f54">info</span>.<span style="color:#434f54">GetValue</span>(<span style="color:#728e00">this</span>).<span style="color:#434f54">ToString</span>() + <span style="color:#7f8c8d">&#34;&#39;&#34;</span>);
}
}
<span style="color:#728e00">return</span> <span style="color:#434f54">dictionary</span>;
}
}
</code></pre></div><p>For instance:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-C#" data-lang="C#"><span style="color:#728e00">internal</span> <span style="color:#728e00">class</span> <span style="color:#434f54">UnitRecord</span> : <span style="color:#434f54">DatabaseInsertable</span>
{
<span style="color:#728e00">public</span> <span style="color:#00979d">string</span> <span style="color:#434f54">creator</span>;
<span style="color:#728e00">public</span> <span style="color:#00979d">string</span> <span style="color:#434f54">guid</span>;
<span style="color:#728e00">protected</span> <span style="color:#728e00">override</span> <span style="color:#00979d">string</span> <span style="color:#434f54">GetTable</span>()
{
<span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;UNIT&#34;</span>;
}
}
</code></pre></div><p>Now you can simply issue <code>new UnitRecord() { creator = &quot;bla&quot;; guid = &quot;lala&quot;; }.Save();</code> and it&rsquo;s saved into the unit table, yay!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 4 November 2013.
</p>
]]>
</description>
</item>
<item>
<title>Visual Studio 2012 for Eclipse users</title>
<link>https://brainbaking.com/post/2013/10/vstudio-missing-features/</link>
<comments>https://brainbaking.com/post/2013/10/vstudio-missing-features/#commento</comments>
<pubDate>Mon, 14 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/vstudio-missing-features/</guid>
<category domain="https://brainbaking.com/tags/visual studio">visual studio</category>
<category domain="https://brainbaking.com/tags/eclipse">eclipse</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Visual%20Studio%202012%20for%20Eclipse%20users.jpg"/>
</p>
<p>When switching over to a new editor and new language, I can sometimes get frustrated by missing features I got (very) attached to. This excludes the obvious difference in shortcut keys.</p>
<h3 id="shortcuts-and-refactoring-tools">Shortcuts and refactoring tools </h3>
<p>One plugin to rule them all: <a href="http://www.jetbrains.com/resharper/">ReSharpner</a>. This productivity tool brings back the incredible development speed to the Visual Studio platform. You can almost map the eclipse (or IntelliJ, since they guys from JetBrains developed it) keys to the ReSharpner keys. If you&rsquo;re used to quickly refactor out variables, introduce classes from parameters or create test classes, you&rsquo;ll be in heaven.</p>
<p>The following shortcuts can be mapped (you&rsquo;re welcome):</p>
<table>
<thead>
<tr>
<th><strong>Eclipse shortcut</strong></th>
<th><strong>ReSharpner shortcut</strong></th>
<th><strong>description</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>CTRL+D</td>
<td>CTRL+L</td>
<td>remove line</td>
</tr>
<tr>
<td>ALT+DOWN</td>
<td>CTRL+D</td>
<td>duplicate line</td>
</tr>
<tr>
<td>CTRL+SPACE (CTRL+ENTER)</td>
<td>CTRL+SPACE (TAB)</td>
<td>code completion, select in combobox</td>
</tr>
<tr>
<td>ALT+SHIFT+UP/DOWN</td>
<td>CTRL+ALT+LEFT/RIGHT</td>
<td>Extend/Shrink selection</td>
</tr>
<tr>
<td>CTRL+SHIFT+/</td>
<td>CTRL+ALT+/</td>
<td>commend line</td>
</tr>
<tr>
<td>CTRL+SHIFT+1</td>
<td>ALT+ENTER</td>
<td>quick fix</td>
</tr>
<tr>
<td>ALT+UP/DOWN</td>
<td>CTRL+SHIFT+ALT+UP/DOWN</td>
<td>move line</td>
</tr>
<tr>
<td>CTRL+SHIFT+O</td>
<td>CTRL+E, (C)/F</td>
<td>organize imports (and format etc, F = silent)</td>
</tr>
<tr>
<td>CTRL+F11</td>
<td>CTRL+U, U</td>
<td>rerun last</td>
</tr>
<tr>
<td>CTRL+O</td>
<td>ALT+\</td>
<td>Go to file member</td>
</tr>
<tr>
<td>CTRL+SHIFT+G</td>
<td>CTRL+SHIFT+ALT+F12 (SHIFT+F12)</td>
<td>find usages</td>
</tr>
<tr>
<td>F3</td>
<td>F12</td>
<td>go to definition</td>
</tr>
<tr>
<td>CTRL+SHIFT+.</td>
<td>SHIFT+ALT+PGDN</td>
<td>go to next error</td>
</tr>
<tr>
<td>CTR+,</td>
<td>SHIFT+ALT+PGUP</td>
<td>go to previous error</td>
</tr>
<tr>
<td>ALT+SHIFT+I</td>
<td>CTRL+R, I</td>
<td>inline variable</td>
</tr>
<tr>
<td>ALT+SHIFT+R</td>
<td>CTRL+R, R</td>
<td>rename</td>
</tr>
<tr>
<td>ALT+SHIFT+M</td>
<td>CTRL+R, M</td>
<td>extract method</td>
</tr>
<tr>
<td>ALT+SHIFT+C</td>
<td>CTRL+R, S</td>
<td>change method signature</td>
</tr>
<tr>
<td>CTRL+SHIFT+B</td>
<td>F9</td>
<td>toggle breakpoint</td>
</tr>
<tr>
<td>CTRL+M</td>
<td>SHIFT+ALT+ENTER</td>
<td>toggle full screen mode</td>
</tr>
<tr>
<td>&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&ndash;</td>
<td>&mdash;&mdash;&mdash;&mdash;</td>
<td>&mdash;&mdash;&ndash;</td>
</tr>
</tbody>
</table>
<p>Other interesting links:</p>
<ul>
<li><a href="http://www.jetbrains.com/resharper/docs/ReSharper70DefaultKeymap_IDEA_scheme.pdf">Default keymap PDF overview</a></li>
<li><a href="http://www.jetbrains.com/resharper/docs/ReSharper70DefaultKeymap_IDEA_scheme.pdf">IntelliJ keymap PDF overview</a></li>
</ul>
<h3 id="comparing-files-with-each-other">Comparing files with each other </h3>
<p>Simply comparing two files within the editor can be a pain - the easiest way to do it in Eclipse is just select both files, rightclick and select &ldquo;compare&rdquo;. No such option here. You can compare a file with a previous version from TFS, but not two physically different files, weird. Install <a href="http://vscommands.squaredinfinity.com/">VSCommands</a> and that problem is also solved:</p>
<p><figure>
<a href="../compare_files_vstudio2012.png" class="lbox">
<img loading="lazy" src="../compare_files_vstudio2012.png" alt="compare files in vstudio" >
</a>
</figure>
</p>
<p>It uses the built-in VS2012 comparison window, which is quite nice.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 14 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>Learning to become a baker</title>
<link>https://brainbaking.com/post/2013/10/learning-to-become-a-baker/</link>
<comments>https://brainbaking.com/post/2013/10/learning-to-become-a-baker/#commento</comments>
<pubDate>Sun, 13 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/learning-to-become-a-baker/</guid>
<category domain="https://brainbaking.com/tags/braindump">braindump</category>
<category domain="https://brainbaking.com/tags/learning">learning</category>
<category domain="https://brainbaking.com/tags/baking">baking</category>
<category domain="https://brainbaking.com/tags/bread">bread</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/baker.jpg"/>
</p>
<p>Originally posted on <a href="https://medium.com/this-happened-to-me/learning-to-become-a-baker-99c0d2c3388a">Medium</a>.</p>
<h4 id="addendum">Addendum</h4>
<p><a href="https://redzuurdesem.be">Red Zuurdesem</a>, my website about baking with sourdough, has been active since 2012, and still is. I hold a <em>professional bread baker&rsquo;s degree</em> since 2016 - this article was written during the first year when I enrolled in the course.</p>
<hr/>
<p>Sometimes people tell me Im obsessed with bread. Thats not entirely my fault. (I like to blame others, who doesnt?) When I was little, my father always baked our own bread on sunday, every single sunday. I cant remember anytime we actually bought bread, except on vacation. At a young age I had no idea how creating something out of nothing actually worked, but I knew it was intriguingthe addition of yeast which caused the dough to bubble up within a short period of time, wow!</p>
<p>When I grew older, I lost my interest in food in generalI had other worries such as studying. (well, and girlfriends, but thats a part of studying!) I have two sisters and we never cooked, our parents always did that. The only thing that remained was the joy of eating a freshly baked slice of bread at sunday after all the breads have been cut and packagedmy father baked enough for the freezer to use throughout the week.
When we ate pizzawith homemade dough of coursethere was always some dough left over to create a “pizza bread” with. The dough was “special” because of the ingredients: a 100% white wheat bread with olive oil, extra sweet. We always fought to get the most slices, usually spread with an even sweeter Nutella. I think the tradition of eating chocolate spread on white bread started there.</p>
<h3 id="having-to-do-it-yourself">Having to do it yourself</h3>
<p>Eating without cooking it yourself abruptly stopped when I rented an appartment. The interest in cooking and baking remained so I started experimenting myself. After a year, I received a bread baking machine for my birthdayyou know, one of those little things where you need to simply weigh all the required ingredients, throw them in there and push “start”. 4 hours later, the irresistible smell of freshly baked bread would fill the kitchen. Great, I baked something! What should I do with it? Wheres my Nutella?</p>
<p>It didnt stop there, that was only the beginning. I started researching on the internet, gathering more and more recipes, experimenting with the bread baking machine on using different flours, mixing them with fruits and nuts. (using fresh kiwis was a failure, but hey, at least I tried, right?)
After another year, I stumbled upon one of the many food blogs, “<a href="http://foodwishes.blogspot.be/2008/03/follow-sourdough-day-1-can-you-say.html">Food wishes</a>” with chef John, where he explained the process of creating a “sourdough”. In Belgium, bakers dont use sourdough, so I didnt even know what that meant. It was so fascinating that I decided to try that myself.</p>
<p><figure>
<a href="/img/brood1.jpg" class="lbox">
<img loading="lazy" src="/img/brood1.jpg" alt="Most people I bake for even complain about the “holes”their chocolate spread drops through them!" >
</a>
</figure>
<em>Most people I bake for even complain about the “holes”their chocolate spread drops through them!</em></p>
<p>Which of course worked with enough patience. As soon as my sourdough starter was active, I got really obsessed with baking bread.Not just bread, but <strong>bread</strong>the real stuff, hand crafted, with (sometimes extremely) long fermentation times. I gave away my bread baking machine (and made someone else happy with their first baking experience) and started investing my time and money in artisan bread baking books like “Bread”. I had to order everything on the internet as I couldnt find a single book on the topic locally which is very,<em>very</em> sad.</p>
<h3 id="deciding-to-do-it-even-better">Deciding to do it even better</h3>
<p>This week is week four in the three year long official baker course. I enrolled into the program with a clear vision on how I would open up a speciality bakery, only baking sourdough bread with long fermentation times and extreme taste and smell. My father doesnt like sourdough. Actually, almost nobody I know does. Why is that? We grew up eating fastly fermented bread with high amounts of commercial yeast. The more yeast added (with chemical flour stabilizers of course) the quicker the baker can bake them, the more he can create and sell. $$$ (in our case €€€), dingding.
I had some trouble finding bakeries in the area wich sell real bread. I found one in Brussels and one in Maastricht. There are others but its really sad, most bakers (or at least the assistents who sell the bread) dont even know what sourdough is. (Yes I know this is completely different in countries like Germany or France, but were talking about Belgium here)</p>
<p>So the more I learned about the sad state of bakeries, the more I was determined to do something about it. I created <a href="http://www.redzuurdesem.be">Save Sourdough</a>, a website to promote baking with sourdough yourself. I baked for colleagues and friends, but I still felt that was not enough. So I finally enrolled in a bakery course (youre obligated to have that diploma if you want to start a bakery).</p>
<p><figure>
<a href="/img/brood2.jpg" class="lbox">
<img loading="lazy" src="/img/brood2.jpg" alt="Sourdough, all bubbly and ready to roll." >
</a>
</figure>
<em>Sourdough, all bubbly and ready to roll.</em></p>
<p>I knew I should not expect too much, but if you know that after following the course for three years (without any prerequired knowledge), you can open up your own bakery, Id expect it to be thorough.
What a disappointment. We do learn to bake bread: white bread to start with, small round boules we call “pistolets”, fluffy sandwich bread, … But its all the industrial way. All the recipes contain stabilizers. You want pistolets? Okay, just add 4% “pistolet” stabilizer. Baking regular bread or sandwich bread? Use bread or sandwich stabilizer. Those things come in huge bags of 25kg in the class, just as the regular flour (industrial milled with added stabilizer out of the box… great) does. What do they actually contain?</p>
<ul>
<li>lactose (What the fuck? Thats right, lactose intolerant or vegan people, stop buying bread from a “regular” bakery!)</li>
<li>Acids (vinegar-like stuff)</li>
<li>EXYZ numbers, usually coloring stuff, depending on the type</li>
</ul>
<p>When asked about why to actually use a stabilizer, the teacher explains:</p>
<ul>
<li>it helps rise the dough more quickly ($$$/€€€, remember)</li>
<li>it helps keep the dough together when mixing quickly (see above)</li>
<li>it gives more color (if using bad/bland flour, see above)</li>
<li>it prolongs the shelf time (see above)</li>
</ul>
<p>Sourdough bread keeps for a week. Without any additives, because of the thousands of natural little micro-organisms present in the sour. Using lactose helps prolong the shelf time the same way, but it actually requires adding something I dont even want to be present in my bread! You also need a chemical ingredient to make sure the gluten in the (usually wheat) dough dont break when mixed on a high speed. Sourdough bread is not mixed, it is folded. Problem solved. Why dont we do it like this? Requires time. Effort. Not needed, mix up that baby. $$$/€€€.</p>
<p>What a disappointment. I see people jotting down everything the teacher says when answering that question, nodding quickly. I guess they just think “when I want to bake bread, I need stabilizers!”. You dont. When you bake bread, you take your time. Or you do not bake bread at all.
A bulk fermentation of 15 minutes? Come on, are you serious? When I bake sourdough at home, its at least 3 hours! Sometimes even up to 2 days in the fridge.</p>
<p>I know Ill still be learning a lot in this course, so I wont quit (and I need the diploma). I already learned why there arent any real artisan bread bakers anymore. The teaching part is all messed up, so how can we expect or bakeries to actually deliver quality goods? The real learning still has to be done at home (or in another country)provided that someone is willing to learn to do it another way. That last part plays a big role, as most people here dont even like the sourdough taste, even mild bread. They are just used to junk, dont blame them.</p>
<h3 id="after-all-we-are-creatures-of-habit-right">After all, we are creatures of habit, right?</h3>
<p>If that is what we want to be, than it shall be so.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 13 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>Unit Testing Stored Procedures</title>
<link>https://brainbaking.com/post/2013/10/unit-testing-stored-procedures/</link>
<comments>https://brainbaking.com/post/2013/10/unit-testing-stored-procedures/#commento</comments>
<pubDate>Thu, 10 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/unit-testing-stored-procedures/</guid>
<category domain="https://brainbaking.com/tags/unit testing">unit testing</category>
<category domain="https://brainbaking.com/tags/sql">sql</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Unit%20Testing%20Stored%20Procedures.jpg"/>
</p>
<p>This article is based on the notes I&rsquo;ve collected on <a href="http://brainbaking.com/wiki/code/db/sql">My Wiki</a>.</p>
<p>Test Driven Development (or TDD), it&rsquo;s one of those buzz words which usuallly appear in the same sentence with &ldquo;scrum&rdquo; or &ldquo;XP&rdquo;. But in practice, I&rsquo;ve seen few people actually applying it all the way through. What do I mean by that? You&rsquo;re probably very familiar with, say Java or .NET, and you know how to write unit tests in that language using your beloved IDE. That&rsquo;s a good start, right. Maybe you might even do it the test-first way: writing a failing test (letting it fail for the right reason), writing the implementation and maybe some refactoring. Red, Green, Refactor.</p>
<p>But what do you do when you need to step out of your language comfort zone to write some Javascript on the client side? Do you copypaste stuff or try to apply the same techniques as you&rsquo;re used to? You might have heard from test frameworks like <a href="http://pivotal.github.io/jasmine/">Jasmine</a> and use these. Also good for you! Client side development is very popular, but what about SQL? Do you write tests for stored procedures? I thought so. There are plenty of frameworks available to help you in doing this, for instance <a href="http://docs.oracle.com/cd/E15846_01/doc.21/e15222/unit_testing.htm">SQL Developer</a> which I used because it&rsquo;s already installed on every developer&rsquo;s PC and has a &ldquo;friendly&rdquo; interface.</p>
<p><figure>
<a href="http://brainbaking.com/wiki/_media/code/db/unittest_sqldev.png" class="lbox">
<img loading="lazy" src="http://brainbaking.com/wiki/_media/code/db/unittest_sqldev.png" alt="sql dev unit test" >
</a>
</figure>
</p>
<p>Once you create a &ldquo;test repository&rdquo;, SQL Developer will create test tables to store it&rsquo;s unit test descriptions and results, prefixed by &ldquo;UT_&rdquo;. You can specify whether you&rsquo;d like to create a new scheme for it or not. When creating a new test, the tool asks you a couple of questions:</p>
<ol>
<li>What do you want to insert or execute before the test? (Setup phase)</li>
<li>What stored procedure do you want to execute? (Execute system under test phase)</li>
<li>What should the result of the procedure be, or execute a query and check it&rsquo;s results? (Verify phase)</li>
<li>What do you want to insert or execute after the test? (Teardown phase)</li>
</ol>
<p>You can reuse the parts to be executed in the different phases for another unit test, yay! This data will also be stored in the predefined tables.</p>
<h3 id="but-what-about-existing-data-when-inserting-new-stuff">But what about existing data when inserting new stuff?</h3>
<p>use this as teardown:</p>
<pre><code>ROLLBACK;
</code></pre>
<h3 id="but-how-do-you-execute-a-stored-procedure-with-inout-ref-cursor-arguments">But how do you execute a stored procedure with IN/OUT REF CURSOR arguments?</h3>
<p>SQL Developer has some trouble executing that, indeed. In this case, we use a little trick:</p>
<ol>
<li>
<p>Create a dummy stored procedure:</p>
<pre><code> create or replace
PROCEDURE UT_DUMMY AS
BEGIN
NULL;
END UT_DUMMY;
</code></pre>
</li>
<li>
<p>Execute the dummy procedure in the SUT phase.</p>
</li>
<li>
<p>Use the verify phase to call the actual to test procedure yourself, and do your verification stuff yourself:</p>
<pre><code> DECLARE
P_USERID NUMBER;
MY_P_CURSOR SCHEMA.PACKAGE.Cursor;
cursor_element MY_P_CURSOR.SCHEMA.CursorType;
found boolean;
BEGIN
P_USERID := 11;
found := false;
PACKAGE.MYPROCEDURE(
P_USERID =&gt; P_USERID,
P_CURSOR =&gt; MY_P_CURSOR
);
WHILE TRUE LOOP
FETCH MY_P_CURSOR INTO cursor_element;
EXIT WHEN MY_P_CURSOR%NOTFOUND;
IF cursor_element.columntocheck = 'My value' THEN
found := true;
END IF;
END LOOP;
IF found = false THEN
raise_application_error(-20000, 'Your error message in here!');
END IF;
END;
</code></pre>
</li>
</ol>
<h3 id="okay-but-what-about-integrating-the-exeuction-of-these-tests-in-my-build-system">Okay but what about integrating the exeuction of these tests in my build system?</h3>
<p>You can use the commandline utility provided by SQL Developer to execute a test or a suite:</p>
<pre><code>ututil -run -suite -name [name] -repo [repo] -db [db] -log 3
</code></pre>
<p>It&rsquo;s very interesting to dynamically import and export tests using &ldquo;-imp&rdquo; and &ldquo;-exp&rdquo;, and creating one suite using this PL/SQL:</p>
<pre><code>SET serveroutput ON;
delete from ut_suite_items;
delete from ut_suite;
DROP SEQUENCE ut_suite_items_seq;
CREATE SEQUENCE ut_suite_items_seq
MINVALUE 0
MAXVALUE 999999999999999999999999999
START WITH 0
INCREMENT BY 1;
DECLARE
suiteid VARCHAR2(900) := 'ALL';
utid VARCHAR2(900);
cursor tableCursor is SELECT UT_ID FROM UT_TEST;
BEGIN
dbms_output.enable(10000);
DBMS_OUTPUT.PUT_LINE('Creating one test suite to rule them ALL...');
insert into ut_suite(ut_sid, coverage, name, created_on, created_by, updated_on, updated_by)
values(suiteid, 0, suiteid, null, null, null, null);
open tableCursor;
fetch tableCursor into utid;
WHILE (tableCursor%FOUND) LOOP
insert into ut_suite_items(ut_sid, ut_id, ut_nsid, run_start, run_tear, sequence, created_on, created_by, updated_on, updated_by)
values (suiteid, utid, null, 'Y', 'Y', ut_suite_items_seq.nextval, null, null, null, null);
fetch tableCursor into utid;
END LOOP;
close tableCursor;
commit;
DBMS_OUTPUT.PUT_LINE('SUCCESS - test suite created!');
END;
/
</code></pre>
<p>It creates only one suite called &lsquo;ALL&rsquo; which can then be executed. The commandline utility will output &ldquo;UT_SUCCESS&rdquo; or throw some kind of exception if one of the tests failed.</p>
<h3 id="i-still-get-errors-using-ututil-some-connectexception">I still get errors using ututil, some ConnectException?</h3>
<p>the utility cannot handle any TNS connections you&rsquo;ve entered in SQL Developer. Change these to regular connection strings and all will be well. Yes it&rsquo;s a huge disadvantage, and yes the connection settings are stored in your locally installed SQL Developer instance, which also kind of sucks. We needed to install SQL developer on the Build integration PC and configure the same connections within it.</p>
<h3 id="what-about-versioning-the-tests-are-stored-in-my-db-but-it-doesnt-evolve-as-quickly-as-the-code-does">What about versioning? The tests are stored in my DB, but it doesn&rsquo;t evolve as quickly as the code does!</h3>
<p>Right, that&rsquo;s where the import/export thing comes in. We store the actual unit tests in XML format inside our regular source control system, next to the &ldquo;other&rdquo; unit tests (in this case in .NET). Every time someone writes a unit test using SQL developer, it extracts that test using:</p>
<pre><code>ututil -exp -test [name] -file [file] ...
</code></pre>
<p>which creates an XML file. Executing the tests happen within a wrapper .NET test class, which goes through some steps to setup the DB system correctly:</p>
<ol>
<li>Cleanup all UT_TEST* and UT_SUITE* tables which would contain the acutal tests.</li>
<li>Loop through all XML files, and impor them one by one (they get inserted into the cleaned tables)</li>
<li>Generate the &lsquo;ALL&rsquo; unit test suite - see PL/SQL above.</li>
<li>Execute the test suite using ututil and parse the results from the command line.</li>
</ol>
<p>That&rsquo;s as far as our imagination and budget goes. We have a stable system which is able to version the XML files - inserting the test data is still dependant on the actual state of the database. One could explore the dynamic creating of tables the stored procedures use, but as our codebase is legacy (read: really really old stuff), we decided not to invest too much time in that.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 10 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>A look at dynamic languages</title>
<link>https://brainbaking.com/post/2013/10/dynamic-languages/</link>
<comments>https://brainbaking.com/post/2013/10/dynamic-languages/#commento</comments>
<pubDate>Tue, 01 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/dynamic-languages/</guid>
<category domain="https://brainbaking.com/tags/javascript">javascript</category>
<category domain="https://brainbaking.com/tags/ruby">ruby</category>
<category domain="https://brainbaking.com/tags/dynamiclangs">dynamiclangs</category>
<description>
<![CDATA[
<h2 id="dynamic-languages-constructs-vergelijken">Dynamic Languages: Constructs vergelijken</h2>
<p>Deze pagina vergelijkt verschillende dynamische talen in een poging om een overzicht te maken tussen de alsmaar groeiende lijst. De meest gebruikte features van zulke talen worden hieronder opgelijst.</p>
<h3 id="het-verschil-tussen-mops-en-prototypal-inheritance">Het verschil tussen MOPs en Prototypal inheritance</h3>
<p>❗ Javascript heeft géén <strong>Meta Object Protocol</strong> (MOP) dat de taal dynamisch maakt, maar bouwt verder op prototypes. Dat wil zeggen dat het klassieke inheritance systeem niet bestaat in Javascript, maar wel nagebootst kan worden door objecten te laten afleiden van objecten. De vergelijkingstabellen hieronder tonen hoe Javascript zich kan <em>gedragen</em> als een klassieke OO taal, dat wil niet automatisch zeggen dat dit de beste manier is om JS te gebruiken!</p>
<p>De volgende dynamische talen beschikken wel over een MOP:</p>
<ol>
<li>Groovy</li>
<li>Python</li>
<li>Ruby</li>
<li>Smalltalk dialecten</li>
<li>LISP dialecten (bvb. Runtime MOPs via <code>CLOS</code>)</li>
<li>Perl 6</li>
<li>OpenC++ (bvb. Compiletime MOPs door C++ te parsen en analyseren)</li>
</ol>
<p><a href="http://fingernailsinoatmeal.com/post/292301859/metaprogramming-ruby-vs-javascript">Ruby VS Javascript metaprogramming</a>:</p>
<blockquote>
<p>The most interesting thing about the Javascript example is that it is exactly the same as the example of adding a dynamic method to a class. There is no difference because Javascript functions <strong>are</strong> closures. The ubiquity of closures in Javascript is extremely powerful and, makes metaprogramming very easy.</p>
</blockquote>
<h1 id="vergelijkingstabellen">Vergelijkingstabellen</h1>
<h2 id="dynamica-van-de-taal-metaprogramming">Dynamica van de taal: Metaprogramming</h2>
<h3 id="methods-toevoegen">Methods toevoegen</h3>
<h4 id="op-klasse-niveau">Op klasse niveau</h4>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">String</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">isTrue</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">return</span> <span style="color:#728e00">this</span> <span style="color:#728e00">==</span> <span style="color:#7f8c8d">&#34;true&#34;</span>; }
</code></pre></div><p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">String</span><span style="color:#728e00">.</span><span style="color:#434f54">metaClass</span><span style="color:#728e00">.</span><span style="color:#434f54">isTrue</span> <span style="color:#728e00">=</span> <span style="color:#728e00">{</span> <span style="color:#434f54">delegate</span> <span style="color:#728e00">==</span> <span style="color:#7f8c8d">&#34;true&#34;</span><span style="color:#728e00">}</span>
</code></pre></div><p>Javascript bevat enkele <em>common pitfalls</em> hierrond, zie JS Inheritance.</p>
<p>Groovy staat ook toe om <em>constructors</em> toe te voegen op deze manier. <br/><br/>
Methods &ldquo;lenen&rdquo; gaat ook met de <strong>&amp;.</strong> operator in Groovy om de pointer naar een method vast te krijgen. In JS gewoon de &ldquo;key&rdquo; (methodnaam) als referentie gebruiken.</p>
<h4 id="op-instance-niveau">Op instance niveau</h4>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#7f8c8d">&#34;someString&#34;</span>.<span style="color:#728e00">isTrue</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">return</span> <span style="color:#728e00">this</span> <span style="color:#728e00">==</span> <span style="color:#7f8c8d">&#34;true&#34;</span>;
}
</code></pre></div><p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#7f8c8d">&#34;someString&#34;</span><span style="color:#728e00">.</span><span style="color:#434f54">metaClass</span><span style="color:#728e00">.</span><span style="color:#434f54">isTrue</span> <span style="color:#728e00">=</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">delegate</span> <span style="color:#728e00">==</span> <span style="color:#7f8c8d">&#34;true&#34;</span>
<span style="color:#728e00">}</span>
</code></pre></div><p>Voor beide talen op exact dezelfde manier dus, op een <em>instance</em> zelf.((Groovy 1.6+ heeft dit standaard, anders uw metaClass nog correct aanpassen! Zie <a href="http://groovy.codehaus.org/Per-Instance+MetaClass">http://groovy.codehaus.org/Per-Instance+MetaClass</a> ))</p>
<p>Als Groovy problemen geeft, kan het zijn doordat <code>ExpandoMetaClass</code> niet geconfigureerd staat voor <em>inheritance</em>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">ExpandoMetaClass</span><span style="color:#728e00">.</span><span style="color:#434f54">enableGlobally</span><span style="color:#728e00">()</span>
</code></pre></div><h4 id="methods-catchen">Methods catchen</h4>
<p>Met &ldquo;catchen&rdquo; wordt &ldquo;<em>decoreren</em>&rdquo; bedoeld. van alle calls op van method namen die niet bestaan en doe ermee wat je wilt.</p>
<p><strong>JavaScript</strong></p>
<p><strong>niet</strong> mogelijk</p>
<p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">SomeClass</span><span style="color:#728e00">.</span><span style="color:#434f54">metaClass</span><span style="color:#728e00">.</span><span style="color:#434f54">methodMissing</span> <span style="color:#728e00">=</span> <span style="color:#728e00">{</span> <span style="color:#434f54">name</span><span style="color:#728e00">,</span> <span style="color:#434f54">arguments</span> <span style="color:#728e00">-&gt;</span>
<span style="color:#728e00">switch</span><span style="color:#728e00">(</span><span style="color:#434f54">name</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#728e00">case</span> <span style="color:#7f8c8d">&#34;bla&#34;</span><span style="color:#728e00">:</span> <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;blaing eh&#34;</span>
<span style="color:#728e00">break</span><span style="color:#728e00">;</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">assert</span> <span style="color:#7f8c8d">&#34;blaing eh&#34;</span> <span style="color:#728e00">==</span> <span style="color:#728e00">new</span> <span style="color:#434f54">SomeClass</span><span style="color:#728e00">().</span><span style="color:#434f54">bla</span><span style="color:#728e00">()</span>
</code></pre></div><p>Groovy kan ook <strong>alle methods</strong> opvangen, ook de bestaande, door de MOP hook <code>invokeMethod</code>, <code>get/setProperty</code>, <code>propertyMissing</code> etc te overriden - op <code>Object</code> of <code>metaClass</code> niveau, op deze manier:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#728e00">class</span> <span style="color:#434f54">SomeClass</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">def</span> <span style="color:#d35400">invokeMethod</span><span style="color:#728e00">(</span><span style="color:#434f54">String</span> <span style="color:#434f54">name</span><span style="color:#728e00">,</span> <span style="color:#434f54">args</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#728e00">switch</span><span style="color:#728e00">(</span><span style="color:#434f54">name</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#728e00">case</span> <span style="color:#7f8c8d">&#34;bla&#34;</span><span style="color:#728e00">:</span> <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;blaing eh&#34;</span>
<span style="color:#728e00">break</span><span style="color:#728e00">;</span>
<span style="color:#728e00">default</span><span style="color:#728e00">:</span>
<span style="color:#95a5a6">// delegate.invokeMethod name, arguments makes an infinite loop! it&#39;s a tarp!
</span><span style="color:#95a5a6"></span> <span style="color:#434f54">delegate</span><span style="color:#728e00">.</span><span style="color:#434f54">metaClass</span><span style="color:#728e00">.</span><span style="color:#434f54">getMetaMethod</span><span style="color:#728e00">(</span><span style="color:#434f54">name</span><span style="color:#728e00">,</span> <span style="color:#434f54">arguments</span><span style="color:#728e00">).</span><span style="color:#434f54">invoke</span><span style="color:#728e00">(</span><span style="color:#434f54">delegate</span><span style="color:#728e00">,</span> <span style="color:#434f54">arguments</span><span style="color:#728e00">)</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">}</span>
</code></pre></div><p>En ja, dat werkt <a href="http://groovy.codehaus.org/ExpandoMetaClass+-+Overriding+static+invokeMethod">Ook met static methods in Groovy</a>!</p>
<p>!! Rhino en SpiderMonkey implementaties van JavaScript (Firefox JS parser bijvoorbeeld) ondersteunen wel een magic missing method, genaamd <code>__noSuchMethod__</code> en een hele hoop andere nifty dingen zoals <code>__defineGetter__</code> en <code>__lookupSetter__</code>. Meer informatie in <a href="http://offthelip.org/?p=101">deze blogpost</a> te vinden. Voorbeeld in Firefox+Firebug:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">SomeClass</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">__noSuchMethod__</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>(<span style="color:#728e00">name</span>, <span style="color:#728e00">arguments</span>) {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;calling method &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">name</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34; with arguments &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">arguments</span>);
<span style="color:#728e00">if</span>(<span style="color:#728e00">name</span> <span style="color:#728e00">===</span> <span style="color:#7f8c8d">&#34;bla&#34;</span>) {
<span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;blaing eh&#34;</span>;
}
}
<span style="color:#7f8c8d">&#34;blaing eh&#34;</span> <span style="color:#728e00">==</span> <span style="color:#728e00">new</span> <span style="color:#728e00">SomeClass</span>().<span style="color:#728e00">bla</span>() <span style="color:#95a5a6">// true
</span></code></pre></div><p>Merk op dat in Groovy zoiets niet bestaat, we overriden <strong>ender welke methodCall</strong>, daarom dat in de <code>default</code> van het <code>switch</code> statement nog altijd een delegate invoke moet gebeuren!</p>
<h4 id="properties-toevoegen">Properties toevoegen</h4>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">gapingHoleInTheGalaxy</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {}
<span style="color:#728e00">gapingHoleInTheGalaxy</span>.<span style="color:#728e00">theSun</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;extraHot&#34;</span>; <span style="color:#95a5a6">// method 1
</span><span style="color:#95a5a6"></span><span style="color:#728e00">gapingHoleInTheGalaxy</span>[<span style="color:#7f8c8d">&#39;theSun&#39;</span>] <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;extraHot&#34;</span>; <span style="color:#95a5a6">// method 2
</span><span style="color:#95a5a6"></span><span style="color:#728e00">gapingHoleInTheGalaxy</span>.<span style="color:#728e00">explode</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;Explosion!&#34;</span>)
}
</code></pre></div><p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">def</span> <span style="color:#434f54">gapingHoleInTheGalaxy</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">Expando</span><span style="color:#728e00">()</span>
<span style="color:#434f54">gapingHoleInTheGalaxy</span><span style="color:#728e00">.</span><span style="color:#434f54">theSun</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;extraHot&#34;</span> <span style="color:#95a5a6">// method 1
</span><span style="color:#95a5a6"></span><span style="color:#434f54">gapingHoleInTheGalaxy</span><span style="color:#728e00">[</span><span style="color:#a61717">&#39;</span><span style="color:#434f54">theSun</span><span style="color:#a61717">&#39;</span><span style="color:#728e00">]</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;extraHot&#34;</span> <span style="color:#95a5a6">// method 2
</span><span style="color:#95a5a6"></span><span style="color:#434f54">gapingHoleInTheGalaxy</span><span style="color:#728e00">.</span><span style="color:#434f54">explode</span> <span style="color:#728e00">=</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">println</span> <span style="color:#7f8c8d">&#34;Explosion!&#34;</span>
<span style="color:#728e00">}</span>
</code></pre></div><p>!! Groovy heeft een speciale klasse <code>Expando</code> die dynamisch toelaat om eender wat toe te voegen, zowel <em>closures</em> als <em>properties</em> op dezelfde manier. Enige nadeel: deze code kan niet gemengd worden met Java als byte code. Bij gewone klassen kan dit niet en moet dit via de <code>metaClass</code> gaan. Bij Javascript werkt dit omdat op eender welk moment het prototype van een object veranderd kan worden en er geen onderscheid is tussen closures en functions.</p>
<p>Merk op dat hier de quotes nodig zijn om via de <code>[]</code> operator closures aan iets te hangen.</p>
<p>Het is wél mogelijk om properties via <code>metaClass</code> toe te voegen door de methodnaam de javaBean specificatie te laten volgen, bvb <code>metaClass.getBrol = {}</code> zodat men <code>def x inst.brol</code> kan uitvoeren.</p>
<h4 id="itereren-over-methods">Itereren over methods</h4>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">for</span>(<span style="color:#728e00">propertyName</span> <span style="color:#728e00">in</span> <span style="color:#728e00">someInstance</span>) {
<span style="color:#728e00">var</span> <span style="color:#728e00">propertyValue</span> <span style="color:#728e00">=</span> <span style="color:#728e00">someInstance</span>[<span style="color:#728e00">propertyName</span>]
<span style="color:#728e00">if</span>(<span style="color:#728e00">typeof</span> <span style="color:#728e00">propertyValue</span> <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;function&#34;</span>) {
<span style="color:#728e00">var</span> <span style="color:#728e00">retVal</span> <span style="color:#728e00">=</span> <span style="color:#728e00">eval</span>(<span style="color:#7f8c8d">&#34;someInstance.&#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">propertyName</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34;(args)&#34;</span>); <span style="color:#95a5a6">// method 1
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">retVal</span> <span style="color:#728e00">=</span> <span style="color:#728e00">propertyValue</span>(<span style="color:#728e00">args</span>) <span style="color:#95a5a6">// method 2
</span><span style="color:#95a5a6"></span> } <span style="color:#728e00">else</span> {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">propertyName</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34; property with value &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">propertyValue</span>);
}
}
</code></pre></div><p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">String</span><span style="color:#728e00">.</span><span style="color:#434f54">metaClass</span><span style="color:#728e00">.</span><span style="color:#434f54">methods</span><span style="color:#728e00">.</span><span style="color:#434f54">each</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">methodName</span> <span style="color:#728e00">=</span> <span style="color:#434f54">it</span><span style="color:#728e00">.</span><span style="color:#434f54">name</span> <span style="color:#95a5a6">// now what? methods are on class level
</span><span style="color:#95a5a6"></span> <span style="color:#434f54">def</span> <span style="color:#434f54">retVal</span> <span style="color:#728e00">=</span> <span style="color:#434f54">someInstanceOfString</span><span style="color:#728e00">.</span><span style="color:#7f8c8d">&#34;${methodName}&#34;</span>
<span style="color:#728e00">}</span>
<span style="color:#434f54">someInstanceOfString</span><span style="color:#728e00">.</span><span style="color:#434f54">properties</span><span style="color:#728e00">.</span><span style="color:#434f54">each</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">println</span> <span style="color:#7f8c8d">&#34;${it.key} property with value ${it.value}&#34;</span>
<span style="color:#728e00">}</span>
</code></pre></div><h3 id="variable-arguments">Variable arguments</h3>
<h4 id="varargs-core">varargs core</h4>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">bla</span>() {
<span style="color:#728e00">for</span>(<span style="color:#728e00">arg</span> <span style="color:#728e00">in</span> <span style="color:#728e00">arguments</span>) { <span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">arg</span>); }
}
<span style="color:#728e00">bla</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">2</span>, <span style="color:#8a7b52">3</span>);
</code></pre></div><p><strong>Groovy</strong></p>
<pre><code class="language-javadef" data-lang="javadef">def bla(Object... args) { // classic Java 1.5 method 2
args.each{ println it }
}
bla(1, 2, 3);
}
</code></pre><p>Een map meegeven gaat altijd natuurlijk, om argumenten expressiever te maken, zoals configuratie: (Groovy vb.)</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">def</span> <span style="color:#d35400">bla</span><span style="color:#728e00">(</span><span style="color:#434f54">Map</span> <span style="color:#434f54">args</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">println</span> <span style="color:#434f54">args</span><span style="color:#728e00">.</span><span style="color:#434f54">stuff</span>
<span style="color:#728e00">}</span>
<span style="color:#434f54">bla</span><span style="color:#728e00">(</span><span style="color:#434f54">stuff</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;wow&#34;</span><span style="color:#728e00">,</span> <span style="color:#434f54">c</span><span style="color:#728e00">:</span> <span style="color:#434f54">3</span><span style="color:#728e00">)</span>
</code></pre></div><h4 id="argument-spreading">Argument spreading</h4>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">bla</span>(<span style="color:#728e00">a</span>, <span style="color:#728e00">b</span>) {
<span style="color:#728e00">return</span> <span style="color:#728e00">a</span> <span style="color:#728e00">+</span> <span style="color:#728e00">b</span> <span style="color:#728e00">+</span> <span style="color:#8a7b52">2</span>;
}
<span style="color:#728e00">var</span> <span style="color:#728e00">args</span> <span style="color:#728e00">=</span> [<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">2</span>];
<span style="color:#728e00">bla</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">2</span>) <span style="color:#728e00">==</span> <span style="color:#728e00">bla</span>.<span style="color:#728e00">apply</span>(<span style="color:#728e00">this</span>, <span style="color:#728e00">args</span>) <span style="color:#95a5a6">// 5
</span></code></pre></div><p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">def</span> <span style="color:#d35400">bla</span><span style="color:#728e00">(</span><span style="color:#434f54">a</span><span style="color:#728e00">,</span> <span style="color:#434f54">b</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">a</span> <span style="color:#728e00">+</span> <span style="color:#434f54">b</span> <span style="color:#728e00">+</span> <span style="color:#434f54">2</span>
<span style="color:#728e00">}</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">args</span> <span style="color:#728e00">=</span> <span style="color:#728e00">[</span><span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">2</span><span style="color:#728e00">]</span>
<span style="color:#d35400">bla</span><span style="color:#728e00">(</span><span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">2</span><span style="color:#728e00">)</span> <span style="color:#728e00">==</span> <span style="color:#434f54">bla</span><span style="color:#728e00">(*</span><span style="color:#434f54">args</span><span style="color:#728e00">)</span>
</code></pre></div><h4 id="fixed-arguments">Fixed arguments</h4>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">bla</span>(<span style="color:#728e00">a</span>, <span style="color:#728e00">b</span>, <span style="color:#728e00">c</span>) {
<span style="color:#728e00">if</span>(<span style="color:#728e00">!</span><span style="color:#728e00">c</span>) <span style="color:#728e00">var</span> <span style="color:#728e00">c</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>;
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;a: &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">a</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34;, b: &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">b</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34;, c: &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">c</span>);
}
<span style="color:#728e00">bla</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">2</span>) <span style="color:#95a5a6">// 1, 2, 0
</span><span style="color:#95a5a6"></span><span style="color:#728e00">bla</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">2</span>, <span style="color:#8a7b52">3</span>); <span style="color:#95a5a6">// 1, 2, 3
</span></code></pre></div><p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">def</span> <span style="color:#d35400">bla</span><span style="color:#728e00">(</span><span style="color:#434f54">a</span><span style="color:#728e00">,</span> <span style="color:#434f54">b</span><span style="color:#728e00">,</span> <span style="color:#434f54">c</span> <span style="color:#728e00">=</span> <span style="color:#434f54">0</span><span style="color:#728e00">)</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">println</span> <span style="color:#7f8c8d">&#34;a: $a, b: $b, c: $c&#34;</span>
<span style="color:#728e00">}</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">blaWow</span> <span style="color:#728e00">=</span> <span style="color:#434f54">bla</span><span style="color:#728e00">.</span><span style="color:#434f54">curry</span><span style="color:#728e00">(</span><span style="color:#434f54">1</span><span style="color:#728e00">)</span>
<span style="color:#434f54">blaWow</span><span style="color:#728e00">(</span><span style="color:#434f54">2</span><span style="color:#728e00">)</span> <span style="color:#95a5a6">// 5, 2, 0
</span><span style="color:#95a5a6"></span><span style="color:#434f54">bla</span><span style="color:#728e00">(</span><span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">2</span><span style="color:#728e00">)</span> <span style="color:#95a5a6">// 1, 2, 0
</span><span style="color:#95a5a6"></span><span style="color:#434f54">bla</span><span style="color:#728e00">(</span><span style="color:#434f54">1</span><span style="color:#728e00">,</span> <span style="color:#434f54">2</span><span style="color:#728e00">,</span> <span style="color:#434f54">3</span><span style="color:#728e00">)</span> <span style="color:#95a5a6">// 1, 2, 3
</span></code></pre></div><p>Merk op dat bij JS er gecontroleerd moet worden of een variabele daadwerkelijk is ingevuld of niet. <code>curry</code> is niet standaard aanwezig maar kan eenvoudig geïmplementeerd worden, zoals deze snippet van het <em>Prototype</em> framework:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"> <span style="color:#728e00">function</span> <span style="color:#728e00">curry</span>() {
<span style="color:#728e00">if</span> (<span style="color:#728e00">!</span><span style="color:#728e00">arguments</span>.<span style="color:#728e00">length</span>) <span style="color:#728e00">return</span> <span style="color:#728e00">this</span>;
<span style="color:#728e00">var</span> <span style="color:#728e00">__method</span> <span style="color:#a61717">######</span> <span style="color:#728e00">this</span>, <span style="color:#728e00">args</span> <span style="color:#728e00">slice</span>.<span style="color:#728e00">call</span>(<span style="color:#728e00">arguments</span>, <span style="color:#8a7b52">0</span>);
<span style="color:#728e00">return</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">a</span> <span style="color:#728e00">=</span> <span style="color:#728e00">merge</span>(<span style="color:#728e00">args</span>, <span style="color:#728e00">arguments</span>);
<span style="color:#728e00">return</span> <span style="color:#728e00">__method</span>.<span style="color:#728e00">apply</span>(<span style="color:#728e00">this</span>, <span style="color:#728e00">a</span>);
}
}
</code></pre></div><p>Dit roept in essentie de eigenlijke method op (met <code>apply</code>) met een aantal parameters predefined.</p>
<h4 id="string-interpolatie">String interpolatie</h4>
<p><strong>JavaScript</strong>
<strong>niet</strong> mogelijk</p>
<p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">def</span> <span style="color:#434f54">dinges</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;mijn dingetje&#34;</span>
<span style="color:#7f8c8d">&#34;$dinges is a dong&#34;</span> <span style="color:#728e00">==</span> <span style="color:#7f8c8d">&#34;mijn dingetje is a dong&#34;</span>
</code></pre></div><p>JS extentie om dit mogelijk te maken: zie <a href="http://www.prototypejs.org/api/string/interpolate">Prototype JS interpolate</a>, bvb:<br/><br/>
<code>&quot;#{dinges} is a dong&quot;.interpolate({dinges: &quot;mijn dingetje&quot;}) ###### &quot;mijn dingetje is a dong&quot;</code><br/><br/>
Merk op dat dit eenvoudig een regex door de string laat lopen.</p>
<p>Merk op dat bij Groovy dit zeer krachtig is en hele expressies in strings kunnen gegoten worden zoals <code>&quot;bla ${this.method} jong&quot;</code>. Ook methods aanroepen zoals this.&quot;${methodName}&quot; werkt.</p>
<h4 id="template-parsing">Template parsing</h4>
<p>Grotere brokken tekst interpoleren werkt via <em>templates</em>. In Prototype JS is er een <code>Template</code> klasse <a href="http:*www.prototypejs.org/api/template">aanwezig</a>, in Groovy zit een uitgebreide en uitbreidbare <a href="http:*groovy.codehaus.org/Groovy+Templates">template engine</a>:</p>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">myTemplate</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Template</span>(<span style="color:#7f8c8d">&#39;The TV show #{title} was created by #{author}.&#39;</span>);
<span style="color:#728e00">var</span> <span style="color:#728e00">show</span> <span style="color:#728e00">=</span> {<span style="color:#728e00">title</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;The Simpsons&#39;</span>, <span style="color:#728e00">author</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;Matt Groening&#39;</span>, <span style="color:#728e00">network</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;FOX&#39;</span> };
<span style="color:#728e00">myTemplate</span>.<span style="color:#728e00">evaluate</span>(<span style="color:#728e00">show</span>);
</code></pre></div><p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">def</span> <span style="color:#434f54">string</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;The TV Show ${title} was created by ${author}.&#34;</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">myTemplate</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">groovy</span><span style="color:#728e00">.</span><span style="color:#434f54">text</span><span style="color:#728e00">.</span><span style="color:#434f54">SimpleTemplateEngine</span><span style="color:#728e00">().</span><span style="color:#434f54">createTemplate</span><span style="color:#728e00">(</span><span style="color:#434f54">string</span><span style="color:#728e00">)</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">show</span> <span style="color:#728e00">=</span> <span style="color:#728e00">[</span> <span style="color:#434f54">title</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;The Simpsons&#34;</span><span style="color:#728e00">,</span> <span style="color:#434f54">author</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;Matt Groening&#34;</span><span style="color:#728e00">,</span> <span style="color:#434f54">network</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;FOX&#34;</span> <span style="color:#728e00">]</span>
<span style="color:#434f54">myTemplate</span><span style="color:#728e00">.</span><span style="color:#434f54">make</span><span style="color:#728e00">(</span><span style="color:#434f54">show</span><span style="color:#728e00">).</span><span style="color:#434f54">toString</span><span style="color:#728e00">()</span>
</code></pre></div><h4 id="evaluatie-van-expressies">Evaluatie van expressies</h4>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">y</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">20</span>;
<span style="color:#728e00">var</span> <span style="color:#728e00">X</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">y</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">10</span>;
<span style="color:#728e00">this</span>.<span style="color:#728e00">boem</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">eval</span>(<span style="color:#7f8c8d">&#34;10 * this.y&#34;</span>)); <span style="color:#95a5a6">// 100, without &#34;this&#34; = 200 (window scope)
</span><span style="color:#95a5a6"></span> }
}
<span style="color:#728e00">new</span> <span style="color:#728e00">X</span>().<span style="color:#728e00">boem</span>()
</code></pre></div><p><strong>Groovy</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#728e00">class</span> <span style="color:#434f54">X</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">y</span> <span style="color:#728e00">=</span> <span style="color:#434f54">20</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">boem</span> <span style="color:#728e00">=</span> <span style="color:#728e00">{</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">y</span> <span style="color:#728e00">=</span> <span style="color:#434f54">10</span>
<span style="color:#434f54">println</span> <span style="color:#434f54">Eval</span><span style="color:#728e00">.</span><span style="color:#434f54">x</span><span style="color:#728e00">(</span><span style="color:#434f54">y</span><span style="color:#728e00">,</span> <span style="color:#7f8c8d">&#34;10 * y&#34;</span><span style="color:#728e00">)</span> <span style="color:#95a5a6">// 100
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">}</span>
<span style="color:#728e00">}</span>
<span style="color:#728e00">new</span> <span style="color:#434f54">X</span><span style="color:#728e00">().</span><span style="color:#434f54">boem</span><span style="color:#728e00">()</span>
</code></pre></div><p>Groovy voorziet gemakkelijkheidshalve een paar methods op <code>Eval</code> zoals <code>Eval.me</code> (zonder params), x/xy/xyz. Wanneer iets uitgebreidere evaluatie nodig is gebruiken we <code>GroovyShell</code>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">def</span> <span style="color:#434f54">binding</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">Binding</span><span style="color:#728e00">(</span><span style="color:#434f54">x</span><span style="color:#728e00">:</span> <span style="color:#434f54">10</span><span style="color:#728e00">,</span> <span style="color:#434f54">y</span><span style="color:#728e00">:</span> <span style="color:#434f54">100</span><span style="color:#728e00">)</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">shell</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">GroovyShell</span><span style="color:#728e00">(</span><span style="color:#434f54">binding</span><span style="color:#728e00">)</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">retVal</span> <span style="color:#728e00">=</span> <span style="color:#434f54">shell</span><span style="color:#728e00">.</span><span style="color:#434f54">evaluate</span><span style="color:#728e00">(</span><span style="color:#7f8c8d">&#39;&#39;&#39;</span>
<span style="color:#434f54">def</span> <span style="color:#434f54">local</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;uncatchable&#34;</span>
<span style="color:#434f54">catchable</span> <span style="color:#728e00">=</span> <span style="color:#434f54">x</span> <span style="color:#728e00">*</span> <span style="color:#434f54">y</span>
<span style="color:#434f54">10</span>
<span style="color:#7f8c8d">&#39;&#39;&#39;</span><span style="color:#728e00">)</span>
<span style="color:#728e00">assert</span> <span style="color:#434f54">retVal</span> <span style="color:#a61717">######</span> <span style="color:#434f54">10</span>
<span style="color:#728e00">assert</span> <span style="color:#434f54">binding</span><span style="color:#728e00">.</span><span style="color:#434f54">catchable</span> <span style="color:#a61717">######</span> <span style="color:#434f54">100</span> <span style="color:#95a5a6">// method 1
</span><span style="color:#95a5a6"></span><span style="color:#728e00">assert</span> <span style="color:#434f54">binding</span><span style="color:#728e00">.</span><span style="color:#434f54">getVariable</span><span style="color:#728e00">(</span><span style="color:#7f8c8d">&#34;catchable&#34;</span><span style="color:#728e00">)</span> <span style="color:#a61717">######</span> <span style="color:#434f54">100</span> <span style="color:#95a5a6">// method 2
</span></code></pre></div><p>Alles wat geëvalueerd wordt zit binnen een <code>Script</code> klasse, daarom dat het <code>def</code> keyword niet nodig is, en enkel dient om lokale variabele te instantiëren. Merk op dat het zelfs zo mogelijk is om nieuwe klassen in te laden, of om Groovy code te evalueren met <code>GroovyShell</code> binnen Java klassen!</p>
<h4 id="scope-chain-aanpassen">Scope chain aanpassen</h4>
<p>Dit is voor beide talen niet 100% hetzelfde: Groovy maakt het mogelijk om objecten te extenden on-the-fly met <code>use</code>, terwijl Javascript de lexicale scope chain kan aanpassen met <code>with</code>.</p>
<p><strong>JavaScript</strong></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">with</span>(<span style="color:#728e00">window</span>.<span style="color:#728e00">screen</span>) {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">width</span>);
}
</code></pre></div><p><strong>Groovy</strong></p>
<pre><code>javadir = new File(&quot;/tmp&quot;)
use(ClassWithEachDirMethod.class) {
dir.eachDir {
println it
}
}
</code></pre>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>C&#43;&#43; Basics</title>
<link>https://brainbaking.com/post/2013/10/cplusplus-basics/</link>
<comments>https://brainbaking.com/post/2013/10/cplusplus-basics/#commento</comments>
<pubDate>Tue, 01 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/cplusplus-basics/</guid>
<category domain="https://brainbaking.com/tags/c&#43;&#43;">c&#43;&#43;</category>
<description>
<![CDATA[
<h2 id="scope">Scope</h2>
<p>C++ heeft block level scope, net als Java, alleen is het mogelijk om een variabele binnen een for loop dezelfde naam te geven als een die buiten die block gedefiniëerd is, terwijl dat in Java niet gaat:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#00979d">int</span> <span style="color:#434f54">j</span>;
<span style="color:#728e00">for</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">i</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>; <span style="color:#434f54">i</span> <span style="color:#728e00">&lt;</span> <span style="color:#8a7b52">10</span>; <span style="color:#434f54">i</span><span style="color:#728e00">++</span>) {
<span style="color:#00979d">int</span> <span style="color:#434f54">j</span> <span style="color:#728e00">=</span> <span style="color:#434f54">i</span> <span style="color:#728e00">+</span> <span style="color:#8a7b52">1</span>; <span style="color:#95a5a6">// compile fout in java
</span><span style="color:#95a5a6"></span>}
</code></pre></div><h3 id="pointer-scope">Pointer scope</h3>
<p><a href="https://en.wikipedia.org/wiki/Auto_ptr">auto_ptr</a> kan gebruikt worden om een pointer automatisch te verwijderen met <code>delete</code> wanneer deze scope verliest - alle andere zaken moet je zelf opkuisen.
❗ Dit is deprecated in C++ 11, gebruik <a href="https://en.wikipedia.org/wiki/Smart_pointer#unique_ptr">unique_ptr</a></p>
<p>Voorbeeld van wikipedia:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;iostream&gt;</span><span style="color:#728e00">
</span><span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;memory&gt;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span><span style="color:#434f54">using</span> <span style="color:#434f54">namespace</span> <span style="color:#434f54">std</span>;
<span style="color:#00979d">int</span> <span style="color:#d35400">main</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">argc</span>, <span style="color:#00979d">char</span> <span style="color:#728e00">**</span><span style="color:#434f54">argv</span>)
{
<span style="color:#00979d">int</span> <span style="color:#728e00">*</span><span style="color:#434f54">i</span> <span style="color:#728e00">=</span> <span style="color:#434f54">new</span> <span style="color:#00979d">int</span>;
<span style="color:#434f54">auto_ptr</span><span style="color:#728e00">&lt;</span><span style="color:#00979d">int</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">x</span>(<span style="color:#434f54">i</span>);
<span style="color:#434f54">auto_ptr</span><span style="color:#728e00">&lt;</span><span style="color:#00979d">int</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">y</span>;
<span style="color:#434f54">y</span> <span style="color:#728e00">=</span> <span style="color:#434f54">x</span>;
<span style="color:#434f54">cout</span> <span style="color:#728e00">&lt;&lt;</span> <span style="color:#434f54">x</span>.<span style="color:#434f54">get</span>() <span style="color:#728e00">&lt;&lt;</span> <span style="color:#434f54">endl</span>; <span style="color:#95a5a6">// Print NULL
</span><span style="color:#95a5a6"></span> <span style="color:#434f54">cout</span> <span style="color:#728e00">&lt;&lt;</span> <span style="color:#434f54">y</span>.<span style="color:#434f54">get</span>() <span style="color:#728e00">&lt;&lt;</span> <span style="color:#434f54">endl</span>; <span style="color:#95a5a6">// Print non-NULL address i
</span><span style="color:#95a5a6"></span>
<span style="color:#728e00">return</span> <span style="color:#8a7b52">0</span>;
}
</code></pre></div><h2 id="overloading-virtual">overloading: &lsquo;virtual&rsquo;</h2>
<p>In java wordt by default het diepste gedefiniëerde element opgeroepen, in C++ ben je verplicht <code>virtual</code> te gebruiken als &ldquo;optimalisatie&rdquo; wordt dit standaard niet gedaan&hellip; Voorbeeld:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#434f54">class</span> <span style="color:#434f54">Simple</span>
{
<span style="color:#434f54">public</span>:
<span style="color:#434f54">Simple</span>() <span style="color:#728e00">:</span> <span style="color:#434f54">someMember</span>(<span style="color:#8a7b52">3</span>) {}
<span style="color:#434f54">virtual</span> <span style="color:#00979d">int</span> <span style="color:#434f54">guessNumber</span>();
<span style="color:#00979d">int</span> <span style="color:#434f54">someMember</span>;
};
</code></pre></div><div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#728e00">#include</span> <span style="color:#728e00">&#34;simplecpp.h&#34;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span>
<span style="color:#00979d">int</span> <span style="color:#434f54">Simple</span><span style="color:#728e00">::</span><span style="color:#434f54">guessNumber</span>()
{
<span style="color:#728e00">return</span> <span style="color:#8a7b52">5</span>;
}
</code></pre></div><p>Als je nu <code>guessNumber()</code> wil overschrijven in een subklasse kan dit:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#728e00">#include</span> <span style="color:#728e00">&#34;simplecpp.h&#34;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span>
<span style="color:#434f54">class</span> <span style="color:#434f54">Complexer</span> : <span style="color:#434f54">public</span> <span style="color:#434f54">Simple</span>
{
<span style="color:#434f54">public</span>:
<span style="color:#434f54">Complexer</span>() {}
<span style="color:#00979d">int</span> <span style="color:#434f54">guessNumber</span>();
};
</code></pre></div><p>Merk op, te overschrijven method heropsommen in header file&hellip; (??) - hier hoeft geen <code>virtual</code> meer bij dan.</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#728e00">#include</span> <span style="color:#728e00">&#34;complexer.h&#34;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span>
<span style="color:#00979d">int</span> <span style="color:#434f54">Complexer</span><span style="color:#728e00">::</span><span style="color:#434f54">guessNumber</span>()
{
<span style="color:#728e00">return</span> <span style="color:#8a7b52">10</span>;
}
</code></pre></div><p>Wat is hier de uitkomst van:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c">
<span style="color:#728e00">#include</span> <span style="color:#728e00">&#34;complexer.h&#34;</span><span style="color:#728e00">
</span><span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;iostream&gt;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span>
<span style="color:#00979d">int</span> <span style="color:#d35400">main</span>()
{
<span style="color:#434f54">Simple</span><span style="color:#728e00">*</span> <span style="color:#434f54">simple</span> <span style="color:#728e00">=</span> <span style="color:#434f54">new</span> <span style="color:#434f54">Complexer</span>();
<span style="color:#434f54">std</span><span style="color:#728e00">::</span><span style="color:#434f54">cout</span> <span style="color:#728e00">&lt;&lt;</span> <span style="color:#434f54">simple</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">guessNumber</span>();
<span style="color:#434f54">delete</span> <span style="color:#434f54">simple</span>;
}
</code></pre></div><ol start="10">
<li>Haal <code>virtual</code> weg. 5. <br/><br/>
Definiëer <code>Complexer</code> zo:</li>
</ol>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#434f54">Complexer</span><span style="color:#728e00">*</span> <span style="color:#434f54">complexer</span> <span style="color:#728e00">=</span> <span style="color:#434f54">new</span> <span style="color:#434f54">Complexer</span>();
</code></pre></div><p>En het is altijd 10.</p>
<h2 id="initialisatie">Initialisatie</h2>
<p>(Voorbeelden van bovenstaande)</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#728e00">#include</span> <span style="color:#728e00">&#34;complexer.h&#34;</span><span style="color:#728e00">
</span><span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;iostream&gt;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span>
<span style="color:#00979d">int</span> <span style="color:#d35400">main</span>()
{
<span style="color:#434f54">Simple</span> <span style="color:#434f54">simpleInitialized</span>; <span style="color:#95a5a6">// oops, I created something?
</span><span style="color:#95a5a6"></span> <span style="color:#95a5a6">// Simple simpleInitialized = NULL; cannot convert from &#39;int&#39; to &#39;Simple&#39; (#define NULL 0)
</span><span style="color:#95a5a6"></span>
<span style="color:#434f54">Simple</span><span style="color:#728e00">*</span> <span style="color:#434f54">simplePtr</span>;
<span style="color:#434f54">std</span><span style="color:#728e00">::</span><span style="color:#434f54">cout</span> <span style="color:#728e00">&lt;&lt;</span> <span style="color:#7f8c8d">&#34;&lt;br/&gt;n initialiezd: &#34;</span> <span style="color:#728e00">&lt;&lt;</span> <span style="color:#434f54">simplePtr</span><span style="color:#728e00">-&gt;</span><span style="color:#434f54">someMember</span>;
<span style="color:#95a5a6">// Run-Time Check Failure #3 - The variable &#39;simplePtr&#39; is being used without being initialized
</span><span style="color:#95a5a6"></span>
<span style="color:#434f54">delete</span> <span style="color:#434f54">simplePtr</span>;
}
</code></pre></div><p>Wat is hier speciaal aan?</p>
<ol>
<li>In C++ wordt altijd een object aangemaakt als je ze declareert. In Java niet!</li>
<li>In C++ is <code>NULL</code> gedefiniëerd als <code>#define NULL 0</code> - je kan dus niet zomaar iets toekennen hieraan. In C++ 11 heb je <code>nullptr</code></li>
<li>Je kan wel een pointer declareren zonder een waarde toe te kennen, en dit geeft dan een run-time fout (zou bvb een <code>NullPointerException</code> gooien in java)</li>
</ol>
<h2 id="typecasting">Typecasting</h2>
<p>Uitgebreide uitleg: zie <a href="http://www.cplusplus.com/doc/tutorial/typecasting/">http://www.cplusplus.com/doc/tutorial/typecasting/</a></p>
<p>In C++ is één impliciete conversie mogelijk door middel van de constructor, bijvoorbeeld:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#434f54">class</span> <span style="color:#434f54">Something</span>
{
<span style="color:#434f54">public</span>:
<span style="color:#434f54">Something</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">i</span>) <span style="color:#728e00">:</span> <span style="color:#434f54">myVar</span>(<span style="color:#434f54">i</span>) {}
<span style="color:#434f54">private</span>:
<span style="color:#00979d">int</span> <span style="color:#434f54">myVar</span>;
}
<span style="color:#00979d">int</span> <span style="color:#434f54">getal</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">10</span>;
<span style="color:#434f54">Something</span> <span style="color:#434f54">something</span> <span style="color:#728e00">=</span> <span style="color:#434f54">getal</span>; <span style="color:#95a5a6">// use constructor
</span></code></pre></div><p>Om dit tegen te gaan kan je altijd het <code>explicit</code> keyword gebruiken, zodat je dit moet doen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#434f54">Something</span> <span style="color:#434f54">something</span> <span style="color:#728e00">=</span> <span style="color:#434f54">Something</span>(<span style="color:#434f54">getal</span>); <span style="color:#95a5a6">// expliciet oproepen constructor
</span></code></pre></div><p>Je kan <code>staic_cast&lt;Type&gt;(var)</code> gebruiken om explicit constructors aan te roepen, zo kunnen ze dan toch nog gecast worden.</p>
<h2 id="c-11-goodies">C++ 11 goodies</h2>
<p>Algemeen: <a href="http://www.informit.com/articles/article.aspx?p=1910142">How C++ 11 helps boost your productivity</a></p>
<ol>
<li><a href="http://www.codeproject.com/Articles/277612/Using-lambdas-Cplusplus-vs-Csharp-vs-Cplusplus-CX">Lambdas</a> zijn mogelijk</li>
<li><code>nullptr</code></li>
<li><code>auto</code> keyword, zoals <code>var</code> in C# - dit is typesafe en door de compiler zelf bepaald.</li>
<li>100% multithreading support, zie hieronder</li>
</ol>
<h1 id="linking-objdlls">Linking obj/dlls</h1>
<p>Probleemstelling: verschillende <strong>solutions</strong>, code over solutions heen willen gebruiken.</p>
<p>Dit compileert by default altijd, maar tijdens het linken van de gecompileerde files loopt het mis. Waarom? Omdat er geen <code>dllexport</code> voorzien is.
<br/><br/> Op te lossen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#728e00">#ifndef RESOURCE_UTILS_H
</span><span style="color:#728e00">#define RESOURCE_UTILS_H
</span><span style="color:#728e00"></span>
<span style="color:#728e00">#include</span> <span style="color:#728e00">&#34;Utility.h&#34;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span>
<span style="color:#728e00">#ifdef _DLL
</span><span style="color:#728e00"></span> <span style="color:#728e00">#define DllExImport __declspec(dllexport)
</span><span style="color:#728e00">#else
</span><span style="color:#728e00"></span> <span style="color:#728e00">#define DllExImport __declspec(dllimport)
</span><span style="color:#728e00">#endif
</span><span style="color:#728e00"></span>
<span style="color:#434f54">class</span> <span style="color:#434f54">DllExImport</span> <span style="color:#434f54">ResourceUtils</span>
{
<span style="color:#434f54">public</span>:
<span style="color:#728e00">static</span> <span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">HICON</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">getIcon</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">resourceId</span>);
<span style="color:#728e00">static</span> <span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">HICON</span><span style="color:#728e00">&gt;</span> <span style="color:#434f54">getIcon</span>(<span style="color:#434f54">HINSTANCE</span> <span style="color:#434f54">resourceHandleInstance</span>, <span style="color:#00979d">int</span> <span style="color:#434f54">resourceId</span>);
<span style="color:#434f54">private</span>:
<span style="color:#434f54">ResourceUtils</span>() {}
};
<span style="color:#728e00">#endif
</span></code></pre></div><p>in de cpp file hoeft niets speciaal meer te staan.</p>
<h4 id="functies-exposen-voor-native-calls">Functies exposen voor native calls</h4>
<p>Zelfde principe om klassen te exposen met <code>_ _declspec(dllexport)</code>. Gebruik eventueel std calls (C# heeft dit nodig): <code>DllExImport MyStruct* _ _stdcall GetSignals();</code>.</p>
<h4 id="properties-van-solutions">Properties van solutions</h4>
<h5 id="die-de-te-exporteren-code-bevat">Die de te exporteren code bevat</h5>
<ol>
<li>Configuration type: Dynamic Libraray (DLL)</li>
<li>Incremental linking: Yes (/INCREMENTAL)</li>
<li>Link Linkage Deps: Yes</li>
<li>Output file: *.dll</li>
</ol>
<h5 id="die-de-code-bevat-die-gebruik-maakt-van-de-dll">Die de code bevat die gebruik maakt van de dll</h5>
<ol>
<li>Linker; Input: Additional dependencies ../OtherSolution.lib</li>
</ol>
<h3 id="shared-libraries-linken-in-unix">Shared libraries linken in Unix</h3>
<p><code>declspec</code> is Win32 specifiek. Lees alles over GCC Visibility in <a href="http://gcc.gnu.org/wiki/Visibility">GNU GCC Wiki on Visibility</a>. Komt op dit neer:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#728e00">#if defined(_MSC_VER)
</span><span style="color:#728e00"></span> <span style="color:#95a5a6">// Microsoft
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">#define EXPORT __declspec(dllexport)
</span><span style="color:#728e00"></span> <span style="color:#728e00">#define IMPORT __declspec(dllimport)
</span><span style="color:#728e00">#elif defined(_GCC)
</span><span style="color:#728e00"></span> <span style="color:#95a5a6">// GCC
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">#define EXPORT __attribute__((visibility(&#34;default&#34;)))
</span><span style="color:#728e00"></span> <span style="color:#728e00">#define IMPORT
</span><span style="color:#728e00">#else
</span><span style="color:#728e00"></span> <span style="color:#95a5a6">// do nothing and hope for the best?
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">#define EXPORT
</span><span style="color:#728e00"></span> <span style="color:#728e00">#define IMPORT
</span><span style="color:#728e00"></span> <span style="color:#728e00">#pragma warning Unknown dynamic link import/export semantics.
</span><span style="color:#728e00">#endif
</span></code></pre></div><p>Zie ook <a href="http://www.akkadia.org/drepper/dsohowto.pdf">How to write shared Libraries</a> by Ulrich Drepper.</p>
<h1 id="mfc">MFC</h1>
<p>❗ MFC en AFX <a href="http://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Library">is hetzelfde</a>:</p>
<blockquote>
<p>One interesting quirk of MFC is the use of &ldquo;Afx&rdquo; as the prefix for many functions, macros and the standard precompiled header name &ldquo;stdafx.h&rdquo;. During early development what became MFC was called &ldquo;Application Framework Extensions&rdquo; and abbreviated &ldquo;Afx&rdquo;. The name Microsoft Foundation Classes (MFC) was adopted too late in the release cycle to change these references</p>
</blockquote>
<h3 id="strings-in-mfc">Strings in MFC</h3>
<p>Gebruik <code>CString</code> - werkt niet op non-win32 omgevingen.</p>
<h5 id="formatting">Formatting</h5>
<p>Formatten kan bijvoorbeeld met <code>string.Format(_T(&quot;%s in %d&quot;), otherString, otherDecimal);</code></p>
<p>❗ Om een string te intialiseren en toe te kennen moet je wel de <code>_T</code> macro gebruiken</p>
<h5 id="substringen">Substringen</h5>
<p><code>Find</code> is hetzelfde als <code>indexOf</code> in andere talen.</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c++" data-lang="c++"><span style="color:#434f54">CString</span> <span style="color:#434f54">HostServiceProxy</span><span style="color:#728e00">::</span><span style="color:#434f54">GetCouponFromResponseString</span>(<span style="color:#434f54">CString</span> <span style="color:#434f54">response</span>)
{
<span style="color:#434f54">CString</span> <span style="color:#434f54">couponKey</span> <span style="color:#a61717">######</span> <span style="color:#434f54">_T</span>(<span style="color:#7f8c8d">&#34;Coupon&#34;</span>);
<span style="color:#434f54">CString</span> <span style="color:#434f54">couponPart</span> <span style="color:#728e00">=</span> <span style="color:#434f54">response</span>.<span style="color:#434f54">Mid</span>(<span style="color:#434f54">response</span>.<span style="color:#434f54">Find</span>(<span style="color:#434f54">couponKey</span>) <span style="color:#728e00">+</span> <span style="color:#434f54">couponKey</span>.<span style="color:#434f54">GetLength</span>());
<span style="color:#728e00">return</span> <span style="color:#434f54">couponPart</span>.<span style="color:#434f54">Left</span>(<span style="color:#434f54">couponPart</span>.<span style="color:#434f54">Find</span>(<span style="color:#434f54">_T</span>(<span style="color:#7f8c8d">&#34;;&#34;</span>)));
}
</code></pre></div><h3 id="resource-handling">Resource handling</h3>
<p>Icons en images worden opgeslagen in .rc files die als resources in de code gekoppeld kunnen worden aan bijvoorbeeld een <code>CButton</code>. Hoe?</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"> <span style="color:#434f54">HANDLE</span> <span style="color:#434f54">hImage</span> <span style="color:#728e00">=</span> <span style="color:#728e00">::</span><span style="color:#434f54">LoadImage</span>(<span style="color:#434f54">AfxGetResourceHandle</span>(), <span style="color:#434f54">MAKEINTRESOURCE</span>(<span style="color:#434f54">resourceId</span>), <span style="color:#434f54">IMAGE_ICON</span>, <span style="color:#8a7b52">16</span>, <span style="color:#8a7b52">15</span>, <span style="color:#434f54">LR_DEFAULTCOLOR</span>);
<span style="color:#728e00">if</span>(<span style="color:#434f54">hImage</span> <span style="color:#a61717">######</span> <span style="color:#728e00">NULL</span>)
<span style="color:#434f54">ASSERT</span>(<span style="color:#434f54">FALSE</span>);
<span style="color:#434f54">HICON</span> <span style="color:#434f54">image</span> <span style="color:#728e00">=</span> <span style="color:#434f54">static_cast</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">HICON</span><span style="color:#728e00">&gt;</span>(<span style="color:#434f54">hImage</span>);
</code></pre></div><p><code>HICON</code> is van <code>WinDef.h</code> en <code>::LoadImage</code> zit op <code>WinUser.h</code>. Zie <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx">MSDN doc</a> voor LoadImage.</p>
<h4 id="de-juiste-resource-handle-vastkrijgen">De juiste resource handle vastkrijgen</h4>
<p>Als je een MFC DLL maakt, gaat <code>AfxGetResourceHandle()</code> verwijzen naar de resource handle van uw DLL zelf. Als je dus resources wil vastpakken van een andere DLL heb je pech. Als je geen MFC DLL maakt kan je dit aanpassen met <code> AFX_MANAGE_STATE(AfxGetStaticModuleState( ))</code>. <strong>Dit gooit echter linking errors</strong> ( error LNK2005: _DllMain@12 already defined) indien je dit vanuit een MFC DLL aanroept - dan is dit niet nodig.</p>
<p>Meer uitleg hierover: zie <a href="http://support.microsoft.com/kb/161589">http://support.microsoft.com/kb/161589</a></p>
<p>❗ de Afx resource handle kan <strong>altijd</strong> gewijzigd worden door leuke dingen te doen als:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"> <span style="color:#434f54">HINSTANCE</span> <span style="color:#434f54">old</span> <span style="color:#728e00">=</span> <span style="color:#434f54">AfxGetResourceHandle</span>();
<span style="color:#434f54">AfxSetResourceHandle</span>(<span style="color:#434f54">GetModuleHandle</span>(<span style="color:#7f8c8d">&#34;andereModule&#34;</span>));
</code></pre></div><p>Gebruik daarom best <code>::GetModuleHandle(char*)</code> bij <code>::LoadImage</code>.</p>
<h4 id="resources-op-het-juiste-moment-terug-vrijgeven">Resources op het juiste moment terug vrijgeven</h4>
<p>Resources worden meestal gewrapped in kleine objectjes die bij de constructor de resource alloceren en bij de destructor deze terug vrijgeven in plaats van in <code>try { ... }</code> zoiets te moeten doen in Java. Dit pattern is <a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">RAII</a> of &ldquo;Resource Acquisition Is Initialization&rdquo;. Voorbeeld:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#434f54">template</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">class</span> <span style="color:#434f54">TObject</span><span style="color:#728e00">&gt;</span>
<span style="color:#434f54">class</span> <span style="color:#434f54">RAIIObject</span>
{
<span style="color:#434f54">public</span>:
<span style="color:#434f54">explicit</span> <span style="color:#434f54">RAIIObject</span>(<span style="color:#728e00">const</span> <span style="color:#434f54">TObject</span><span style="color:#728e00">&amp;</span> <span style="color:#434f54">obj</span>) <span style="color:#728e00">:</span> <span style="color:#434f54">m_Object</span>(<span style="color:#434f54">obj</span>) {}
<span style="color:#434f54">RAIIObject</span>() {}
<span style="color:#728e00">~</span><span style="color:#434f54">RAIIObject</span>() {<span style="color:#434f54">ReleaseObject</span>();}
<span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">TObject</span><span style="color:#728e00">&gt;&amp;</span> <span style="color:#434f54">operator</span><span style="color:#a61717">######</span>(<span style="color:#728e00">const</span> <span style="color:#434f54">TObject</span><span style="color:#728e00">&amp;</span> <span style="color:#434f54">obj</span>) {<span style="color:#728e00">if</span>(<span style="color:#728e00">&amp;</span><span style="color:#434f54">obj</span> <span style="color:#728e00">!</span> <span style="color:#728e00">&amp;</span><span style="color:#434f54">m_Object</span>) {<span style="color:#434f54">ReleaseObject</span>(); <span style="color:#434f54">m_Object</span> <span style="color:#728e00">=</span> <span style="color:#434f54">obj</span>;} <span style="color:#728e00">return</span> <span style="color:#728e00">*</span><span style="color:#434f54">this</span>;}
<span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">TObject</span><span style="color:#728e00">&gt;&amp;</span> <span style="color:#434f54">operator</span><span style="color:#a61717">######</span>(<span style="color:#728e00">const</span> <span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">TObject</span><span style="color:#728e00">&gt;&amp;</span> <span style="color:#434f54">obj</span>) {<span style="color:#728e00">if</span>(<span style="color:#728e00">&amp;</span><span style="color:#434f54">obj</span> <span style="color:#728e00">!</span> <span style="color:#434f54">this</span>) {<span style="color:#434f54">ReleaseObject</span>(); <span style="color:#434f54">m_Object</span> <span style="color:#728e00">=</span> <span style="color:#434f54">obj</span>;} <span style="color:#728e00">return</span> <span style="color:#728e00">*</span><span style="color:#434f54">this</span>;}
<span style="color:#434f54">TObject</span><span style="color:#728e00">&amp;</span> <span style="color:#434f54">GetObject</span>() {<span style="color:#728e00">return</span> <span style="color:#434f54">m_Object</span>;}
<span style="color:#728e00">const</span> <span style="color:#434f54">TObject</span><span style="color:#728e00">&amp;</span> <span style="color:#434f54">GetObject</span>() <span style="color:#728e00">const</span> {<span style="color:#728e00">return</span> <span style="color:#434f54">m_Object</span>;}
<span style="color:#434f54">operator</span> <span style="color:#434f54">TObject</span><span style="color:#728e00">&amp;</span>() {<span style="color:#728e00">return</span> <span style="color:#434f54">m_Object</span>;}
<span style="color:#434f54">operator</span> <span style="color:#728e00">const</span> <span style="color:#434f54">TObject</span><span style="color:#728e00">&amp;</span>() <span style="color:#728e00">const</span> {<span style="color:#728e00">return</span> <span style="color:#434f54">m_Object</span>;}
<span style="color:#434f54">private</span>:
<span style="color:#00979d">void</span> <span style="color:#434f54">ReleaseObject</span>();
<span style="color:#434f54">TObject</span> <span style="color:#434f54">m_Object</span>;
};
<span style="color:#434f54">template</span><span style="color:#728e00">&lt;&gt;</span> <span style="color:#00979d">inline</span> <span style="color:#00979d">void</span> <span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">HICON</span><span style="color:#728e00">&gt;::</span><span style="color:#434f54">ReleaseObject</span>() {<span style="color:#728e00">::</span><span style="color:#434f54">DestroyIcon</span>(<span style="color:#434f54">m_Object</span>); <span style="color:#434f54">m_Object</span> <span style="color:#728e00">=</span> <span style="color:#728e00">NULL</span>;}
<span style="color:#434f54">template</span><span style="color:#728e00">&lt;&gt;</span> <span style="color:#00979d">inline</span> <span style="color:#00979d">void</span> <span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">CBrush</span><span style="color:#728e00">&gt;::</span><span style="color:#434f54">ReleaseObject</span>() {<span style="color:#434f54">m_Object</span>.<span style="color:#434f54">DeleteObject</span>();}
<span style="color:#434f54">template</span><span style="color:#728e00">&lt;&gt;</span> <span style="color:#00979d">inline</span> <span style="color:#00979d">void</span> <span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">CBitmap</span><span style="color:#728e00">&gt;::</span><span style="color:#434f54">ReleaseObject</span>() {<span style="color:#434f54">m_Object</span>.<span style="color:#434f54">DeleteObject</span>();}
<span style="color:#434f54">template</span><span style="color:#728e00">&lt;&gt;</span> <span style="color:#00979d">inline</span> <span style="color:#00979d">void</span> <span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">CFont</span><span style="color:#728e00">&gt;::</span><span style="color:#434f54">ReleaseObject</span>() {<span style="color:#434f54">m_Object</span>.<span style="color:#434f54">DeleteObject</span>();}
<span style="color:#434f54">template</span><span style="color:#728e00">&lt;&gt;</span> <span style="color:#00979d">inline</span> <span style="color:#00979d">void</span> <span style="color:#434f54">RAIIObject</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">CMenu</span><span style="color:#728e00">&gt;::</span><span style="color:#434f54">ReleaseObject</span>() {<span style="color:#434f54">m_Object</span>.<span style="color:#434f54">DestroyMenu</span>();}
</code></pre></div><h1 id="preprocessing">Preprocessing</h1>
<h2 id="handige-macros">Handige macro&rsquo;s</h2>
<h5 id="exceptiondebug-informatie-expanden">Exception/Debug informatie expanden</h5>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c++" data-lang="c++"><span style="color:#728e00">#define _ERROR_STR2(a) #a
</span><span style="color:#728e00">#define _ERROR_STR(a) _ERROR_STR2(a)
</span><span style="color:#728e00">#define ERROR_INFO(fn) _T(_ERROR_STR(__FILE__&#34; line: &#34;__LINE__&#34; function: &#34;fn))
</span></code></pre></div><p>Te gebruiken als <code>someFn(ERROR_INFO(&quot;bla&quot;))</code>. Merk op dat <code>__FUNCTION__</code> of <code>__FUNC__</code> ook gebruikt kan worden, afhankelijk van de C++ compiler, maar dit is geen deel van de standaard (vanaf C++ v11).</p>
<p>De <code>#a</code> notatie wordt gebruikt om iets te <a href="http://gcc.gnu.org/onlinedocs/cpp/Stringification.html">stringifyen</a> in de preprocessor, vandaar de delegate:</p>
<blockquote>
<p>Sometimes you may want to convert a macro argument into a string constant. Parameters are not replaced inside string constants, but you can use the # preprocessing operator instead. When a macro parameter is used with a leading #, the preprocessor replaces it with the literal text of the actual argument, converted to a string constant. Unlike normal parameter replacement, the argument is not macro-expanded first. This is called stringification.</p>
</blockquote>
<h1 id="threading">Threading</h1>
<p>Handige links:</p>
<ol>
<li><a href="http://www.codeproject.com/Articles/7953/Thread-Synchronization-for-Beginners">Thread synchronization for beginners</a></li>
</ol>
<h2 id="thread-safe-singleton-pattern">Thread-safe Singleton pattern</h2>
<p>Bijna onmogelijk in C++ &lt; v11 blijkbaar?</p>
<p>Onderstaand voorbeeld gebruikt Win32 code (<code>WaitForSingleObject</code>) en een mutex om te wachten:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c++" data-lang="c++"><span style="color:#728e00">#pragma once
</span><span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;WinBase.h&gt;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span>
<span style="color:#728e00">class</span> <span style="color:#434f54">AddinProcessService</span>
{
<span style="color:#728e00">static</span> <span style="color:#434f54">AddinProcessService</span> <span style="color:#728e00">*</span><span style="color:#434f54">singletonInstance</span>;
<span style="color:#434f54">AddinProcessService</span>() <span style="color:#728e00">:</span> <span style="color:#434f54">m_coupon</span>(<span style="color:#434f54">_T</span>(<span style="color:#7f8c8d">&#34;&#34;</span>)), <span style="color:#434f54">m_hostServiceAddress</span>(<span style="color:#434f54">_T</span>(<span style="color:#7f8c8d">&#34;&#34;</span>)) {}
<span style="color:#728e00">public</span><span style="color:#728e00">:</span>
<span style="color:#00979d">inline</span> <span style="color:#728e00">const</span> <span style="color:#434f54">CString</span><span style="color:#728e00">&amp;</span> <span style="color:#434f54">GetHostServiceAddress</span>() <span style="color:#728e00">const</span>
{
<span style="color:#728e00">return</span> <span style="color:#434f54">m_hostServiceAddress</span>;
}
<span style="color:#00979d">inline</span> <span style="color:#728e00">const</span> <span style="color:#434f54">CString</span><span style="color:#728e00">&amp;</span> <span style="color:#434f54">GetCoupon</span>() <span style="color:#728e00">const</span>
{
<span style="color:#728e00">return</span> <span style="color:#434f54">m_coupon</span>;
}
<span style="color:#00979d">inline</span> <span style="color:#00979d">void</span> <span style="color:#d35400">SetCoupon</span>(<span style="color:#434f54">CString</span> <span style="color:#434f54">coupon</span>)
{
<span style="color:#434f54">m_coupon</span> <span style="color:#728e00">=</span> <span style="color:#434f54">coupon</span>;
}
<span style="color:#00979d">inline</span> <span style="color:#00979d">void</span> <span style="color:#d35400">SetHostServiceAddress</span>(<span style="color:#434f54">CString</span> <span style="color:#434f54">address</span>)
{
<span style="color:#434f54">m_hostServiceAddress</span> <span style="color:#728e00">=</span> <span style="color:#434f54">address</span>;
}
<span style="color:#728e00">static</span> <span style="color:#434f54">AddinProcessService</span><span style="color:#728e00">*</span> <span style="color:#d35400">getSingletonInstance</span>()
{
<span style="color:#728e00">static</span> <span style="color:#728e00">volatile</span> <span style="color:#00979d">int</span> <span style="color:#434f54">initialized</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>;
<span style="color:#728e00">static</span> <span style="color:#434f54">HANDLE</span> <span style="color:#434f54">mtx</span>;
<span style="color:#728e00">if</span> (<span style="color:#728e00">!</span><span style="color:#434f54">initialized</span>)
{
<span style="color:#728e00">if</span> (<span style="color:#728e00">!</span><span style="color:#434f54">mtx</span>)
{
<span style="color:#434f54">HANDLE</span> <span style="color:#434f54">mymtx</span>;
<span style="color:#434f54">mymtx</span> <span style="color:#728e00">=</span> <span style="color:#434f54">CreateMutex</span>(<span style="color:#728e00">NULL</span>, <span style="color:#8a7b52">0</span>, <span style="color:#728e00">NULL</span>);
<span style="color:#728e00">if</span> (<span style="color:#434f54">InterlockedCompareExchangePointer</span>(<span style="color:#728e00">&amp;</span><span style="color:#434f54">mtx</span>, <span style="color:#434f54">mymtx</span>, <span style="color:#728e00">NULL</span>) <span style="color:#728e00">!=</span> <span style="color:#728e00">NULL</span>)
<span style="color:#434f54">CloseHandle</span>(<span style="color:#434f54">mymtx</span>);
}
<span style="color:#434f54">WaitForSingleObject</span>(<span style="color:#434f54">mtx</span>, <span style="color:#8a7b52">0</span>);
<span style="color:#728e00">if</span> (<span style="color:#728e00">!</span><span style="color:#434f54">initialized</span>)
{
<span style="color:#434f54">libInitInternal</span>();
<span style="color:#434f54">initialized</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">1</span>;
}
<span style="color:#434f54">ReleaseMutex</span>(<span style="color:#434f54">mtx</span>);
}
<span style="color:#728e00">return</span> <span style="color:#434f54">singletonInstance</span>;
};
<span style="color:#728e00">private</span><span style="color:#728e00">:</span>
<span style="color:#434f54">CString</span> <span style="color:#434f54">m_hostServiceAddress</span>;
<span style="color:#434f54">CString</span> <span style="color:#434f54">m_coupon</span>;
<span style="color:#728e00">static</span> <span style="color:#00979d">void</span> <span style="color:#d35400">libInitInternal</span>()
{
<span style="color:#434f54">singletonInstance</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">AddinProcessService</span>();
}
};
</code></pre></div><p>❗ Vergeet niet in de cpp file uw singletonInstance pointer te declareren, anders krijg je linker errors: <code>AddinProcessService* AddinProcessService::singletonInstance;</code></p>
<p>In UNIX kan men <a href="https://computing.llnl.gov/tutorials/pthreads/">pthreads</a> gebruiken, ongeveer op deze manier:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c++" data-lang="c++"><span style="color:#728e00">static</span> <span style="color:#434f54">Foo</span> <span style="color:#728e00">&amp;</span><span style="color:#434f54">getInst</span>()
{
<span style="color:#728e00">static</span> <span style="color:#434f54">Foo</span> <span style="color:#728e00">*</span><span style="color:#434f54">inst</span> <span style="color:#728e00">=</span> <span style="color:#728e00">NULL</span>;
<span style="color:#728e00">if</span>(<span style="color:#434f54">inst</span> <span style="color:#a61717">######</span> <span style="color:#728e00">NULL</span>)
{
<span style="color:#434f54">pthread_mutex_lock</span>(<span style="color:#728e00">&amp;</span><span style="color:#434f54">mutex</span>);
<span style="color:#728e00">if</span>(<span style="color:#434f54">inst</span> <span style="color:#a61717">######</span> <span style="color:#728e00">NULL</span>)
<span style="color:#434f54">inst</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">Foo</span>(...);
<span style="color:#434f54">pthread_mutex_unlock</span>(<span style="color:#728e00">&amp;</span><span style="color:#434f54">mutex</span>);
}
<span style="color:#728e00">return</span> <span style="color:#728e00">*</span><span style="color:#434f54">inst</span>;
}
</code></pre></div><p>Dan kan je <code>#ifdef WIN32</code> gebruiken om te switchen tussen beide implementaties.</p>
<h4 id="c-11-multithreading">C++ 11 multithreading</h4>
<p>Vanaf C++ 11 zijn multithreads 100% native supported, dit wil zeggen dat manueel locken met een <code>mutex</code> overbodig wordt. Bovenstaande singleton kan gereduceerd worden tot (merk het <strong>static</strong> keyword op, dat is het belangrijkste voor de autolock):</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c++" data-lang="c++"><span style="color:#728e00">static</span> <span style="color:#434f54">Singleton</span><span style="color:#728e00">&amp;</span> <span style="color:#434f54">get</span>(){
<span style="color:#728e00">static</span> <span style="color:#434f54">Singleton</span> <span style="color:#434f54">instance</span>;
<span style="color:#728e00">return</span> <span style="color:#434f54">instance</span>;
}
</code></pre></div><p>Voor meer info, zie <a href="http://stackoverflow.com/questions/11711920/how-to-implement-multithread-safe-singleton-in-c11-without-using-mutex">http://stackoverflow.com/questions/11711920/how-to-implement-multithread-safe-singleton-in-c11-without-using-mutex</a></p>
<h1 id="win32-api-specifics">Win32 API specifics</h1>
<h4 id="get-loaded-dll-info-from-given-process">Get Loaded DLL info from given process</h4>
<p>huidig proces: <code>GetCurrentProcessId()</code> - dit is een <code>HANDLE</code>.</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c++" data-lang="c++"><span style="color:#434f54">CString</span> <span style="color:#434f54">ExceptionHandler</span><span style="color:#728e00">::</span><span style="color:#434f54">GetLoadedDllInfo</span>() <span style="color:#728e00">const</span>
{
<span style="color:#434f54">CString</span> <span style="color:#434f54">dlls</span> <span style="color:#728e00">=</span> <span style="color:#434f54">_T</span>(<span style="color:#7f8c8d">&#34;&#34;</span>);
<span style="color:#434f54">HANDLE</span> <span style="color:#434f54">process</span> <span style="color:#728e00">=</span> <span style="color:#434f54">OpenProcess</span>(<span style="color:#434f54">PROCESS_QUERY_INFORMATION</span> <span style="color:#728e00">|</span> <span style="color:#434f54">PROCESS_VM_READ</span>, <span style="color:#434f54">FALSE</span>, <span style="color:#434f54">GetCurrentProcessId</span>());
<span style="color:#728e00">if</span>(<span style="color:#434f54">process</span> <span style="color:#a61717">######</span> <span style="color:#728e00">NULL</span>)
{
<span style="color:#728e00">return</span> <span style="color:#434f54">dlls</span>;
}
<span style="color:#434f54">HMODULE</span> <span style="color:#434f54">hMods</span>[<span style="color:#8a7b52">1024</span>];
<span style="color:#434f54">DWORD</span> <span style="color:#434f54">cbNeeded</span>;
<span style="color:#434f54">BOOL</span> <span style="color:#434f54">modules</span> <span style="color:#728e00">=</span> <span style="color:#434f54">EnumProcessModules</span>(<span style="color:#434f54">process</span>, <span style="color:#434f54">hMods</span>, <span style="color:#728e00">sizeof</span>(<span style="color:#434f54">hMods</span>), <span style="color:#728e00">&amp;</span><span style="color:#434f54">cbNeeded</span>);
<span style="color:#728e00">if</span>(<span style="color:#728e00">!</span><span style="color:#434f54">modules</span>)
{
<span style="color:#728e00">return</span> <span style="color:#434f54">dlls</span>;
}
<span style="color:#728e00">for</span> (<span style="color:#00979d">int</span> <span style="color:#434f54">i</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>; <span style="color:#434f54">i</span> <span style="color:#728e00">&lt;</span> (<span style="color:#434f54">cbNeeded</span> <span style="color:#728e00">/</span> <span style="color:#728e00">sizeof</span>(<span style="color:#434f54">HMODULE</span>)); <span style="color:#434f54">i</span><span style="color:#728e00">++</span>)
{
<span style="color:#434f54">TCHAR</span> <span style="color:#434f54">szModName</span>[<span style="color:#434f54">MAX_PATH</span>];
<span style="color:#728e00">if</span> (<span style="color:#434f54">GetModuleFileNameEx</span>(<span style="color:#434f54">process</span>, <span style="color:#434f54">hMods</span>[<span style="color:#434f54">i</span>], <span style="color:#434f54">szModName</span>, <span style="color:#728e00">sizeof</span>(<span style="color:#434f54">szModName</span>) <span style="color:#728e00">/</span> <span style="color:#728e00">sizeof</span>(<span style="color:#434f54">TCHAR</span>)))
{
<span style="color:#434f54">dlls</span>.<span style="color:#434f54">Format</span>(<span style="color:#434f54">_T</span>(<span style="color:#7f8c8d">&#34;%s, %s&#34;</span>), <span style="color:#434f54">dlls</span>, <span style="color:#434f54">szModName</span>);
}
}
<span style="color:#434f54">CloseHandle</span>(<span style="color:#434f54">process</span>);
<span style="color:#728e00">return</span> <span style="color:#434f54">dlls</span>;
}
</code></pre></div><p>Hiervoor moet je <code>#include &lt;psapi.h&gt;</code> includen én de psapi.lib file mee linken! Zie <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms682631(v=vs.85).aspx">EnumProcessModules MSDN</a>.</p>
<h1 id="c-native-calls-uitvoeren">C++ Native calls uitvoeren</h1>
<h4 id="voorbeeld-project">Voorbeeld project</h4>
<p>Wat is het probleem:</p>
<ol>
<li>Ik wil Native C++ methods kunnen aanroepen vanuit C#. Dit kan met de <code>DllImport</code> attribute.</li>
<li>Ik wil structs kunnen remarshallen die uit de native code komen. Dit kan met <code>StructLayout</code> en <code>PtrToStructrue</code>.</li>
<li>Ik wil een char* mappen op een C# string: gebruik <code>[MarshalAsAttribute(UnmanagedType.LPStr)]</code> in uw C# struct.</li>
<li>Ik wil parameters mee kunnen geven: gebruik de juiste calling method (STD of DECL) instelling, zie <code>CallingConvention</code> op <code>UnmanagedFunctionPointer</code>.</li>
</ol>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c++" data-lang="c++"><span style="color:#728e00">#pragma once
</span><span style="color:#728e00"></span>
<span style="color:#728e00">#ifdef _DLL
</span><span style="color:#728e00">#define DllExImport __declspec(dllexport)
</span><span style="color:#728e00">#else
</span><span style="color:#728e00">#define DllExImport __declspec(dllimport)
</span><span style="color:#728e00">#endif
</span><span style="color:#728e00"></span>
<span style="color:#728e00">struct</span> <span style="color:#434f54">MyStruct</span>
{
<span style="color:#00979d">char</span><span style="color:#728e00">*</span> <span style="color:#434f54">id</span>;
<span style="color:#00979d">char</span><span style="color:#728e00">*</span> <span style="color:#434f54">description</span>;
};
<span style="color:#434f54">DllExImport</span> <span style="color:#434f54">MyStruct</span><span style="color:#728e00">*</span> <span style="color:#00979d">__stdcall</span> <span style="color:#d35400">GetSignals</span>();
</code></pre></div><div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c++" data-lang="c++"><span style="color:#728e00">#include</span> <span style="color:#728e00">&#34;stdafx.h&#34;</span><span style="color:#728e00">
</span><span style="color:#728e00">#include</span> <span style="color:#728e00">&#34;TestClass.h&#34;</span><span style="color:#728e00">
</span><span style="color:#728e00"></span>
<span style="color:#434f54">DllExImport</span> <span style="color:#434f54">MyStruct</span><span style="color:#728e00">*</span> <span style="color:#00979d">__stdcall</span> <span style="color:#d35400">GetSignals</span>()
{
<span style="color:#728e00">static</span> <span style="color:#434f54">MyStruct</span> <span style="color:#434f54">a</span>[] <span style="color:#728e00">=</span>
{
{ <span style="color:#7f8c8d">&#34;id1&#34;</span>, <span style="color:#7f8c8d">&#34;desc1&#34;</span> },
{ <span style="color:#7f8c8d">&#34;id2&#34;</span>, <span style="color:#7f8c8d">&#34;desc2&#34;</span> },
{ <span style="color:#7f8c8d">&#34;id3&#34;</span>, <span style="color:#7f8c8d">&#34;desc3&#34;</span> }
};
<span style="color:#728e00">return</span> <span style="color:#434f54">a</span>;
}
</code></pre></div><div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-csharp" data-lang="csharp"><span style="color:#728e00">namespace</span> <span style="color:#434f54">structArrayImportTest</span>
{
<span style="color:#728e00">#region
</span><span style="color:#728e00"></span>
<span style="color:#728e00">using</span> <span style="color:#434f54">System</span>;
<span style="color:#728e00">using</span> <span style="color:#434f54">System.Runtime.InteropServices</span>;
<span style="color:#728e00">#endregion
</span><span style="color:#728e00"></span>
<span style="color:#728e00">internal</span> <span style="color:#728e00">class</span> <span style="color:#434f54">StructImporter</span>
{
<span style="color:#95a5a6">// Charset.Ansi is not needed it seems
</span><span style="color:#95a5a6"></span><span style="color:#434f54"> [DllImport(&#34;kernel32.dll&#34;, EntryPoint = &#34;LoadLibrary&#34;)]</span>
<span style="color:#728e00">private</span> <span style="color:#728e00">static</span> <span style="color:#728e00">extern</span> <span style="color:#434f54">IntPtr</span> <span style="color:#434f54">LoadLibrary</span>(
<span style="color:#434f54"> [MarshalAs(UnmanagedType.LPStr)]</span> <span style="color:#00979d">string</span> <span style="color:#434f54">lpLibFileName</span>);
<span style="color:#434f54">
</span><span style="color:#434f54"> [DllImport(&#34;kernel32.dll&#34;, EntryPoint = &#34;GetProcAddress&#34;)]</span>
<span style="color:#728e00">private</span> <span style="color:#728e00">static</span> <span style="color:#728e00">extern</span> <span style="color:#434f54">IntPtr</span> <span style="color:#434f54">GetProcAddress</span>(<span style="color:#434f54">IntPtr</span> <span style="color:#434f54">hModule</span>,
<span style="color:#434f54"> [MarshalAs(UnmanagedType.LPStr)]</span> <span style="color:#00979d">string</span> <span style="color:#434f54">lpProcName</span>);
<span style="color:#434f54">
</span><span style="color:#434f54"> [DllImport(&#34;kernel32&#34;, SetLastError ###### true, EntryPoint &#34;GetProcAddress&#34;)]</span>
<span style="color:#728e00">private</span> <span style="color:#728e00">static</span> <span style="color:#728e00">extern</span> <span style="color:#434f54">IntPtr</span> <span style="color:#434f54">GetProcAddressOrdinal</span>(<span style="color:#434f54">IntPtr</span> <span style="color:#434f54">hModule</span>, <span style="color:#434f54">IntPtr</span> <span style="color:#434f54">procName</span>);
<span style="color:#434f54">
</span><span style="color:#434f54"> [DllImport(&#34;kernel32.dll&#34;, EntryPoint = &#34;FreeLibrary&#34;)]</span>
<span style="color:#728e00">private</span> <span style="color:#728e00">static</span> <span style="color:#728e00">extern</span> <span style="color:#00979d">bool</span> <span style="color:#434f54">FreeLibrary</span>(<span style="color:#00979d">int</span> <span style="color:#434f54">hModule</span>);
<span style="color:#434f54">
</span><span style="color:#434f54"> [StructLayout(LayoutKind.Sequential)]</span>
<span style="color:#728e00">public</span> <span style="color:#728e00">class</span> <span style="color:#434f54">MyStruct</span>
{
<span style="color:#434f54"> [MarshalAsAttribute(UnmanagedType.LPStr)]</span>
<span style="color:#728e00">public</span> <span style="color:#00979d">string</span> <span style="color:#434f54">_id</span>;
<span style="color:#434f54"> [MarshalAsAttribute(UnmanagedType.LPStr)]</span>
<span style="color:#728e00">public</span> <span style="color:#00979d">string</span> <span style="color:#434f54">_description</span>;
}
<span style="color:#434f54">
</span><span style="color:#434f54"> [UnmanagedFunctionPointer(CallingConvention.StdCall)]</span>
<span style="color:#728e00">public</span> <span style="color:#728e00">delegate</span> <span style="color:#434f54">IntPtr</span> <span style="color:#434f54">fGetSignals</span>();
<span style="color:#728e00">public</span> <span style="color:#434f54">fGetSignals</span> <span style="color:#434f54">GetSignals</span>;
<span style="color:#728e00">public</span> <span style="color:#728e00">void</span> <span style="color:#434f54">Import</span>()
{
<span style="color:#434f54">IntPtr</span> <span style="color:#434f54">lib</span> = <span style="color:#434f54">LoadLibrary</span>(<span style="color:#7f8c8d">@&#34;C:&lt;br/&gt;Users&lt;br/&gt;bkwog&lt;br/&gt;Documents&lt;br/&gt;Visual Studio 2012&lt;br/&gt;Projects&lt;br/&gt;structArrayExportTest&lt;br/&gt;Debug&lt;br/&gt;structArrayExportTest.dll&#34;</span>);
<span style="color:#95a5a6">// gebruik dumpbin /exports [bla.dll] om ordinal &amp; name van exported functions te bepalen.
</span><span style="color:#95a5a6"></span> <span style="color:#434f54">IntPtr</span> <span style="color:#434f54">signalsHandle</span> = <span style="color:#434f54">GetProcAddressOrdinal</span>(<span style="color:#434f54">lib</span>, <span style="color:#728e00">new</span> <span style="color:#434f54">IntPtr</span>(<span style="color:#8a7b52">1</span>));
<span style="color:#434f54">GetSignals</span> = (<span style="color:#434f54">fGetSignals</span>) <span style="color:#434f54">Marshal</span>.<span style="color:#434f54">GetDelegateForFunctionPointer</span>(<span style="color:#434f54">signalsHandle</span>, <span style="color:#728e00">typeof</span> (<span style="color:#434f54">fGetSignals</span>));
<span style="color:#434f54">IntPtr</span> <span style="color:#434f54">myStructs</span> = <span style="color:#434f54">GetSignals</span>();
<span style="color:#00979d">int</span> <span style="color:#434f54">structSize</span> = <span style="color:#434f54">Marshal</span>.<span style="color:#434f54">SizeOf</span>(<span style="color:#728e00">typeof</span>(<span style="color:#434f54">MyStruct</span>));
<span style="color:#434f54">Console</span>.<span style="color:#434f54">WriteLine</span>(<span style="color:#434f54">structSize</span>);
<span style="color:#728e00">for</span> (<span style="color:#00979d">int</span> <span style="color:#434f54">i</span> = <span style="color:#8a7b52">0</span>; <span style="color:#434f54">i</span> &lt; <span style="color:#8a7b52">3</span>; ++<span style="color:#434f54">i</span>)
{
<span style="color:#95a5a6">// What&#39;s the difference between toInt32 &amp; 64 here? Both work...
</span><span style="color:#95a5a6"></span> <span style="color:#434f54">IntPtr</span> <span style="color:#434f54">data</span> = <span style="color:#728e00">new</span> <span style="color:#434f54">IntPtr</span>(<span style="color:#434f54">myStructs</span>.<span style="color:#434f54">ToInt64</span>() + <span style="color:#434f54">structSize</span> * <span style="color:#434f54">i</span>);
<span style="color:#434f54">MyStruct</span> <span style="color:#434f54">ms</span> = (<span style="color:#434f54">MyStruct</span>)<span style="color:#434f54">Marshal</span>.<span style="color:#434f54">PtrToStructure</span>(<span style="color:#434f54">data</span>, <span style="color:#728e00">typeof</span>(<span style="color:#434f54">MyStruct</span>));
<span style="color:#434f54">Console</span>.<span style="color:#434f54">WriteLine</span>(<span style="color:#7f8c8d">&#34;id: &#34;</span> + <span style="color:#434f54">ms</span>.<span style="color:#434f54">_id</span> + <span style="color:#7f8c8d">&#34; - descr: &#34;</span> + <span style="color:#434f54">ms</span>.<span style="color:#434f54">_description</span> );
}
}
}
}
</code></pre></div><h4 id="calling-convention">Calling convention</h4>
<p>In te stellen via C++ project settings -&gt; advanced -&gt; calling convention, voor alles, of per functie met <code>__stdcall</code>. C# werkt hiet default mee. Aanpasbaar in het attribute, zie boven.</p>
<p>Als de calling convention niet overeen zou komen, krijg je bij het uitvoeren in de C# code de volgende fout:</p>
<blockquote>
<p>call to PInvoke function &lsquo;structArrayImportTest!structArrayImportTest.StructImporter+fGetSignals::Invoke&rsquo; has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.</p>
</blockquote>
<h4 id="dumpbin">dumpbin</h4>
<p>Als je niet met ordinals wenst te werken maar de volledige naam van de functie kan jet met <code>dumpbin.exe</code> dit achterhalen:</p>
<pre><code>C:&lt;br/&gt;Program Files (x86)&lt;br/&gt;Microsoft Visual Studio 10.0&lt;br/&gt;Common7&lt;br/&gt;IDE&gt;dumpbin /exports TfsAdmin.exe structArrayExportTest.dll
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file TfsAdmin.exe
File Type: EXECUTABLE IMAGE
Dump of file structArrayExportTest.dll
File Type: DLL
Section contains the following exports for structArrayExportTest.dll
00000000 characteristics
52A888CA time date stamp Wed Dec 11 16:46:18 2013
0.00 version
1 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
1 0 00011113 ?GetSignals@@YAPAUTestStruct@@XZ
2 1 000110E6 ?GetSize@@YAPAHXZ
Summary
1000 .data
1000 .idata
3000 .rdata
3000 .reloc
11000 .rsrc
8000 .text
10000 .textbss
</code></pre><p>Merk op dat de functie <code>GetSignals</code> hier niet die naam heeft, maar <code>?GetSignals@@YAPAUTestStruct@@XZ</code>!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>Heavily used Unix Commands</title>
<link>https://brainbaking.com/post/2013/10/unix-cmd/</link>
<comments>https://brainbaking.com/post/2013/10/unix-cmd/#commento</comments>
<pubDate>Tue, 01 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/unix-cmd/</guid>
<category domain="https://brainbaking.com/tags/unix">unix</category>
<category domain="https://brainbaking.com/tags/cmd">cmd</category>
<description>
<![CDATA[
<h3 id="binaries-zoeken">Binaries zoeken</h3>
<p>Kan met <code>whereis</code>, <strong>maar</strong> die zoekt blijkbaar niet in &ldquo;alle&rdquo; binary dirs - enkel degene die geconfigureerd zijn onder:</p>
<pre><code>sysctl user.cs_path
# output: user.cs_path = /usr/bin:/bin:/usr/sbin:/sbin
</code></pre><h3 id="shell-automatisation">Shell automatisation</h3>
<p>Command-line programs <em>feeden</em> kan met het <code>expect</code> tooltje. Bijvoorbeeld, bij het aanloggen in <code>ssh</code> moet je daarna een wachtwoord geven en op enter drukken dat niet als commandline argument meegegeven kan worden. Dit kan je dan zo forceren:</p>
<pre><code>#!/usr/bin/expect -f
# Expect script to supply root/admin password for remote ssh server
# and execute command.
# This script needs three argument to(s) connect to remote server:
# password = Password of remote UNIX server, for root user.
# ipaddr = IP Addreess of remote UNIX server, no hostname
# scriptname = Path to remote script which will execute on remote server
# For example:
# ./sshlogin.exp password 192.168.1.11 who
# ------------------------------------------------------------------------
# Copyright (c) 2004 nixCraft project &lt;http://cyberciti.biz/fb/&gt;
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# ----------------------------------------------------------------------
# set Variables
set password [lrange $argv 0 0]
set ipaddr [lrange $argv 1 1]
set username [lrange $argv 2 2]
set timeout -1
# now connect to remote UNIX box (ipaddr) with given script to execute
spawn ssh $username@$ipaddr
match_max 100000
# Look for passwod prompt
expect &quot;*?assword:*&quot;
# Send password aka $password
send -- &quot;$password&lt;br/&gt;r&quot;
# send blank line (&lt;br/&gt;r) to make sure we get back to gui
send -- &quot;&lt;br/&gt;r&quot;
expect eof
</code></pre><p>(<a href="http://nixcraft.com/shell-scripting/4489-ssh-passing-unix-login-passwords-through-shell-scripts.html">bron</a>) - voor meer uitleg zie <a href="https://en.wikipedia.org/wiki/Expect" target="_blank">Expect</a>
wiki.</p>
<h3 id="synchronizingbackuppingfile-copying">Synchronizing/backupping/file copying</h3>
<p>Gebruik het <code>rsync</code> commando om incrementeel een kopie te nemen van een directory en alle subdirs van plaats1 naar plaats2. Dit kan lokaal, naar een externe HDD of zelfs via een server. <code>rsync</code> heeft ook een daemon mode die je aan kan zetten met <code>--daemon</code> - Zie <a href="http://www.samba.org/ftp/rsync/rsync.html">rsync man</a>. Het belangrijkste commando is zonder twijfel:</p>
<pre><code>$ rsync -auv -E -W --del [src] [dest]
</code></pre><p>Opties:</p>
<ul>
<li><code>-a</code>: archive mode: auto-enable een hoop andere opties (keep timestamps etc)</li>
<li><code>-u</code>: update (incremental mode)</li>
<li><code>-v</code>: verbose</li>
<li><code>-E</code>: preserve executability (niet nodig onder windows)</li>
<li><code>--del</code>: delete files die in de source verdwijnen ook in de destination.</li>
</ul>
<p>Een extra optie <code>-z</code> kan ook compressie over netwerk toevoegen. Verwijder dan best <code>-W</code>.</p>
<p>Je kan periodiek dit commando uit voeren om de destination dir up-to-date te houden. Vergeet niet dat rsync ook een <code>daemon</code> mode heeft, met nog veel meer opties!</p>
<h3 id="user-rechten-geven-om-root-te-worden">User rechten geven om root te worden</h3>
<p>Probleem bij <code>su</code> commando: <em>su: Sorry for normal user account.</em></p>
<p>Vergeten toe te voegen aan de <code>wheel</code> user group, zo doen:</p>
<p><code>pw user mod vivek -G wheel</code></p>
<h3 id="shell-editing-mode">Shell editing mode</h3>
<p>Zie <a href="http://www.catonmat.net/blog/bash-vi-editing-mode-cheat-sheet/">http://www.catonmat.net/blog/bash-vi-editing-mode-cheat-sheet/</a></p>
<pre><code>$ set -o vi
</code></pre><p>Best opslaan in uw <code>.bashrc</code> (of whateverrc)</p>
<p>-&gt; Tof om te weten: <code>CTRL+L</code> <strong>cleart het scherm</strong> van een <strong>terminal</strong> (dit werkt ook voor Cygwin!)</p>
<h3 id="command-history">Command History</h3>
<p>voorbeeld:</p>
<pre><code>dir $ history
1 ls -la
2 cd ~
3 rm somedir
dir $ !2
~ $ !!
</code></pre><p>waarbij ![getal] laatste x commando uitvoert en !! het laatste. Zie <code>man history</code> voor geavanceerde voorbeelden.</p>
<h3 id="copy-and-auto-create-dir-structure">Copy and auto-create dir structure</h3>
<p>Bewaar dit shell script naar cpi.sh:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#728e00">#!/bin/bash
</span><span style="color:#728e00"></span><span style="color:#728e00">if</span> <span style="color:#728e00">[</span> ! -d <span style="color:#7f8c8d">&#34;</span><span style="color:#434f54">$2</span><span style="color:#7f8c8d">&#34;</span> <span style="color:#728e00">]</span>; <span style="color:#728e00">then</span>
mkdir -p <span style="color:#7f8c8d">&#34;</span><span style="color:#434f54">$2</span><span style="color:#7f8c8d">&#34;</span>
<span style="color:#728e00">fi</span>
cp -R <span style="color:#7f8c8d">&#34;</span><span style="color:#434f54">$1</span><span style="color:#7f8c8d">&#34;</span> <span style="color:#7f8c8d">&#34;</span><span style="color:#434f54">$2</span><span style="color:#7f8c8d">&#34;</span>
</code></pre></div><p><code>chmod +x cpi.sh</code> en dan in uw <code>.bashrc</code> een link leggen om <code>cpi</code> te gebruiken.</p>
<h3 id="xargs">xargs</h3>
<p>Het bovenstaande kan ook uitgevoerd worden met <code>xargs</code> en piping. Bijvoorbeeld bepaalde bestanden (niet-recursief) kopiëren naar &ldquo;tmp&rdquo;:</p>
<pre><code>ls | grep .php | xargs -i cp {} ./tmp
</code></pre><p>Andere interessante opties van xargs:</p>
<ul>
<li><code>-ix</code>: gebruik <code>{}</code> (of <code>x</code> karakters indien specified) om lijn per lijn de input te vervangen. Het kan zijn dat dit escaped moet worden met backslashen voor de shell!</li>
<li><code>-0</code>: gebruik in combinatie met <code>-print0</code> en <code>find</code> om het verschil tussen spaties en newlines duidelijk te maken</li>
<li><code>-p</code>: confirm elke actie, interessant bij verwijderen van crutiale files</li>
<li><code>-lx</code>: gebruik maximum x lijnen input per command line.</li>
<li><code>-nx</code>: gebruik maximum x argumenten per command line.</li>
<li><code>-t</code>: verbose mode (<code>--verbose</code> werkt ook)</li>
</ul>
<h3 id="sed">sed</h3>
<p>Gebruik <code>sed</code> om snel replaces te doen door middel van regex, of door lines te nummeren, &hellip; <br/><br/>
Het is ook mogelijk om regex partities te <em>groeperen</em>, vergeet niet de haakjes zelf te escapen! Om de gegroepeerde waarde in het &ldquo;replace&rdquo; geteelde te gebruiken, moeten we niet <code>$1</code> maar <code>&lt;br/&gt;1</code> gebruiken. Bijvoorbeeld:</p>
<pre><code>sed 's/&lt;br/&gt;(.*&lt;br/&gt;)/regel:&lt;br/&gt;1/g' log.tmp &gt;&gt; $logfile
</code></pre><p>Resultaat:</p>
<ol>
<li>Replace x door y via <code>s/regex/replace/</code></li>
<li>Replace alle gevonden instanties (<code>g</code> na expressie)</li>
<li>Groepeer alles door te zoeken op <code>.*</code> en er haakjes rond te plaatsen</li>
<li>Vervang alles door &lsquo;regel:&rsquo; + alles van de groep</li>
</ol>
<p>Dus prepend elke regel met &lsquo;regel:&rsquo;.</p>
<p>-&gt; Groeperen in sed vereist escaped parentheses, anders matchen we exact <code>(</code> in de zoekstring zelf!</p>
<h5 id="chainen">chainen</h5>
<p>Een keer sed aanroepen en in een sequentie meerdere replaces doen gaat met het <code>-e</code> argument (script mode):</p>
<pre><code>cat file | sed -e 's/replace/by/g' -e 's/other/new/g'
</code></pre><h5 id="aan-begin-van-lijnen-prependen">Aan begin van lijnen prependen</h5>
<p>Gebruik het symbool &lsquo;^&rsquo; om het begin van een lijn te matchen, en &lsquo;$&rsquo; om het einde van een lijn te matchen:</p>
<pre><code>cat file | sed 's/^&lt;br/&gt;([^=]&lt;br/&gt;)/ *&lt;br/&gt;1/'
</code></pre><p>Hier wordt in het begin van elke lijn spatie spatie ster toegevoegd behalve als de lijn begint met het gelijkheidsteken. Omdat we anders het eerste karakter vervangen moeten we die ook capturen!</p>
<p>-&gt; Zoals in eclipse een getal matchen met <code>&lt;br/&gt;d</code> werkt niet, daarvoor moet je <code>[0-9]</code> gebruiken.</p>
<h3 id="uniq">uniq</h3>
<p>Vergelijkt een lijn met de volgende en gooit dubbels eruit. Instelbaar met een beperkt aantal parameters. <br/><br/>
<strong>adjacent matching lines</strong>, meer kan dit ding niet!</p>
<h5 id="sed-gebruiken-om-uniq-te-emuleren">sed gebruiken om uniq te emuleren</h5>
<p>Zie <a href="http://www.catonmat.net/blog/sed-one-liners-explained-part-three/">http://www.catonmat.net/blog/sed-one-liners-explained-part-three/</a> voor volledige uitleg</p>
<pre><code>sed '$!N; /^&lt;br/&gt;(.*&lt;br/&gt;)&lt;br/&gt;n&lt;br/&gt;1$/!P; D'
</code></pre><h5 id="sed-gebruiken-om-álle-dubbels-eruit-te-smijten-buffering">sed gebruiken om álle dubbels eruit te smijten: buffering</h5>
<pre><code>sed -n 'G; s/&lt;br/&gt;n/&amp;&amp;/; /^&lt;br/&gt;([ -~]*&lt;br/&gt;n&lt;br/&gt;).*&lt;br/&gt;n&lt;br/&gt;1/d; s/&lt;br/&gt;n//; h; P'
</code></pre><h3 id="cut">cut</h3>
<p>Een utility command dat meestal gebruikt wordt om lijnen op te splitsen afhankelijk van een <strong>delimiter</strong>. Bijvoorbeeld:</p>
<pre><code>cat test.txt | cut -d '|' -f 3
</code></pre><p>meest gebruikte opties:</p>
<ul>
<li><code>-d</code> verplicht, geef delimiter op</li>
<li><code>-f</code> selecteer enkel deze kolommen</li>
</ul>
<h3 id="combinatievoorbeeld">Combinatievoorbeeld</h3>
<p>Onderstaand script zoekt in de svn log entries met &lsquo;jira&rsquo; of &lsquo;hel&rsquo; (case insensitive, <code>-i</code> grep operator) behalve &lsquo;gcl&rsquo; of &lsquo;lvm&rsquo;, print context 1 lijn above en 2 lijnen below, filtert dubbels, haalt de derde kolom eruit gesplitst door &lsquo;|&rsquo; (datum), vervangt eender welke hoeveelheid &lsquo;-&rsquo; door niets en wrap datums beginnende met 2011 met twee = tekens.</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#728e00">#!/bin/sh
</span><span style="color:#728e00"></span><span style="color:#434f54">datefrom</span><span style="color:#728e00">=</span>2011-02-28
<span style="color:#434f54">dateto</span><span style="color:#728e00">=</span>2011-03-12
<span style="color:#434f54">logfile</span><span style="color:#728e00">=</span>/cygdrive/c/opt/wamp/www/wiki/data/wiki/helena/svnlog.txt
<span style="color:#728e00">pushd</span> /cygdrive/c/opt/hudson/jobs/Helena_build/workspace/burgerlijkestand
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;### Svn log Helena Trunk &#34;</span> &gt; <span style="color:#434f54">$logfile</span>
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;❗ periode **[</span><span style="color:#434f54">$datefrom</span><span style="color:#7f8c8d"> - </span><span style="color:#434f54">$dateto</span><span style="color:#7f8c8d">]**&#34;</span> &gt;&gt; <span style="color:#434f54">$logfile</span>
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;#### Helena Jira&#39;s via svn log&#34;</span> &gt;&gt; <span style="color:#434f54">$logfile</span>
svn --username######cp8tsc --passwordq3Sp8Phu log -r<span style="color:#728e00">{</span><span style="color:#434f54">$datefrom</span><span style="color:#728e00">}</span>:<span style="color:#728e00">{</span><span style="color:#434f54">$dateto</span><span style="color:#728e00">}</span> |
grep -B <span style="color:#8a7b52">2</span> -A <span style="color:#8a7b52">1</span> -i <span style="color:#7f8c8d">&#39;HEL-&lt;br/&gt;|jira&#39;</span> |
grep -v <span style="color:#7f8c8d">&#39;gcl&lt;br/&gt;|lvm&#39;</span> |
sed -e <span style="color:#7f8c8d">&#39;s/-*//&#39;</span> -e <span style="color:#7f8c8d">&#39;s/r[0-9]* .*(&lt;br/&gt;(.*&lt;br/&gt;)).*/#####&lt;br/&gt;1/g&#39;</span> -e <span style="color:#7f8c8d">&#39;s/^&lt;br/&gt;([^=]&lt;br/&gt;)/ *&lt;br/&gt;1/&#39;</span> |
sed -n <span style="color:#7f8c8d">&#39;G; s/&lt;br/&gt;n/&amp;&amp;/; /^&lt;br/&gt;([ -~]*&lt;br/&gt;n&lt;br/&gt;).*&lt;br/&gt;n&lt;br/&gt;1/d; s/&lt;br/&gt;n//; h; P&#39;</span> &gt;&gt; <span style="color:#434f54">$logfile</span>
<span style="color:#728e00">popd</span>
</code></pre></div><h1 id="random-commands">Random commands</h1>
<ul>
<li><code>seq 1 10</code> print in een sequence getalletjes.</li>
<li><code>head</code> werkt ook in plaats van <code>tail</code>, maar zelfs van een lijst - ge kunt <code>head 1</code> van een stream dus gebruiken als pop voor een stack.</li>
<li><code>ftp -i -n [host] &lt;&lt; FTP_SCRIPT</code> newline, een hoop commands, en <code>FTP_SCRIPT</code> op het laatste = in 1 regel wat op een ftp server doen.</li>
<li><code>mail -a [attach]</code> = in 1 regel als attach iets mailen naar iemand (zie <code>man</code>)</li>
<li><code>wc</code> = wordcount; -e enkel lijnen</li>
</ul>
<h2 id="video-convertingconcatenating-etc">Video converting/concatenating etc</h2>
<p>Met behulp van <code>ffmpeg</code> .</p>
<h4 id="concatting">Concatting</h4>
<p>Alle files die eindigen op mp4:</p>
<pre><code>ffmpeg -f concat -i &lt;(printf &quot;file '%s'&lt;br/&gt;n&quot; ./*.mp4) -c copy output.mp4
</code></pre><p>Gaat ook met <code>mplayer</code> en de tool <code>mencoder</code>:</p>
<pre><code>mencoder -oac pcm -ovc copy -idx -o all.mp4 1.mp4 2.mp4 3.mp4 4.mp4 5.mp4
</code></pre><h4 id="resizing-compressing">Resizing (compressing)</h4>
<p>Ook met <code>ffmpeg</code> - bijvoorbeeld reduceren naar &ldquo;medium&rdquo; quality. Neem alle mp4s in folder:</p>
<pre><code>for i in *.mp4 ; do ffmpeg -i &quot;$i&quot; -c:a copy -preset medium &quot;${i%.*}_medium.${i##*.}&quot;; done
</code></pre><p>Voor meer presets zoals &ldquo;medium&rdquo;, zie <a href="http://trac.ffmpeg.org/wiki/x264EncodingGuide">http://trac.ffmpeg.org/wiki/x264EncodingGuide</a></p>
<h1 id="bash-scripting">Bash Scripting</h1>
<h4 id="rerun-last-command">Rerun last command</h4>
<pre><code>!!
</code></pre><p>Joink.</p>
<h4 id="bash-opties-uit-een-shell-script-halen">bash opties uit een shell script halen</h4>
<p>Gepikt van <a href="http://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash">http://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash</a></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#728e00">#!/bin/bash
</span><span style="color:#728e00"></span><span style="color:#728e00">for</span> i in <span style="color:#434f54">$*</span>
<span style="color:#728e00">do</span>
<span style="color:#728e00">case</span> <span style="color:#434f54">$i</span> in
-p######*|--prefix*<span style="color:#728e00">)</span>
PREFIX######<span style="color:#7f8c8d">`</span><span style="color:#728e00">echo</span> <span style="color:#434f54">$i</span> | sed <span style="color:#7f8c8d">&#39;s/[-a-zA-Z0-9]*//&#39;</span><span style="color:#7f8c8d">`</span>
;;
-s######*|--searchpath*<span style="color:#728e00">)</span>
SEARCHPATH######<span style="color:#7f8c8d">`</span><span style="color:#728e00">echo</span> <span style="color:#434f54">$i</span> | sed <span style="color:#7f8c8d">&#39;s/[-a-zA-Z0-9]*//&#39;</span><span style="color:#7f8c8d">`</span>
;;
-l######*|--lib*<span style="color:#728e00">)</span>
DIR######<span style="color:#7f8c8d">`</span><span style="color:#728e00">echo</span> <span style="color:#434f54">$i</span> | sed <span style="color:#7f8c8d">&#39;s/[-a-zA-Z0-9]*//&#39;</span><span style="color:#7f8c8d">`</span>
;;
--default<span style="color:#728e00">)</span>
<span style="color:#434f54">DEFAULT</span><span style="color:#728e00">=</span>YES
;;
*<span style="color:#728e00">)</span>
<span style="color:#95a5a6"># unknown option</span>
;;
<span style="color:#728e00">esac</span>
<span style="color:#728e00">done</span>
<span style="color:#728e00">echo</span> <span style="color:#434f54">PREFIX</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">${</span><span style="color:#434f54">PREFIX</span><span style="color:#7f8c8d">}</span>
<span style="color:#728e00">echo</span> SEARCH <span style="color:#434f54">PATH</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">${</span><span style="color:#434f54">SEARCHPATH</span><span style="color:#7f8c8d">}</span>
<span style="color:#728e00">echo</span> <span style="color:#434f54">DIRS</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">${</span><span style="color:#434f54">DIR</span><span style="color:#7f8c8d">}</span>
</code></pre></div><p>Makkelijker dan <code>getopts()</code>?</p>
<h4 id="pipen-en-multiple-lines-in-shell-scripts">Pipen en multiple lines in shell scripts</h4>
<p>Dit is legale shell code:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#728e00">#!/bin/sh
</span><span style="color:#728e00"></span>cat dinges.log |
cut -d <span style="color:#7f8c8d">&#39; &#39;</span> -f <span style="color:#8a7b52">3</span>
grep <span style="color:#7f8c8d">&#39;Exception&#39;</span> |
uniq
</code></pre></div><p>De pipe aan het begin van een nieuwe lijn alleszins niet. Ook <code>&gt;&gt;</code> of <code>&gt;</code> kan niet het begin zijn van een nieuwe lijn, dan wordt een spatie gepiped naar de outputstream.</p>
<h4 id="array-loops">array loops</h4>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#434f54">names</span><span style="color:#728e00">=(</span> Jennifer Tonya Anna Sadie <span style="color:#728e00">)</span>
<span style="color:#728e00">for</span> name in <span style="color:#7f8c8d">${</span><span style="color:#434f54">names</span>[@]<span style="color:#7f8c8d">}</span>
<span style="color:#728e00">do</span>
<span style="color:#728e00">echo</span> <span style="color:#434f54">$name</span>
<span style="color:#95a5a6"># other stuff on $name</span>
<span style="color:#728e00">done</span>
</code></pre></div><p>Ook mogelijk om bvb een counter bij te houden met <code>for (( i = 0 ; i &lt; ${#names[@]} ; i++ ))</code>. Array waarde accessen met <code>${names[$i]}</code>.</p>
<p>Inline arrays &ldquo;maken&rdquo; en over lopen gaat met <code>for VAR in 'a' 'b' 'c' do ... done</code>.</p>
<h5 id="argumenten-samen-rapen-in-een-variabele">argumenten samen rapen in een variabele</h5>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#434f54">DIR_EXCLUDES</span><span style="color:#728e00">=(</span>eclipsecompiled <span style="color:#728e00">test</span> bin target<span style="color:#728e00">)</span>
<span style="color:#434f54">FILE_EXCLUDES</span><span style="color:#728e00">=(</span>messages errors<span style="color:#728e00">)</span>
<span style="color:#434f54">SEARCH</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;&#34;</span>
<span style="color:#728e00">for</span> FILE_EXCLUDE in <span style="color:#7f8c8d">${</span><span style="color:#434f54">FILE_EXCLUDES</span>[@]<span style="color:#7f8c8d">}</span>
<span style="color:#728e00">do</span>
<span style="color:#434f54">SEARCH</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;</span><span style="color:#7f8c8d">${</span><span style="color:#434f54">SEARCH</span><span style="color:#7f8c8d">}</span><span style="color:#7f8c8d"> -not -name *</span><span style="color:#7f8c8d">${</span><span style="color:#434f54">FILE_EXCLUDE</span><span style="color:#7f8c8d">}</span><span style="color:#7f8c8d">*&#34;</span>
<span style="color:#728e00">done</span>
<span style="color:#728e00">for</span> DIR_EXCLUDE in <span style="color:#7f8c8d">${</span><span style="color:#434f54">DIR_EXCLUDES</span>[@]<span style="color:#7f8c8d">}</span>
<span style="color:#728e00">do</span>
<span style="color:#434f54">SEARCH</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;</span><span style="color:#7f8c8d">${</span><span style="color:#434f54">SEARCH</span><span style="color:#7f8c8d">}</span><span style="color:#7f8c8d"> -not -path *</span><span style="color:#7f8c8d">${</span><span style="color:#434f54">DIR_EXCLUDE</span><span style="color:#7f8c8d">}</span><span style="color:#7f8c8d">*&#34;</span>
<span style="color:#728e00">done</span>
</code></pre></div><p>❗ dit werkt <strong>niet</strong> als er een dubbele quote bij komt kijken in de vorm van <code>&lt;br/&gt;&quot;</code> - vreemd? uit te zoeken&hellip;</p>
<h4 id="controleren-of-een-string-in-een-variabele-steekt">Controleren of een string in een variabele steekt</h4>
<p>Zie <a href="http://stackoverflow.com/questions/229551/string-contains-in-bash">http://stackoverflow.com/questions/229551/string-contains-in-bash</a> - makkelijkste manieren zijn</p>
<h5 id="met-grep">met grep</h5>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#728e00">if</span> grep -q <span style="color:#7f8c8d">&#39;|&#39;</span> <span style="color:#728e00">&lt;&lt;&lt;</span><span style="color:#434f54">$line</span>; <span style="color:#728e00">then</span>
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;jup&#34;</span>
<span style="color:#728e00">fi</span>
</code></pre></div><h5 id="met-regexp">met regexp</h5>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#728e00">if</span> <span style="color:#728e00">[[</span> <span style="color:#7f8c8d">&#34;</span><span style="color:#434f54">$line</span><span style="color:#7f8c8d">&#34;</span> <span style="color:#728e00">=</span>~ <span style="color:#7f8c8d">&#34;|&#34;</span> <span style="color:#728e00">]]</span>; <span style="color:#728e00">then</span>
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;jup&#34;</span>
<span style="color:#728e00">fi</span>
</code></pre></div><h4 id="loopen-over-alle-lijnen-van-bepaalde-output-voor-verdere-processing">Loopen over alle lijnen van bepaalde output voor verdere processing</h4>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#7f8c8d">`</span>cat somefile<span style="color:#7f8c8d">`</span> | <span style="color:#728e00">while</span> <span style="color:#728e00">read</span> line
<span style="color:#728e00">do</span>
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;lijn </span><span style="color:#434f54">$line</span><span style="color:#7f8c8d">&#34;</span>
<span style="color:#728e00">done</span>
</code></pre></div><p>Dit kan ook maar dan moet je de separator variabele voor <code>for</code> aanpassen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#434f54">IFS</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">$&#39;&lt;br/&gt;n&#39;</span>
<span style="color:#728e00">for</span> line in <span style="color:#7f8c8d">`</span>cat somefile<span style="color:#7f8c8d">`</span>
<span style="color:#728e00">do</span>
<span style="color:#728e00">echo</span> <span style="color:#7f8c8d">&#34;lijn </span><span style="color:#434f54">$line</span><span style="color:#7f8c8d">&#34;</span>
<span style="color:#728e00">done</span>
</code></pre></div><p>❗ By default splitst for <strong>op spaties</strong></p>
<h1 id="find-command">Find command</h1>
<p>-&gt; Zie <a href="http://northredoubt.com/n/2009/12/30/linuxunixcygwin-find-command/">http://northredoubt.com/n/2009/12/30/linuxunixcygwin-find-command/</a> voor enorm veel uitleg over basics van <code>find</code>.</p>
<h3 id="finding-stuff">Finding stuff</h3>
<pre><code>find / -name &quot;*.ext&quot; -type f -exec [command with args] {} &lt;br/&gt;;
</code></pre><p>Bovenstaande lijn zoekt in root directory voor alle .ext bestanden (-type f is standaard, <code>d</code> staat voor directory etc, zie manual) en pipet alle resultaten naar een bepaald commando achter <code>-exec</code>. <code>{}</code> Stelt het gevonden bestand voor (full path), <code>&lt;br/&gt;;</code> eindigt het exec commando. De puntkomma wordt escaped door die backslash.</p>
<p>❗ - Er moet een <strong>Spatie</strong> tussen <code>{}</code> en <code>&lt;br/&gt;;</code> komen, anders krijgt men een foutmelding:</p>
<blockquote>
<p>find: missing argument to &lsquo;-exec&rsquo;</p>
</blockquote>
<h3 id="includen-en-excluden-filters">Includen en excluden: filters</h3>
<p>Ik zoek *.properties behalve die en die file en overal behalve in die en die directory:</p>
<pre><code>find . -name &quot;*.properties&quot; -not -path &quot;*dir*&quot; -not -name &quot;ugly.properties&quot;
</code></pre><p><code>-not</code> is te combineren met eender wat én te chainen, bijvoorbeeld met <code>-size</code> enzo.</p>
<h1 id="greppin-away">Greppin' away</h1>
<h4 id="surrounding-lines-while-greppin">Surrounding lines while greppin'</h4>
<p>Dit heet <strong>lines in context</strong> in <em>man grep</em>.</p>
<pre><code>grep -B 3 -A 2 foo README.txt
</code></pre><p>Verklaring: Zoek foo in readme.txt met 3 lijnen boven en 2 lijnen onderaan. <br/><br/>
Indien aantal lijnen gelijk, gebruik simpelweg <code>-C [x]</code>.</p>
<h4 id="inverse-grepping">Inverse grepping</h4>
<h5 id="in-file-contents">In file contents</h5>
<p>Om te zoeken naar bijvoorbeeld &lsquo;hond&rsquo;, maar niet &lsquo;kat&rsquo;, moet je inverse zoeken voor kat:</p>
<pre><code>cat file | grep 'hond' | grep -v 'kat'
</code></pre><h4 id="finding-pattern-a-or-b">Finding pattern a OR b</h4>
<p>Combineren gaat met het pipe character (escaped) <code>&lt;br/&gt;|</code> - voorbeeld zoekt naar hond of kat:</p>
<pre><code>cat file | grep 'hond&lt;br/&gt;|kat'
</code></pre><p>❗ Normale manier is <code>egrep pattern1|pattern2</code> gebruiken of <code>grep -E pattern1|pattern2</code>.</p>
<h4 id="toon-meer-info-bij-context">Toon meer info bij context</h4>
<pre><code>grep 'zoekstring' file.bla -n -H
</code></pre><p>Print ook line numbers &amp; filename, vooral handig wanneer dit van een <code>-exec</code> commando komt van een search, bijvoorbeeld:</p>
<pre><code>find . -name &quot;*.php&quot; -exec grep 'backlink' {} -C 2 -n -H &lt;br/&gt;; &gt; find_backlinks.txt
</code></pre><ol>
<li>Zoek alle .php files vanaf de current directory</li>
<li>Zoek in alle gevonden files naar &lsquo;backlink&rsquo;</li>
<li>Print 2 bovenste en onderste context lijnen af</li>
<li>Print lijn nummer en prefix met bestandsnaam</li>
<li>Output alles naar find_backlinks.txt</li>
</ol>
<p>De <code>-print</code> flag bij find print de filename af voor elke gevonden file die naar de <code>-exec</code> doorgegeven wordt.</p>
<p>❗ Onder Solaris een commando uitvoeren met <code>-exec</code> moet dit ook nog gewrapped worden met een shell executable, zo:</p>
<pre><code>find . -name &quot;*.php&quot; -exec sh -c 'grep -n &quot;backlink&quot; $1' {} {}&lt;br/&gt;; -print
</code></pre><p>Vergeet niet dat grep ook <strong>andere argumenten</strong> (of volgorde) heeft (eerst flags dan search pattern en file, geen -C option etc)!<br/><br/>
Zie <a href="http://www.compuspec.net/reference/os/solaris/find/find_and_execute_with_pipe.shtml">http://www.compuspec.net/reference/os/solaris/find/find_and_execute_with_pipe.shtml</a> <br/><br/></p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>Introduction to JavaScript</title>
<link>https://brainbaking.com/post/2013/10/introduction-to-js/</link>
<comments>https://brainbaking.com/post/2013/10/introduction-to-js/#commento</comments>
<pubDate>Tue, 01 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/introduction-to-js/</guid>
<category domain="https://brainbaking.com/tags/javascript">javascript</category>
<description>
<![CDATA[
<h1 id="javascript-inleiding">Javascript Inleiding</h1>
<h3 id="primitives">Primitives</h3>
<h4 id="soorten">Soorten</h4>
<p>In javascript zijn er slechts 3 primitives:</p>
<ol>
<li><code>string</code> (geassocieerd object: <code>String</code>)</li>
<li><code>boolean</code> (geassocieerd object: <code>Boolean</code>)</li>
<li><code>number</code> (geassocieerd object: <code>Number</code>)</li>
</ol>
<p>Primitives zijn <strong>immutable</strong>! Toekennen van properties maakt ook een tijdelijk object aan, dus dit heeft geen nut.</p>
<h5 id="soort-afchecken">Soort afchecken</h5>
<p>Aangezien JS loosely typed is, kunnen we nooit weten wat er nu in <code>var variabele;</code> steekt op een bepaald moment in de code.<br/><br/>
Om dit op te lossen kan men <code>typeof</code> gebruiken, een functie die een string teruggeeft wat het type van die variabele is.</p>
<p>Typeof retourneert in het geval van een object, de string <code>object</code>, in alle andere gevallen de bovenstaande primitive namen.</p>
<h4 id="object-coercing">Object coercing</h4>
<p>-&gt; <em>(Lees eerst het stuk over objecten etc aub!)</em></p>
<p>Elk van de primitives worden door Javascript automatisch geconverteerd naar hun object representatie wanneer men properties of functies hierop probeert toe te passen. Bvb:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">someString</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;someString&#34;</span>;
<span style="color:#728e00">someString</span>.<span style="color:#728e00">indexOf</span>(<span style="color:#7f8c8d">&#34;String&#34;</span>); <span style="color:#95a5a6">// indexOf() wordt op new String(&#34;someString&#34;) opgeroepen
</span></code></pre></div><p>Direct nadat dit geëvalueerd wordt schiet de garbage collector aan de gang en wordt het tijdelijk object verwijderd.</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">tekst</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;dit is tekst jong&#34;</span>;
<span style="color:#728e00">tekst</span>.<span style="color:#728e00">length</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">3</span>; <span style="color:#95a5a6">// -&gt; String object created &amp; garbage-collected
</span><span style="color:#95a5a6"></span><span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">tekst</span>); <span style="color:#95a5a6">// dit is tekst jong (old primitive value)
</span></code></pre></div><p>Het object dat wordt aangemaakt bijhouden en daar de lengte van afkappen is zelfs gevaarlijk:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">s</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">String</span>(<span style="color:#7f8c8d">&#34;ss&#34;</span>);
<span style="color:#728e00">s</span>.<span style="color:#728e00">length</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">1</span>;
<span style="color:#728e00">for</span>(<span style="color:#728e00">var</span> <span style="color:#728e00">i</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>; <span style="color:#728e00">i</span> <span style="color:#728e00">&lt;</span> <span style="color:#728e00">s</span>.<span style="color:#728e00">length</span>; <span style="color:#728e00">i</span><span style="color:#728e00">++</span>) {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">s</span>[<span style="color:#728e00">i</span>]); <span style="color:#95a5a6">// prints only once &#39;s&#39;
</span><span style="color:#95a5a6"></span>}
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">s</span>); <span style="color:#95a5a6">// prints &#39;ss&#39;??
</span></code></pre></div><p>Als we weten dat een object aangemaakt wordt zodra we een property oproepen, vraagt een mens zich af, hoe zit dat met <code>number</code>s? De <code>.</code> accessor wordt hier gebruikt om komma&rsquo;s voor te stellen&hellip; Wel, aangezien elk object ook values van properties kan retourneren via de <code>[]</code> operator (zie later), werkt dit dus wel:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#8a7b52">21.54</span>[<span style="color:#7f8c8d">&#34;toFixed&#34;</span>]() <span style="color:#95a5a6">// returns 22, way cool!
</span></code></pre></div><p>Zie <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Number">Mozilla MDC Docs: JS Reference: Number</a> voor wat mogelijke functies zijn op <code>Number</code>.</p>
<h3 id="objecten-en-functies">Objecten en Functies</h3>
<p>Douglas Crockford:</p>
<blockquote>
<p>An object is a dynamic collection of properties.</p>
</blockquote>
<p>As opposed to &ldquo;<em>instances of classes</em>&rdquo;.</p>
<p>Een <em>functie</em> in JS kan net zoals andere waarden toegekend worden aan een variabele. Een functie ís in feite een waarde. Dit is anders in bijvoorbeeld Java, een &ldquo;functie&rdquo; (method) is een syntax block code die uitgevoerd kan worden. Wanneer een functie aan een property van een object gekoppeld is spreken we van een method op dat object.</p>
<p>Een object bevat properties. Een functie is een rij van expressies die één waarde retourneert voor dezelfde input te evalueren. Bekijk een &ldquo;functie&rdquo; als zijn mathematische beschrijving: <code>f(x)</code>.</p>
<h4 id="object-literals">Object Literals</h4>
<p>Een object definiëren gaat heel makkelijk:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">Ezel</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Object</span>();
<span style="color:#728e00">Ezel</span>.<span style="color:#728e00">poten</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">4</span>;
<span style="color:#728e00">Ezel</span>.<span style="color:#728e00">balk</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;iaia met mijn &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">this</span>.<span style="color:#728e00">poten</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34; poten&#34;</span>);
};
</code></pre></div><p>Zodra een <code>Object</code> gemaakt wordt, kunnen eender welke property keys toegekend worden met eender welke variabele. Dit kan ook op een <em>associatieve</em> manier, bijvoorbeeld <code>Ezel[&quot;poten&quot;] = 4;</code>.</p>
<p>Bekijk het volgend stukje code:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">Ezel</span> <span style="color:#728e00">=</span> {
<span style="color:#728e00">poten</span><span style="color:#728e00">:</span> <span style="color:#8a7b52">4</span>,
<span style="color:#728e00">balk</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;iaia met mijn &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">this</span>.<span style="color:#728e00">poten</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34; poten&#34;</span>);
}
};
</code></pre></div><p>Hier wordt een object door middel van een <strong>literal</strong> gedefiniëerd. De correcte manier om de ezel te laten balken is <code>Ezel.balk()</code>. Merk op dat <code>Ezel</code> een gewoon object met wat simpele properties is, bekijk het als een map. Dit is een instantie van <code>Object</code>: <code>typeof Ezel</code> retourneert dit.</p>
<h5 id="json-en-object-literals">JSON en Object Literals</h5>
<p><a href="http://www.json.org/js.html">JSON</a> ((JavaScript Object Notation)) is een subset van JavaScript, dus door de JS Compiler op te roepen met <code>eval()</code> is het heel eenvoudig om JSON Strings te evalueren. Een JSON Object is in feite een JS Object Literal:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">JSONObj</span> <span style="color:#728e00">=</span> {
<span style="color:#7f8c8d">&#34;bindings&#34;</span><span style="color:#728e00">:</span> [
{ <span style="color:#7f8c8d">&#34;key&#34;</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;value1&#34;</span>, <span style="color:#7f8c8d">&#34;key2&#34;</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;value2&#34;</span> },
{ <span style="color:#7f8c8d">&#34;key&#34;</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;value3&#34;</span>, <span style="color:#7f8c8d">&#34;key2&#34;</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;value4&#34;</span> }
]
}
</code></pre></div><p>Dat object kan via een string opgebouwd worden door <code>eval()</code> te gebruiken, maar dit is <strong>gevaarlijk</strong> aangezien van een externe webserver ook JS functies in dat data object kunnen zitten! Gebruik daarvoor altijd een JSON Parser, zoals de built-in <code>JSON.parse()</code>.</p>
<p>Om de omgekeerde weg uit te gaan, van object naar string, gebruik <code>JSON.stringify()</code>. Meer uitleg, zie bovenstaande link.</p>
<h4 id="functie-literals">Functie Literals</h4>
<p>Een functie definiëren gaat op drie manieren:</p>
<ol>
<li><code>function bla() { ... }</code> - de normale manier, een <strong>function statement</strong>.</li>
<li><code>var bla = function() { ...}</code> - een <strong>function literal</strong>, ofwel een <em>lambda function</em> (Lisp referentie). In feite een closure die toevallig toegekend wordt aan variabele <code>bla</code>.</li>
<li><code>var bla = new Function(&quot;&quot;, &quot;...&quot;)</code> met als eerste argument de argumenten van de functie, allemaal in <code>string</code> vorm.</li>
</ol>
<p>De onderstaande code definiëert bijvoorbeeld in lambda-stijl een functie genaamd Ezel:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">Ezel</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">poten</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">4</span>;
<span style="color:#728e00">this</span>.<span style="color:#728e00">balk</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;iaia met mijn &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">this</span>.<span style="color:#728e00">poten</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34; poten&#34;</span>);
}
};
</code></pre></div><p>Merk de verschillen op met het bovenstaande:</p>
<ul>
<li><code>function()</code> staat voor <code>{</code>.</li>
<li><code>this</code> wordt gebruikt om keys aan te spreken! Waarom? zie scoping.</li>
<li>De functie bevat gewone statements met <code>=</code> en niet met <code>:</code>. Dit is geen object maar een functie!</li>
</ul>
<p>!! De functie die net aangemaakt is kan nu als constructor dienen. Die werd intern ook aan de Ezel <code>prototype</code> property gekoppeld:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">Ezel</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">constructor</span>
</code></pre></div><p>De correcte manier om de ezel te laten balken is <code>new Ezel().balk()</code>.<br/><br/>
Meer info over hoe <code>new</code> werkt om de ezel instance de poten en de balk functie toe te kennen: zie inheritance.</p>
<h5 id="functies-zijn-objecten">Functies zijn objecten</h5>
<blockquote>
<p>Functions are first class Objects!</p>
</blockquote>
<p>Bewijs: (Uitleg: zie inheritance)</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">Function</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">__proto__</span> <span style="color:#728e00">==</span> <span style="color:#728e00">Object</span>.<span style="color:#728e00">prototype</span>;
(<span style="color:#728e00">function</span> <span style="color:#728e00">fn</span>(){}).<span style="color:#728e00">__proto__</span> <span style="color:#728e00">==</span> <span style="color:#728e00">Function</span>.<span style="color:#728e00">prototype</span>;
</code></pre></div><p>Dus functies zijn <em>ook</em> associatieve maps, dus <code>(function(){}).bla = 3;</code> werkt perfect! Zie scoping, deel &ldquo;Object/Class Member variables&rdquo;.</p>
<h5 id="de-kracht-van-closures">De kracht van closures</h5>
<p>In Javascript is élke functie een <em>closure</em>! In sommige andere talen kan enkel een closure &ldquo;deep bindings&rdquo; uitvoeren (= scope chain bijhouden, zie scoping deel), of een functie opnieuw retourneren. In JS is er geen verschil tussen een literal function en een gewone, buiten de notatie - een literal bind een anonieme functie aan een variabele. Zoiets kan dus perfect:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">a</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">aGetal</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">10</span>;
<span style="color:#728e00">return</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">bGetal</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">20</span>;
<span style="color:#728e00">return</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">cGetal</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">30</span>;
<span style="color:#728e00">return</span> <span style="color:#728e00">aGetal</span> <span style="color:#728e00">+</span> <span style="color:#728e00">bGetal</span> <span style="color:#728e00">+</span> <span style="color:#728e00">cGetal</span>;
}
}
}
<span style="color:#728e00">a</span>()()() <span style="color:#95a5a6">// 60
</span></code></pre></div><p>Merk op dat de <code>()</code> operator een functie uivoert, en hier alles 3x genest is, maar toch de binnenste functie een referentie naar <code>aGetal</code> kan gebruiken, gedefiniëert in de buitenste functie! Lees hierover meer in het scoping gedeelte.</p>
<h5 id="declaratie-van-functie-literals">Declaratie van functie literals</h5>
<p>In javascript worden variabelen die met <code>var</code> gedeclareerd worden <strong>altijd</strong> vooraan geplaatst, ook impliciet. Dit wil zeggen dat wanneer ik een function literal definieer, eigenlijk het volgende gebeurt:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">x</span>() {
<span style="color:#728e00">alert</span>(<span style="color:#7f8c8d">&#34;yo&#34;</span>);
<span style="color:#728e00">var</span> <span style="color:#728e00">b</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { };
} <span style="color:#95a5a6">// is for the JS parser equal to:
</span><span style="color:#95a5a6"></span>
<span style="color:#728e00">function</span> <span style="color:#728e00">xParsed</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">b</span>;
<span style="color:#728e00">alert</span>(<span style="color:#7f8c8d">&#34;yo&#34;</span>);
<span style="color:#728e00">b</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { };
}
</code></pre></div><p>Wanneer je <code>b()</code> probeert uit te voeren vóórdat b effectief geïnitialiseerd is, ontploft de boel. Let hier dus op, en gebruik als dit niet mogelijk is geen literal. Bij naamgevingen binnen een scope geldt een volgorde:</p>
<ol>
<li>Language-defined (<code>this</code>, <code>arguments</code>)</li>
<li>Formal-defined (arguments)</li>
<li>Function-defined</li>
<li>Variable-defined</li>
</ol>
<p>Dat wil zeggen dat wanneer je twee keer x probeert toe te kennen aan een getal én een functie, heeft de functie voorrang.</p>
<p>!! Uitzondering: een formeel argument met naam <code>arguments</code> heeft voorrang op lang-defined <code>arguments</code>. Bad practice&hellip;</p>
<h5 id="itereren-over-properties-van-objecten">Itereren over properties van objecten</h5>
<p>Vergeet niet dat in Javascript alle objecten (zowel object literals als instanties van functies) zich gedragen als een <a href="https://en.wikipedia.org/wiki/Associative%20array" target="_blank">Associative array</a>
- en dat we dus ook kunnen lopen over alle keys:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">N</span> <span style="color:#728e00">=</span> { <span style="color:#728e00">one</span><span style="color:#728e00">:</span> <span style="color:#8a7b52">1</span>, <span style="color:#728e00">two</span><span style="color:#728e00">:</span> <span style="color:#8a7b52">2</span> };
<span style="color:#728e00">for</span>(<span style="color:#728e00">key</span> <span style="color:#728e00">in</span> <span style="color:#728e00">N</span>) {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">key</span> <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34; represents as value: &#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">N</span>[<span style="color:#728e00">key</span>]);
}
</code></pre></div><p>Om de value van een bepaalde key op te halen kan je natuurlijk ook <code>eval('N.' + key)</code> gebruiken - alle wegen leiden tot Rome&hellip;</p>
<h5 id="controleren-of-een-key-in-een-objectarray-beschikbaar-is">Controleren of een key in een object/array beschikbaar is</h5>
<p>Dit kan op enkele manieren:</p>
<ol>
<li><code>'key' in object</code> ((Opgelet: <code>in</code> kan misleidend effect hebben bij gebruik in combinatie met prototypal inheritance, zie later!))</li>
<li><code>object.hasOwnProperty('key')</code> -&gt; gaat wel <code>false</code> retourneren bij overgenomen keys vanuit prototypes. Zie later.</li>
<li>nogmaals itereren (er zijn betere ideeën, dit is de neiging die veel mensen hebben, te procedureel denken!)</li>
</ol>
<p>Wat géén goede manier is:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">Obj</span> <span style="color:#728e00">=</span> {
<span style="color:#728e00">x</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;x&#39;</span>,
<span style="color:#728e00">u</span><span style="color:#728e00">:</span> <span style="color:#00979d">null</span>,
<span style="color:#728e00">un</span><span style="color:#728e00">:</span> <span style="color:#00979d">undefined</span>
};
<span style="color:#728e00">Obj</span>.<span style="color:#728e00">x</span> <span style="color:#728e00">===</span> <span style="color:#00979d">undefined</span> <span style="color:#95a5a6">// false, so it must exist as a key, right?
</span><span style="color:#95a5a6"></span><span style="color:#728e00">Obj</span>.<span style="color:#728e00">u</span> <span style="color:#728e00">==</span> <span style="color:#00979d">undefined</span> <span style="color:#95a5a6">// whoops, true? oplossing: gebruik &#39;#####&#39;
</span><span style="color:#95a5a6"></span><span style="color:#728e00">Obj</span>.<span style="color:#728e00">un</span> <span style="color:#728e00">==</span> <span style="color:#00979d">undefined</span> <span style="color:#95a5a6">// whoops, still true? value kan ook undefined zijn natuurlijk!
</span></code></pre></div><p>#####= Varargs #####=</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">f</span>() {
<span style="color:#728e00">return</span> <span style="color:#728e00">arguments</span>[<span style="color:#8a7b52">0</span>] <span style="color:#728e00">+</span> <span style="color:#728e00">arguments</span>[<span style="color:#8a7b52">1</span>];
}
<span style="color:#728e00">f</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">2</span>) <span style="color:#95a5a6">// == 3
</span></code></pre></div><p>Indien er geen argumenten gespecifiëerd zijn, zijn ze allemaal <em>optioneel</em>! Dit wil zeggen dat een functie aangeroepen kan worden zonder het aantal argumenten 100% te laten overeen komen.</p>
<h6 id="anonymus-functions-en-recursie">anonymus functions en recursie</h6>
<p><code>arguuments</code> heeft nog een speciale property: <code>arguments.callee(...)</code> dat de huidige functie voorstelt, hiermee kan je jezelf aanroepen!</p>
<p>!! Dit gaat een syntax error geven bij ECMA Script standaard 5 in <em>strict</em> mode</p>
<h6 id="verplicht-alle-argumenten-invullen">verplicht alle argumenten invullen</h6>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">f</span>(<span style="color:#728e00">x</span>, <span style="color:#728e00">y</span>, <span style="color:#728e00">z</span>) {
<span style="color:#728e00">if</span>(<span style="color:#728e00">arguments</span>.<span style="color:#728e00">length</span> <span style="color:#728e00">!=</span> <span style="color:#728e00">arguments</span>.<span style="color:#728e00">callee</span>.<span style="color:#728e00">length</span>) {
<span style="color:#728e00">throw</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Error</span>(<span style="color:#7f8c8d">&#34;kapot wabezig&#34;</span>);
}
}
<span style="color:#728e00">f</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">2</span>) <span style="color:#95a5a6">// == 3
</span></code></pre></div><p>Het is natuurlijk makkelijker om <code>!= 3</code> hardcoded te plaatsen, maar dit kan extracted worden naar een aparte functie.</p>
<h6 id="function-overloading">Function overloading</h6>
<p>Overloading bestaat niet in JS aangezien de tweede definitie van de functie de eerste overschrijft (de property &ldquo;functienaam&rdquo; in het object, zeg maar). <br/><br/>
Het is wel mogelijk om één functie te maken die delegeert, zie <a href="http://ejohn.org/blog/javascript-method-overloading/">http://ejohn.org/blog/javascript-method-overloading/</a></p>
<p>Maak handig gebruik van het feit dat de <code>.length</code> property ook op functies opgeroepen kunnen worden! (Telt enkel de gedefiniëerde)</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript">(<span style="color:#728e00">function</span> <span style="color:#728e00">x</span>(<span style="color:#728e00">y</span>, <span style="color:#728e00">z</span>) {}).<span style="color:#728e00">length</span> <span style="color:#a61717">######</span> <span style="color:#8a7b52">2</span>; <span style="color:#95a5a6">// y and z
</span></code></pre></div><p>#####= this Keyword #####=</p>
<p>Zie scoping</p>
<p>#####= Aspect Oriented Programming in JS #####=</p>
<p>Via AOP kan men net voor of na een bepaalde functie gedrag toevoegen zonder dat een component dat die functie aanroept daar weet van heeft. Het is zo makkelijk om bijvoorbeeld logging toe te voegen. In Java wordt Spring AOP gedaan via proxy beans die van dezelfde interface afleiden en daarna delegeren, of via AspectJ die rechtstreeks bytecode wijzigt.</p>
<p>In Javascript kan dat makkelijker, omdat we de referentie naar een functie gewoon kunnen &ldquo;vast&rdquo; pakken. Stel dat ik voordat de ezel balkt wil loggen &ldquo;ik ga balken&rdquo;:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">oldBalkF</span> <span style="color:#728e00">=</span> <span style="color:#728e00">Ezel</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">balk</span>; <span style="color:#95a5a6">// vereist dat balk via `prototype` werd toegevoegd
</span><span style="color:#95a5a6"></span><span style="color:#728e00">Ezel</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">balk</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;ik ga balken! &#34;</span>);
<span style="color:#728e00">oldBalkF</span>.<span style="color:#728e00">call</span>(<span style="color:#728e00">this</span>);
}
<span style="color:#728e00">new</span> <span style="color:#728e00">Ezel</span>().<span style="color:#728e00">balk</span>(); <span style="color:#95a5a6">// print log eerst
</span></code></pre></div><p>Hier merken we twee dingen op:</p>
<ol>
<li>In de nieuwe balk functie kan <strong>niet</strong> zomaar <code>oldBalkF()</code> uitgevoerd worden dan is mijn <code>this</code> referentie naar de ezel instantie weer weg.</li>
<li>De <code>window</code> scope werd vervuild door oldBalkF, die nog steeds toegankelijk is. Hier zijn twee oplossingen voor:
1. <code>delete oldBalkF;</code> na de <code>call</code> instructie (extra werk)
1. Gebruik een anonieme functie die direct uitgevoerd wordt die de scope bewaakt!</li>
</ol>
<p>#####= undefined #####=</p>
<p>Refereren naar een property in een object dat niet bestaat, geeft ons de speciale waarde <code>undefined</code>.<br/><br/>
Merk op dat dit <em>niet hezelfde</em> is als <code>null</code>. Toch zijn ze gerelateerd:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">x</span> <span style="color:#728e00">=</span> {
<span style="color:#728e00">one</span><span style="color:#728e00">:</span> <span style="color:#8a7b52">1</span>
};
<span style="color:#728e00">if</span>(<span style="color:#728e00">x</span>.<span style="color:#728e00">two</span> <span style="color:#728e00">==</span> <span style="color:#00979d">null</span>) {
<span style="color:#8a7b52">3</span>;
}
</code></pre></div><p>Dit geeft 3 omdat <code>x.two ##### undefined</code> en <code>null ###### undefined</code>. Aangezien <code>null</code> in een if test by default <code>true</code> retourneert, kan de if test korter: <code>if(x.two) { ... }</code>.</p>
<p>Zo is het makkelijk om optionele argumenten van functies na te gaan:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">count</span>(<span style="color:#728e00">one</span>, <span style="color:#728e00">two</span>, <span style="color:#728e00">three</span>) {
<span style="color:#728e00">if</span>(<span style="color:#728e00">!</span><span style="color:#728e00">two</span>) <span style="color:#728e00">two</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>;
<span style="color:#728e00">if</span>(<span style="color:#728e00">!</span><span style="color:#728e00">three</span>) <span style="color:#728e00">three</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>;
<span style="color:#728e00">return</span> <span style="color:#728e00">one</span> <span style="color:#728e00">+</span> <span style="color:#728e00">two</span> <span style="color:#728e00">+</span> <span style="color:#728e00">three</span>;
}
</code></pre></div><p>!! <code>undefined</code> is een window-scope variabele die initiëel de value <code>undefined</code> heeft, dit is dus géén keyword, pas op!</p>
<h1 id="async-coding-in-js">Async coding in JS</h1>
<p><a href="http://www.infoq.com/articles/surviving-asynchronous-programming-in-javascript">Asynchronous programming in JS: APIs interview</a> (infoQ)</p>
<h2 id="het-probleem">Het probleem</h2>
<p>Alle events in javascript zijn asynchroon. Dat wil zeggen dat we geen idee hebben wanneer de eigenlijke code uitgevoerd is, en we een <strong>callback closure</strong> moeten meegeven, die verder werkt als de asynchrone code uitgevoerd is.</p>
<p>Dit is oké voor 1-2 asynchrone calls. Maar stel u voor dat we 4+ async calls moeten maken om werk gedaan te krijgen. Typisch dingen zoals:</p>
<ul>
<li>setTimeouts</li>
<li>animaties (jQuery ea)</li>
<li>AJAX calls (REST, naar domein logica, bewaren, opvragen, veranderen, &hellip;)</li>
</ul>
<h3 id="een-integratietest-schrijven-in-js">Een integratietest schrijven in JS</h3>
<p>In <em>Java</em> kunnen we gewoon wat methods oproepen die data persisteert, daarna de eigenlijke <em>asserts</em> schrijven en eventueel in de <code>@After</code> met JUnit data cleanup uitvoeren:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#434f54">DomainObj</span> <span style="color:#434f54">obj</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">DomainObjPersister</span><span style="color:#728e00">()</span>
<span style="color:#728e00">.</span><span style="color:#434f54">withA</span><span style="color:#728e00">()</span>
<span style="color:#728e00">.</span><span style="color:#434f54">withLala</span><span style="color:#728e00">(</span><span style="color:#7f8c8d">&#34;lala&#34;</span><span style="color:#728e00">)</span>
<span style="color:#728e00">.</span><span style="color:#434f54">persist</span><span style="color:#728e00">();</span>
<span style="color:#434f54">ChildObj</span> <span style="color:#434f54">child</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#434f54">ChildObjPersister</span><span style="color:#728e00">()</span>
<span style="color:#728e00">.</span><span style="color:#434f54">withParent</span><span style="color:#728e00">(</span><span style="color:#434f54">obj</span><span style="color:#728e00">)</span>
<span style="color:#728e00">.</span><span style="color:#434f54">persist</span><span style="color:#728e00">();</span>
<span style="color:#434f54">assertThat</span><span style="color:#728e00">(</span><span style="color:#434f54">child</span><span style="color:#728e00">.</span><span style="color:#434f54">getStuff</span><span style="color:#728e00">()).</span><span style="color:#434f54">isNotEmpty</span><span style="color:#728e00">();</span>
</code></pre></div><p>Om <code>child</code> te kunnen persisteren moeten we <code>obj</code> als parent meegeven, dus die call moet eerst uitgevoerd zijn. Alle persisters gaan naar de database. Dit zou in javascript zoiets zijn=
<img style='float: left; width: nolink&|px;' src='/img//code/javascript/kill-it-with-fire.gif'></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">$</span>.<span style="color:#728e00">ajax</span>(<span style="color:#7f8c8d">&#39;/domain/obj/store&#39;</span>, {
<span style="color:#728e00">success</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>(<span style="color:#728e00">obj</span>) {
<span style="color:#728e00">$</span>.<span style="color:#728e00">ajax</span>(<span style="color:#7f8c8d">&#39;/domain/child/store&#39;</span>, {
<span style="color:#728e00">success</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>(<span style="color:#728e00">child</span>) {
<span style="color:#728e00">assertThat</span>(<span style="color:#728e00">child</span>.<span style="color:#728e00">getStuff</span>()).<span style="color:#728e00">isNotEmpty</span>();
}, ...
});
},
<span style="color:#728e00">type</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;PUT&#39;</span>,
<span style="color:#728e00">dataType</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;json&#39;</span>,
<span style="color:#728e00">data</span><span style="color:#728e00">:</span> <span style="color:#728e00">JSON</span>.<span style="color:#728e00">stringify</span>({ <span style="color:#728e00">key</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;value&#39;</span>, <span style="color:#728e00">key2</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;value2&#39;</span> })
});
</code></pre></div><p>Dus een callback wrappen in een callback wrappen in een callback.</p>
<h4 id="async-event-loop-hulpjes">Async event loop hulpjes</h4>
<p>Zie ook <a href="http://vimeo.com/96425312">Philip Roberts: Help, I&rsquo;m stuck in an event-loop</a></p>
<img style='float: left; width: nolink |px;' src='/img//code/javascript/476470428_960.jpg'>
<p>Tooltje om event loop te visualiseren zodat je ziet wat er gebeurt. Breaken in chrome helpt natuurlijk ook, gewoon naar de call stack kijken&hellip;</p>
<h4 id="asynchroon-testen-in-jasmine">Asynchroon testen in Jasmine</h4>
<p>Met <strong>Jasmine</strong> is het (beperkt) mogelijk om te wachten tot dat een stukje werk uitgevoerd is voordat de assertions afgegaan worden. <br/><br/>
Dit kan op de volgende manier:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript">
<span style="color:#728e00">it</span>(<span style="color:#7f8c8d">&#34;should be green, right??&#34;</span>, <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">asyncCallFinished</span> <span style="color:#728e00">=</span> <span style="color:#00979d">false</span>;
<span style="color:#728e00">function</span> <span style="color:#728e00">callback</span>(<span style="color:#728e00">someObj</span>) {
<span style="color:#728e00">asyncCallFinished</span> <span style="color:#728e00">=</span> <span style="color:#00979d">true</span>;
}
<span style="color:#728e00">doAsyncCall</span>(<span style="color:#728e00">callback</span>);
<span style="color:#728e00">waitsFor</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">return</span> <span style="color:#728e00">asyncCallFinished</span> <span style="color:#a61717">#####</span> <span style="color:#00979d">true</span>;
});
<span style="color:#728e00">runs</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">expect</span>(<span style="color:#728e00">stuff</span>).<span style="color:#728e00">toBeLotsBetter</span>();
});
});
</code></pre></div><p>Pitfalls:</p>
<ul>
<li>Ge moet closure scope gebruiken om een variabele bij te houden om te controleren of de async call klaar is in een callback</li>
<li>Ge moet <code>waitsFor()</code> gebruiken, intern pollt Jasmine waarschijnlijk gewoon&hellip;</li>
<li>Ge moet eigenlijke assertions wrappen in <code>runs()</code> omdat <code>waitsFor()</code> direct retourneert en opzich async is.</li>
</ul>
<p>De assertion functiepointers die meegegeven worden met <code>runs()</code> worden intern opgeslaan en bijgehouden totdat de closure van <code>waitsFor()</code> <code>true</code> retourneert. Daarna wordt ook alles pas meegegeven met de Jasmine reporter (logging, output etc). Redelijk omslachtig, aangezien 3+ async calls dan <code>waitsFor()</code> moeten wrappen. Geen oplossing.</p>
<h5 id="asynchroon-testen-met-qunit">Asynchroon testen met QUnit</h5>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">asyncTest</span>(<span style="color:#7f8c8d">&#34;should be green, right??&#34;</span>, <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">stuff</span> <span style="color:#728e00">=</span> <span style="color:#728e00">gogo</span>();
<span style="color:#728e00">function</span> <span style="color:#728e00">callback</span>(<span style="color:#728e00">obj</span>) {
<span style="color:#728e00">equal</span>(<span style="color:#728e00">obj</span>.<span style="color:#728e00">stuff</span>, <span style="color:#8a7b52">2</span>);
<span style="color:#728e00">start</span>();
}
<span style="color:#728e00">doAsyncCall</span>(<span style="color:#728e00">callback</span>);
});
</code></pre></div><p>Pitfalls:</p>
<ul>
<li>In de callback van uw async stuk code moeten zoals verwacht uw assertions zitten</li>
<li>Ge moet een speciale test method gebruiken, <code>asyncTest()</code></li>
<li>Ge moet na uw assertions <code>start()</code> aanroepen (??)</li>
</ul>
<h5 id="de-oplossing">De oplossing</h5>
<p><a href="https://github.com/willconant/flow-js">https://github.com/willconant/flow-js</a> e.a. (of iets zelfgemaakt in die aard).</p>
<p>Herneem bovenstaande integratietest code in javascript, maar dan met flow.js geschreven:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">flow</span>.<span style="color:#728e00">exec</span>(
<span style="color:#728e00">function</span>() {
<span style="color:#728e00">$</span>.<span style="color:#728e00">ajax</span>(<span style="color:#7f8c8d">&#39;/domain/obj/store&#39;</span>, {
<span style="color:#728e00">success</span><span style="color:#728e00">:</span> <span style="color:#728e00">this</span>,
<span style="color:#728e00">type</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;PUT&#39;</span>,
<span style="color:#728e00">dataType</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;json&#39;</span>,
<span style="color:#728e00">data</span><span style="color:#728e00">:</span> <span style="color:#728e00">JSON</span>.<span style="color:#728e00">stringify</span>({ <span style="color:#728e00">key</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;value&#39;</span>, <span style="color:#728e00">key2</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#39;value2&#39;</span> })
});
},
<span style="color:#728e00">function</span>(<span style="color:#728e00">obj</span>) {
<span style="color:#728e00">$</span>.<span style="color:#728e00">ajax</span>(<span style="color:#7f8c8d">&#39;/domain/child/store&#39;</span>, {
<span style="color:#728e00">success</span><span style="color:#728e00">:</span> <span style="color:#728e00">this</span>, ...
});
},
<span style="color:#728e00">function</span>(<span style="color:#728e00">child</span>) {
<span style="color:#728e00">assertThat</span>(<span style="color:#728e00">child</span>.<span style="color:#728e00">getStuff</span>()).<span style="color:#728e00">isNotEmpty</span>();
}
);
</code></pre></div><p>Pitfalls:</p>
<ul>
<li>Error handling wordt opgefreten - gebruik Firebug&rsquo;s <strong>debug on all errors</strong> knop in de console. (anders mechanisme maken dat ze doorgooit van closure1 naar 2 ea)</li>
<li><code>curry()</code> gaat niet lukken aangezien de <code>this</code> pas in de closure zelf de juiste waarde krijgt.</li>
<li><code>this</code> moet meegegeven worden als callback, dus te intensief gebruik makend van <code>this</code> pointer in eigen code kan BOEM geven.</li>
</ul>
<p>flow.js geeft het resultaat van closure1 mee als argument aan closure2 (via <code>arguments</code>) en zo maar door, dat is mega handig.</p>
<h5 id="synchrone-code-code-combineren-met-asynchrone-in-flowjs">Synchrone code code combineren met asynchrone in flow.js</h5>
<p>Enige minpunt is dat de callback <code>this()</code> moet expliciet aangeroepen worden om van closureX naar closureY over te stappen! <br/><br/>
Los dit op met een utility functie:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">flow</span>.<span style="color:#728e00">sync</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>(<span style="color:#728e00">work</span>) {
<span style="color:#728e00">return</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">this</span>(<span style="color:#728e00">work</span>.<span style="color:#728e00">apply</span>(<span style="color:#728e00">this</span>, <span style="color:#728e00">Array</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">slice</span>.<span style="color:#728e00">call</span>(<span style="color:#728e00">arguments</span>, <span style="color:#8a7b52">0</span>)));
}
}
</code></pre></div><p>Zodat we dit kunnen doen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">flow</span>.<span style="color:#728e00">exec</span>(
<span style="color:#728e00">function</span>() {
<span style="color:#728e00">asyncStuff</span>(<span style="color:#728e00">this</span>);
},
<span style="color:#728e00">flow</span>.<span style="color:#728e00">sync</span>(<span style="color:#728e00">function</span>(<span style="color:#728e00">resultfromPrev</span>) {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;lol&#34;</span>); <span style="color:#95a5a6">// no this() required afterwards
</span><span style="color:#95a5a6"></span> }),
<span style="color:#728e00">function</span>(<span style="color:#728e00">resultFromSyncStuff</span>) {
<span style="color:#728e00">doMoreAsyncStuff</span>(<span style="color:#728e00">this</span>);
}
);
</code></pre></div><h5 id="in-een-asynchrone-closure-parallel-werken">In een asynchrone closure parallel werken</h5>
<p>Gebruik <code>this.MULTI()</code> als callback ipv <code>this</code> (zie voorbeeld hieronder)</p>
<h5 id="flowjs-combineren-met-jasmine">flow.js combineren met Jasmine</h5>
<p>Om de smeerlapperij van <code>waitsFor()</code> weg te werken kunnen we ook <code>flow.exec</code> gebruiken.</p>
<p>❗ De laatste stap gaat <strong>altijd</strong> een <code>runs()</code> moeten bevatten voor de reporter om aan te duiden dat assertions uitgevoerd worden, aangezien de <code>exec()</code> functie direct retourneert. Dus moeten we 1x wachten, totdat de hele &ldquo;flow&rdquo; gedaan is. We kunnen dit combineren met BDD en een mini-DSL hierrond schrijven. Resultaat:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">when</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">flowDone</span> <span style="color:#728e00">=</span> <span style="color:#00979d">false</span>;
<span style="color:#728e00">var</span> <span style="color:#728e00">slice</span> <span style="color:#728e00">=</span> <span style="color:#728e00">Array</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">slice</span>;
<span style="color:#728e00">var</span> <span style="color:#728e00">argsArray</span> <span style="color:#728e00">=</span> <span style="color:#728e00">slice</span>.<span style="color:#728e00">call</span>(<span style="color:#728e00">arguments</span>, <span style="color:#8a7b52">0</span>);
<span style="color:#728e00">var</span> <span style="color:#728e00">laatsteArgumenten</span>;
<span style="color:#728e00">argsArray</span>.<span style="color:#728e00">push</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">laatsteArgumenten</span> <span style="color:#728e00">=</span> <span style="color:#728e00">slice</span>.<span style="color:#728e00">call</span>(<span style="color:#728e00">arguments</span>, <span style="color:#8a7b52">0</span>);
<span style="color:#728e00">flowDone</span> <span style="color:#728e00">=</span> <span style="color:#00979d">true</span>;
});
<span style="color:#728e00">flow</span>.<span style="color:#728e00">exec</span>.<span style="color:#728e00">apply</span>(<span style="color:#728e00">this</span>, <span style="color:#728e00">argsArray</span>);
<span style="color:#728e00">waitsFor</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">return</span> <span style="color:#728e00">flowDone</span> <span style="color:#a61717">#####</span> <span style="color:#00979d">true</span>;
});
<span style="color:#728e00">return</span> {
<span style="color:#728e00">then</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>(<span style="color:#728e00">assertionsFn</span>) {
<span style="color:#728e00">runs</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">assertionsFn</span>.<span style="color:#728e00">apply</span>(<span style="color:#728e00">this</span>, <span style="color:#728e00">laatsteArgumenten</span>);
});
}
};
}
</code></pre></div><p>Voorbeeldcode:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript">
<span style="color:#728e00">describe</span>(<span style="color:#7f8c8d">&#34;plaatsen domein&#34;</span>, <span style="color:#728e00">function</span>() {
<span style="color:#728e00">it</span>(<span style="color:#7f8c8d">&#34;wanneer ik alle plaatsen ophaal, kan ik hier domeinspecifieke functies aan opvragen&#34;</span>, <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">plaatsen</span>;
<span style="color:#728e00">when</span>(
<span style="color:#728e00">function</span>() {
<span style="color:#728e00">DOMEIN</span>.<span style="color:#728e00">plaatsRepository</span>.<span style="color:#728e00">bewaarPlaats</span>(<span style="color:#728e00">plaats</span>, <span style="color:#728e00">this</span>.<span style="color:#728e00">MULTI</span>());
<span style="color:#728e00">DOMEIN</span>.<span style="color:#728e00">plaatsRepository</span>.<span style="color:#728e00">bewaarPlaats</span>(<span style="color:#728e00">anderePlaats</span>, <span style="color:#728e00">this</span>.<span style="color:#728e00">MULTI</span>());
},
<span style="color:#728e00">function</span>() {
<span style="color:#728e00">DOMEIN</span>.<span style="color:#728e00">plaatsRepository</span>.<span style="color:#728e00">haalPlaatsenOp</span>(<span style="color:#728e00">this</span>);
}
).<span style="color:#728e00">then</span>(
<span style="color:#728e00">function</span>(<span style="color:#728e00">opgehaaldePlaatsen</span>) {
<span style="color:#728e00">opgehaaldePlaatsen</span>.<span style="color:#728e00">forEach</span>(<span style="color:#728e00">function</span>(<span style="color:#728e00">plaats</span>) {
<span style="color:#728e00">expect</span>(<span style="color:#728e00">plaats</span>.<span style="color:#728e00">geefMeting</span>).<span style="color:#728e00">toBeDefined</span>();
});
}
);
});
});
</code></pre></div><p>Merk op dat de closure meegeven in <code>then()</code> (slechts 1 mogelijk voor assertions) als <strong>argument</strong> het resultaat van de laatste closure in <code>when()</code> meekrijgt!</p>
<h5 id="jquery-16-deferred-en-piping">jQuery 1.6: Deferred en piping</h5>
<p>Vanaf <strong>jQuery 1.6</strong> is het mogelijk om met <code>$.Deferred</code> te werken, dat het mogelijk maakt om een closure uit te voeren op het moment dat &ldquo;werk&rdquo; gedaan is. Met werk bedoelen we:</p>
<ol>
<li>fx: <code>.animate</code> ea</li>
<li>http: <code>.ajax</code> ea</li>
<li>custom code die zelf een <code>$.Deferred</code> object retourneren</li>
</ol>
<h5 id="promising-stuff">Promising stuff</h5>
<p>Alle async operaties worden aan een <em>queue</em> toegevoegd van het jQuery element zelf. Je kan op eender welk moment vragen aan dat queue object, dat wanneer alle items zijn verwerkt er iets speciaals uigevoerd wordt:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">$</span>(<span style="color:#7f8c8d">&#39;#blink&#39;</span>).<span style="color:#728e00">fadeOut</span>().<span style="color:#728e00">promise</span>().<span style="color:#728e00">done</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#39;done blinking!&#39;</span>);
});
</code></pre></div><p>Dit kan dus ook met <code>$.ajax</code>.</p>
<h5 id="zelf-deferred-code-schrijven">Zelf Deferred code schrijven</h5>
<p>Maak een deferred object aan door <code>$.Deferred()</code> aan te roepen. Op dat moment kan je <code>done()</code> hierop zoals in het vorige voorbeeld aanroepen. Bijvoorbeeld:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript">
<span style="color:#728e00">function</span> <span style="color:#728e00">startStuff</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">df</span> <span style="color:#728e00">=</span> <span style="color:#728e00">$</span>.<span style="color:#728e00">Deferred</span>();
<span style="color:#728e00">setTimeout</span>(<span style="color:#8a7b52">1000</span>, <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#39;done async call&#39;</span>);
<span style="color:#728e00">df</span>.<span style="color:#728e00">resolve</span>();
});
<span style="color:#728e00">return</span> <span style="color:#728e00">df</span>.<span style="color:#728e00">promise</span>();
}
<span style="color:#728e00">startStuff</span>().<span style="color:#728e00">done</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#39;really really done with &#34;start stuff&#34;!&#39;</span>);
});
</code></pre></div><h5 id="multiple-elements-in-queue-piping">Multiple elements in queue: piping</h5>
<p>Stel dat eerst element #1 animatie triggert, dan #2, en daarna nog logica dient te gebeuren. Dit kan ook met <code>$.Deferred</code>, door <code>.pipe()</code> te gebruiken om verder te breiden aan de queue.</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">$</span>(<span style="color:#7f8c8d">&#34;button&#34;</span>).<span style="color:#728e00">bind</span>( <span style="color:#7f8c8d">&#34;click&#34;</span>, <span style="color:#728e00">function</span>() {
<span style="color:#728e00">$</span>(<span style="color:#7f8c8d">&#34;p&#34;</span>).<span style="color:#728e00">append</span>( <span style="color:#7f8c8d">&#34;Started...&#34;</span>);
<span style="color:#728e00">var</span> <span style="color:#728e00">div1</span> <span style="color:#a61717">######</span> <span style="color:#728e00">$</span>(<span style="color:#7f8c8d">&#34;#div1&#34;</span>), <span style="color:#728e00">div2</span> <span style="color:#728e00">$</span>(<span style="color:#7f8c8d">&#34;#div2&#34;</span>);
<span style="color:#728e00">var</span> <span style="color:#728e00">df</span> <span style="color:#728e00">=</span> <span style="color:#728e00">$</span>.<span style="color:#728e00">Deferred</span>();
<span style="color:#728e00">df</span>.<span style="color:#728e00">pipe</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">return</span> <span style="color:#728e00">div1</span>.<span style="color:#728e00">fadeOut</span>(<span style="color:#7f8c8d">&#34;slow&#34;</span>)
}).<span style="color:#728e00">pipe</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">return</span> <span style="color:#728e00">div2</span>.<span style="color:#728e00">fadeOut</span>()
}).<span style="color:#728e00">done</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">$</span>(<span style="color:#7f8c8d">&#34;p&#34;</span>).<span style="color:#728e00">append</span>( <span style="color:#7f8c8d">&#34; -- DONE&#34;</span>);
});
<span style="color:#728e00">df</span>.<span style="color:#728e00">resolve</span>();
});
</code></pre></div><p>❗ Pas op, in de <code>.pipe()</code> functie moet een nieuw <strong>promised object</strong> geretourneerd worden! Dat nieuw object wordt als return value van de vorige pipe gebruikt. Op die manier wordt er dus <em>chaining</em> toegepast.</p>
<h1 id="javascript-inheritance">Javascript Inheritance</h1>
<blockquote>
<p>JavaScript uses prototypal inheritance. This means that Javascript does not distinguish between classes/prototypes and instances and, therefore, we can add our desired behavior directly to the instance.</p>
</blockquote>
<h2 id="new-operator">&ldquo;new&rdquo; operator</h2>
<p>Zie <a href="http://unitstep.net/blog/2008/01/24/javascript-and-inheritance/">http://unitstep.net/blog/2008/01/24/javascript-and-inheritance/</a> <br/><br/>
Gegeven de volgende functie:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">X</span>(<span style="color:#728e00">bla</span>) {
<span style="color:#728e00">this</span>.<span style="color:#728e00">x</span> <span style="color:#728e00">=</span> <span style="color:#728e00">bla</span>;
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;doeiets&#34;</span>);
<span style="color:#728e00">this</span>.<span style="color:#728e00">ding</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">return</span> <span style="color:#728e00">this</span>.<span style="color:#728e00">x</span>; };
}
</code></pre></div><p>Wat gebeurt er bij de klassieke manier van een &ldquo;klasse&rdquo; initialiseren? Zo:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">new</span> <span style="color:#728e00">X</span>(<span style="color:#7f8c8d">&#34;argument&#34;</span>).<span style="color:#728e00">ding</span>()
</code></pre></div><p>Omdat geen klassen bestaan, wordt er eigenlijk een &ldquo;leeg&rdquo; object aangemaakt en het prototype van het bestaand object aangepast door <code>call</code> te gebruiken:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">johnDoe</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>(){};
<span style="color:#728e00">X</span>.<span style="color:#728e00">call</span>(<span style="color:#728e00">johnDoe</span>, <span style="color:#7f8c8d">&#34;dinges&#34;</span>)
<span style="color:#728e00">johnDoe</span>.<span style="color:#728e00">ding</span>()
<span style="color:#728e00">johnDoe</span>.<span style="color:#728e00">x</span> <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;dinges&#34;</span>
</code></pre></div><p>Wat gebeurt hier?</p>
<ol>
<li><code>function(){}</code> is een <em>closure</em>, dus een <em>function</em>, zonder inhoud.</li>
<li>de <code>call</code> functie roept een functie aan en vervangt de <code>this</code> referentie (<strong>context</strong>) door het meegegeven argument</li>
<li>Bijgevolg wordt in <code>X()</code>, <code>this.x = bla</code> gedaan, dat wil zeggen dat vanaf nu onze anonieme closure de property <code>x</code> <strong>bevat</strong>, samen met alle functies die binnen <code>X</code> gedefinieerd zijn.</li>
</ol>
<p>Merk op dat &ldquo;bevat&rdquo; impliceert dat het object johnDoe natuurlijk nu ook geheugen toegekend krijgt om de variabele &ldquo;x&rdquo; op te slaan. Dit in contrast met <em>prototypal inheritance</em>, zie volgend stuk.</p>
<p>Eender welke functie heeft een <code>prototype</code>. Een &ldquo;lege&rdquo; functie bevat een dynamische &ldquo;constructor&rdquo; (de functie zelf) met lege body:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript">(<span style="color:#728e00">function</span>(){}).<span style="color:#728e00">prototype</span>
</code></pre></div><h5 id="gewenst-gedrag---wat-waar-plaatsen">Gewenst gedrag - wat waar plaatsen</h5>
<ul>
<li>Indien ik een functie of een variabele heb die anders kan zijn naargelang de implementatie (definiëer de &ldquo;naamgeving&rdquo;), plaats deze dan in de <strong>constructor</strong> functie.</li>
<li>Indien ik een functie of een variabele heb die specifiek voor die functie is en niet gaat veranderen, plaats deze dan <strong>in het concreet object</strong> via <code>this.</code>.</li>
<li>Indien ik een functie of een variabele heb die ik tijdelijk wens te gebruiken, plaats deze dan <strong>in het concreet object</strong> via <code>var</code> ((Maak slim gebruik van scope chaining om zaken te encapsuleren!)).</li>
</ul>
<p>Typisch bevatten constructor functies ook <em>geen</em> return waarden ((dit retourneert dus impliciet <code>undefined</code>)) - we gebruiken deze functies toch altijd in combinatie met de <code>new</code> operator, dus kennen de nieuwe instantie van het object direct toe aan een variabele.</p>
<h5 id="prototype-gebruiken-als-inheritance">prototype gebruiken als inheritance</h5>
<p>-&gt; Meer informatie inclusief grafen met uitgebreide uitleg hoe prototype en constructors werken: zie <a href="http://joost.zeekat.nl/constructors-considered-mildly-confusing.html">http://joost.zeekat.nl/constructors-considered-mildly-confusing.html</a></p>
<p>Aangezien we aan objecten hun functions kunnen via <code>.prototype</code>, is het niet moeilijk om een object zich te laten gedragen als zijn &ldquo;ouder&rdquo;. Neem bijvoorbeeld een dier object, en een concrete ezel implementatie die een extra functie &ldquo;balk&rdquo; definiëert.</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">Vierpotige</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">aantalPoten</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">4</span>;
<span style="color:#728e00">this</span>.<span style="color:#728e00">eetIets</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;omnomnom&#34;</span>);
}
}
<span style="color:#728e00">function</span> <span style="color:#728e00">Ezel</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">balk</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;IEE-AA enzo&#34;</span>);
}
}
<span style="color:#728e00">Ezel</span>.<span style="color:#728e00">prototype</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Vierpotige</span>();
<span style="color:#728e00">var</span> <span style="color:#728e00">ezeltje</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Ezel</span>();
<span style="color:#728e00">ezeltje</span>.<span style="color:#728e00">eetIets</span>(); <span style="color:#95a5a6">// aha! outputs &#39;omnom&#39; en &#39;als ezel fret ik ook nog gras enzo&#39;
</span></code></pre></div><p>Wat gebeurt hier precies?</p>
<ol>
<li>Vierpotige bevat een property aantalPoten en een functie eetIets.</li>
<li>de constructor functie Vierpotige wordt aangeroepen zodra een Ezel aangemaakt wordt, zodat properties en functies overgenomen worden.</li>
<li>een nieuwe ezel eet iets via een prototype functie van een lege Vierpotige.</li>
</ol>
<p>❗ <strong>Opgelet</strong> Vierpotige.prototype bevat enkel de constructor functie zelf en <em>NIET</em> &ldquo;eetIets&rdquo;, daarom dat we Ezel.prototype gelijk stellen aan een nieuwe lege vierpotige. Dit zou niet werken:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">Ezel</span>.<span style="color:#728e00">prototype</span> <span style="color:#728e00">=</span> <span style="color:#728e00">Vierpotige</span>.<span style="color:#728e00">prototype</span>;
<span style="color:#728e00">new</span> <span style="color:#728e00">Ezel</span>().<span style="color:#728e00">eetIets</span>() <span style="color:#95a5a6">// kapot
</span></code></pre></div><p>Tenzij we eetIets definiëren via <code>Vierpotige.prototype.eetIets = function() { ... }</code> - <em>maar</em> dan kan <code>aantalPoten</code> niet meer vanaf een ezel accessed worden.</p>
<p>Nu de prototype property van Ezel en Vierpotige gelijk zijn, kunnen we het prototype uitbreiden met een functie en die direct op ons nieuw ezeltje toepassen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">Vierpotige</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">verteer</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;ist wc bezet??&#34;</span>)
}
<span style="color:#728e00">ezeltje</span>.<span style="color:#728e00">verteer</span>()
</code></pre></div><p>❗ <strong>Waarschuwing</strong> het prototype van <code>Vierpotige</code> aanpassen past ook elke <code>Ezel</code> instantie aan, dit is énorm gevaarlijk als er publieke properties zoals <code>aantalPoten</code> gedefiniëerd zijn! Want in tegenstelling tot wat velen denken, worden properties <strong>niet</strong> gekopiëerd! Dus dit zou het aantal poten van ALLE ezels aanpassen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">dier</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Vierpotige</span>();
<span style="color:#728e00">Ezel</span>.<span style="color:#728e00">prototype</span> <span style="color:#728e00">=</span> <span style="color:#728e00">dier</span>;
<span style="color:#728e00">new</span> <span style="color:#728e00">Ezel</span>().<span style="color:#728e00">aantalPoten</span> <span style="color:#a61717">######</span> <span style="color:#8a7b52">4</span>; <span style="color:#95a5a6">// true
</span><span style="color:#95a5a6"></span><span style="color:#728e00">dier</span>.<span style="color:#728e00">aantalPoten</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">2</span>;
<span style="color:#728e00">new</span> <span style="color:#728e00">Ezel</span>().<span style="color:#728e00">aantalPoten</span> <span style="color:#a61717">######</span> <span style="color:#8a7b52">4</span>; <span style="color:#95a5a6">// false
</span></code></pre></div><h5 id="properties-overriden">Properties overriden</h5>
<p>Prototypal inheritance werkt omdat JS bij elke property lookup kijkt in welk object die referentie gedefiniëerd is. Is dat het huidig object, neem dan die waarde. Indien neen, kijk in het <code>prototype</code> object. Indien neen, kijk in het <code>prototype</code> object van dat object, en zo maar door tot op <code>Object</code> niveau. We kunnen zo ook een property van een prototype zelf overriden, door ander gedrag te definiëren, of zelfs de super aan te roepen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">Vierpotige</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">eetIets</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;vierpotige eten&#34;</span>);
}
<span style="color:#728e00">Ezel</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">eetIets</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">Vierpotige</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">eetIets</span>(); <span style="color:#95a5a6">// &#34;super&#34;
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;als ezel fret ik ook nog gras enzo&#34;</span>);
}
</code></pre></div><h5 id="built-in-js-types-extenden">Built-in JS types extenden</h5>
<p>❗ Extend <strong>nooit</strong> <code>Object.prototype</code>! Waarom? Omdat Eender welk object een instantie van <code>Object</code> is, dus zijn prototype heeft, en met een <code>for(x in prop)</code> deze property nu ineens toegankelijk is voor elk object. Een leeg object <code>{ }</code> wordt verwacht géén properties te hebben!</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">Object</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">hack</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {}
<span style="color:#728e00">for</span>(<span style="color:#728e00">x</span> <span style="color:#728e00">in</span> {}) {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">x</span>); <span style="color:#95a5a6">// print &#34;hack&#34;, zou hier niet in mogen komen
</span><span style="color:#95a5a6"></span>}
</code></pre></div><h5 id="checken-op-inheritance">Checken op inheritance</h5>
<p>Met Javascript kan men door middel van <code>typeof</code> controleren van welk type een variabele is. Dat komt neer op:</p>
<ul>
<li>object (<code>{}</code>)</li>
<li>function (<code>function() {}</code>)</li>
<li>string (<code>&quot;&quot;</code>)</li>
<li>number (<code>-47.2</code>)</li>
</ul>
<p>Het is niet zo interessant om te gebruiken voor eigen inheritance. Daarvoor dient <code>instanceof</code>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">ezeltje</span> <span style="color:#728e00">instanceof</span> <span style="color:#728e00">Vierpotige</span> <span style="color:#728e00">==</span> <span style="color:#00979d">true</span>
<span style="color:#728e00">ezeltje</span> <span style="color:#728e00">instanceof</span> <span style="color:#728e00">Ezel</span> <span style="color:#728e00">==</span> <span style="color:#00979d">true</span>
<span style="color:#728e00">new</span> <span style="color:#728e00">Vierpotige</span>() <span style="color:#728e00">instanceof</span> <span style="color:#728e00">Ezel</span> <span style="color:#728e00">==</span> <span style="color:#00979d">false</span>
</code></pre></div><h5 id="zelf-inheritance-afchecken-met-prototype">Zelf inheritance afchecken met prototype</h5>
<h6 id="met-constructors">met constructors</h6>
<p>Dit is een zeer beperkte manier dat geen rekening houdt met &ldquo;inheritance&rdquo;:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">instanceOf</span>(<span style="color:#728e00">One</span>, <span style="color:#728e00">Two</span>) {
<span style="color:#728e00">return</span> <span style="color:#728e00">One</span>.<span style="color:#728e00">constructor</span> <span style="color:#a61717">######</span> <span style="color:#728e00">Two</span>;
}
<span style="color:#728e00">instanceOf</span>(<span style="color:#728e00">Ezel</span>, <span style="color:#728e00">Vierpotige</span>) <span style="color:#95a5a6">// true
</span></code></pre></div><p>Aangezien elk object een <code>.constructor</code> property heeft die afgeleid werd vanuit de constructor functie die aangeroepen werd, kan men op deze manier een simpele check afwegen. Een praktischer voorbeeld is <code>(typeof (new Date()) ###### object) &amp;&amp; (new Date().constructor ###### Date)</code>.</p>
<h6 id="met-__proto__">met <strong>proto</strong></h6>
<p>Het <code>instanceof</code> keyword kijkt natuurlijk naar de <code>prototype</code> properties van beide objecten om te controleren of object a van object b komt. Dit kan men ook zelf doen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">instanceOf</span>(<span style="color:#728e00">One</span>, <span style="color:#728e00">Two</span>) {
<span style="color:#728e00">return</span> <span style="color:#728e00">One</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">__proto__</span> <span style="color:#a61717">######</span> <span style="color:#728e00">Two</span>.<span style="color:#728e00">prototype</span>;
}
<span style="color:#728e00">instanceOf</span>(<span style="color:#728e00">Ezel</span>, <span style="color:#728e00">Vierpotige</span>) <span style="color:#95a5a6">// true
</span></code></pre></div><p>Hoe kan dit kloppen?</p>
<ol>
<li>Herinner u dit statement: <code>Ezel.prototype = new Vierpotige();</code>. Dit stelt de <code>prototype</code> van Ezel gelijk aan die van een vierpotige. Het enige wat in de <code>prototype</code> van Vierpotige steekt is de <code>verteer()</code> functie, de rest werd via de constructor functie overgekopiëerd!</li>
<li>De magic property <code>_ _proto_ _</code> wordt intern gezet zodra een prototype wordt toegekend aan een object. Aangezien Ezel zelf ook prototype functies heeft specifiek voor ezels, kunnen we die van Vierpotige niet overriden, maar wel gebruiken.</li>
</ol>
<p>❗ Bekijk iets toevoegen via <code>.property</code> als iets toevoegen aan het algemeen prototype object, en iets rechtstreeks toevoegen via een key als iets toevoegen op een instance van dat prototype object. In andere dynamische talen stelt <code>property</code> de <code>metaClass</code> voor, maar JS werkt enkel met functies.</p>
<p>De betere oplossing: <strong><code>isPrototypeOf()</code></strong>! Zie magic properties.</p>
<p>❗ <strong><code>_ _proto_ _</code> is een <strong>instance</strong> property, <code>.prototype</code> een constructor function property</strong></p>
<h6 id="met-properties">met properties</h6>
<p>Door <code>hasOwnProperty()</code> te gebruiken kan je nagaan of een property overgenomen is of niet. Vanaf JS 1.5.</p>
<h5 id="call-als-inheritance">call als inheritance</h5>
<p>De klassieke inheritance structuur zoals in Java en C++ kan beter benaderd worden door <code>call</code> te gebruiken. Herbekijk onze ezels:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">Vierpotige</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">aantalPoten</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">4</span>;
<span style="color:#728e00">this</span>.<span style="color:#728e00">eetIets</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;omnomnom&#34;</span>);
}
}
<span style="color:#728e00">function</span> <span style="color:#728e00">Ezel</span>() {
<span style="color:#728e00">Vierpotige</span>.<span style="color:#728e00">call</span>(<span style="color:#728e00">this</span>);
<span style="color:#728e00">this</span>.<span style="color:#728e00">balk</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;IEE-AA enzo&#34;</span>);
}
}
<span style="color:#728e00">var</span> <span style="color:#728e00">ezeltje</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Ezel</span>();
<span style="color:#728e00">ezeltje</span>.<span style="color:#728e00">eetIets</span>(); <span style="color:#95a5a6">// aha! outputs omnom
</span></code></pre></div><p>Door als eerste statement in de constructor functie van <code>Ezel</code> een <code>call</code> te plaatsen naar onze &ldquo;parent&rdquo;, <em>kopiëren</em> we alle keys en values die daarin gedefiniëerd staan. In tegenstelling tot prototypal inheritance kost dit dus veel meer geheugengebruik, en is dit beperkter om uit te breiden. We linken eigenlijk impliciet twee functies aan elkaar door waarden over te nemen, maar iets aanpassen aan <code>Vierpotige</code> gaat de <code>Ezel</code> op geen ekele manier doen veranderen.</p>
<h5 id="prototypal-inheritance-toepassen">prototypal inheritance toepassen</h5>
<p>In plaats van <code>new</code> overal te gebruiken zonder te weten wat hierachter ligt, kan men <code>create</code> ook gebruiken:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">if</span> (<span style="color:#728e00">typeof</span> <span style="color:#728e00">Object</span>.<span style="color:#728e00">create</span> <span style="color:#728e00">!</span><span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#39;function&#39;</span>) {
<span style="color:#728e00">Object</span>.<span style="color:#728e00">create</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span> (<span style="color:#728e00">o</span>) {
<span style="color:#728e00">function</span> <span style="color:#728e00">F</span>() {}
<span style="color:#728e00">F</span>.<span style="color:#728e00">prototype</span> <span style="color:#728e00">=</span> <span style="color:#728e00">o</span>;
<span style="color:#728e00">return</span> <span style="color:#728e00">new</span> <span style="color:#728e00">F</span>();
};
}
<span style="color:#728e00">newObject</span> <span style="color:#728e00">=</span> <span style="color:#728e00">Object</span>.<span style="color:#728e00">create</span>(<span style="color:#728e00">oldObject</span>);
</code></pre></div><p>Zie <a href="http://javascript.crockford.com/prototypal.html">http://javascript.crockford.com/prototypal.html</a></p>
<h5 id="een-minder-verbose-manier-om-extra-properties-te-definiëren">Een minder verbose manier om extra properties te definiëren</h5>
<p>Zie <a href="http://howtonode.org/prototypical-inheritance">http://howtonode.org/prototypical-inheritance</a> -</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">Object</span>.<span style="color:#728e00">defineProperty</span>(<span style="color:#728e00">Object</span>.<span style="color:#728e00">prototype</span>, <span style="color:#7f8c8d">&#34;spawn&#34;</span>, {<span style="color:#728e00">value</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span> (<span style="color:#728e00">props</span>) {
<span style="color:#728e00">var</span> <span style="color:#728e00">defs</span> <span style="color:#728e00">=</span> {}, <span style="color:#728e00">key</span>;
<span style="color:#728e00">for</span> (<span style="color:#728e00">key</span> <span style="color:#728e00">in</span> <span style="color:#728e00">props</span>) {
<span style="color:#728e00">if</span> (<span style="color:#728e00">props</span>.<span style="color:#728e00">hasOwnProperty</span>(<span style="color:#728e00">key</span>)) {
<span style="color:#728e00">defs</span>[<span style="color:#728e00">key</span>] <span style="color:#728e00">=</span> {<span style="color:#728e00">value</span><span style="color:#728e00">:</span> <span style="color:#728e00">props</span>[<span style="color:#728e00">key</span>], <span style="color:#728e00">enumerable</span><span style="color:#728e00">:</span> <span style="color:#00979d">true</span>};
}
}
<span style="color:#728e00">return</span> <span style="color:#728e00">Object</span>.<span style="color:#728e00">create</span>(<span style="color:#728e00">this</span>, <span style="color:#728e00">defs</span>);
}});
</code></pre></div><p>Op die manier kan je <code>BaseObj.spawn({'extraProp': 'extraValue'});</code> gebruiken, zonder de relatieve verbose manier van extra properties te moeten gebuiken die <code>Object.create</code> <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create#Classical_inheritance_with_Object.create">handhaaft</a>.</p>
<h5 id="prototype-js-en-classcreate">Prototype JS en Class.create</h5>
<p>Javascript frameworks proberen altijd inheritance makkelijker te maken voor klassieke OO developers door functies te modelleren als klassen. In <a href="http://www.prototypejs.org/api/class">Prototype JS</a> kan men zoiets doen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript">
<span style="color:#728e00">var</span> <span style="color:#728e00">Animal</span> <span style="color:#728e00">=</span> <span style="color:#728e00">Class</span>.<span style="color:#728e00">create</span>({
<span style="color:#728e00">initialize</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">something</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;wow&#34;</span>;
},
<span style="color:#728e00">speak</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">this</span>.<span style="color:#728e00">something</span>);
}
});
<span style="color:#728e00">var</span> <span style="color:#728e00">Snake</span> <span style="color:#728e00">=</span> <span style="color:#728e00">Class</span>.<span style="color:#728e00">create</span>(<span style="color:#728e00">Animal</span>, {
<span style="color:#728e00">hiss</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">speak</span>();
}
});
</code></pre></div><p>Snake leidt af van Animal, en de <code>initialize()</code> functies stellen de constructor functies voor. Wat gebeurt er dan achter de schermen bij <code>Class.create({...})</code>?</p>
<ol>
<li>Net zoals hierboven wordt de constructor functie via <code>apply</code> aangeroepen (zelfde als call). Enkel wordt als <code>this</code> een lege functie toegevoegd.</li>
<li><code>Object.extend()</code> wordt gebruikt om alle keys van de parent te kopiëren naar de nieuwe lege functie.</li>
<li>De <code>prototype</code> property van de parent wordt net zoals hierboven gezet op de nieuwe &ldquo;klasse&rdquo;.</li>
<li>Speciale gevallen zoals een &ldquo;lege constructor&rdquo; functie indien nodig, intern bijhouden wat sub- en superklassen van elkaar zijn, etc.</li>
</ol>
<p>In essentie komt het neer op &ldquo;<em>syntax sugaring</em>&rdquo; zodat het klassieke OO model gebruikt kan worden - terwijl er onderliggend iets anders gebeurt.<br/><br/>
Meer info over deze implementatie: <a href="http://code.google.com/p/inheritance/">http://code.google.com/p/inheritance/</a></p>
<p>############= Multiple inheritance ############=</p>
<p>Perfect mogelijk, of slechts delen van object A en alles van B voor object C gebruiken (<strong>mixins</strong>!). Simpelweg alles van de ene <code>prototype</code> property naar de andere overzetten wat nodig is:</p>
<p>######= Methode 1 ######=</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">A</span>(){};
<span style="color:#728e00">A</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">a</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;a&#34;</span>; }
<span style="color:#728e00">A</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">c</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;a&#34;</span>; }
<span style="color:#728e00">function</span> <span style="color:#728e00">B</span>(){};
<span style="color:#728e00">B</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">b</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;b&#34;</span>; }
<span style="color:#728e00">function</span> <span style="color:#728e00">C</span>(){};
<span style="color:#728e00">for</span>(<span style="color:#728e00">prop</span> <span style="color:#728e00">in</span> <span style="color:#728e00">B</span>.<span style="color:#728e00">prototype</span>) {
<span style="color:#728e00">C</span>.<span style="color:#728e00">prototype</span>[<span style="color:#728e00">prop</span>] <span style="color:#728e00">=</span> <span style="color:#728e00">B</span>.<span style="color:#728e00">prototype</span>[<span style="color:#728e00">prop</span>];
}
<span style="color:#728e00">C</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">a</span> <span style="color:#728e00">=</span> <span style="color:#728e00">A</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">a</span>;
<span style="color:#728e00">C</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">c</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;c&#34;</span>; }
<span style="color:#728e00">var</span> <span style="color:#728e00">c</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">C</span>();
<span style="color:#728e00">c</span>.<span style="color:#728e00">a</span>() <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;a&#34;</span>;
<span style="color:#728e00">c</span>.<span style="color:#728e00">b</span>() <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;b&#34;</span>;
<span style="color:#728e00">c</span>.<span style="color:#728e00">c</span>() <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;c&#34;</span>;
</code></pre></div><p>######= Methode 2 ######=</p>
<p>Creeër de illusie om constructor(s) aan te roepen in een constructor functie van een ander object:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">B</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">b</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;b&#34;</span>; }
}
<span style="color:#728e00">function</span> <span style="color:#728e00">C</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">c</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;c&#34;</span>; }
}
<span style="color:#728e00">function</span> <span style="color:#728e00">A</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">a</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() { <span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;a&#34;</span>; }
<span style="color:#728e00">this</span>.<span style="color:#00979d">super</span> <span style="color:#728e00">=</span> <span style="color:#728e00">B</span>;
<span style="color:#728e00">this</span>.<span style="color:#728e00">super2</span> <span style="color:#728e00">=</span> <span style="color:#728e00">C</span>;
<span style="color:#728e00">this</span>.<span style="color:#00979d">super</span>(); <span style="color:#95a5a6">// kopiëer de b functie in A, maar inherit niet!
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">this</span>.<span style="color:#728e00">super2</span>();
}
<span style="color:#728e00">var</span> <span style="color:#728e00">a</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">A</span>();
<span style="color:#728e00">a</span>.<span style="color:#728e00">a</span>() <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;a&#34;</span>;
<span style="color:#728e00">a</span>.<span style="color:#728e00">b</span>() <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;b&#34;</span>;
<span style="color:#728e00">a</span>.<span style="color:#728e00">c</span>() <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;c&#34;</span>;
</code></pre></div><p>######= Problemen met mixins ######=</p>
<p>❗ Dit is géén authentieke multiple inheritance. Hier zijn twee problemen aan gekoppeld:</p>
<ol>
<li>Zodra via <code>B.prototype</code> een nieuwe functie toegevoegd wordt, zal C deze <strong>niet</strong> overpakken omdat <code>C.prototype</code> niet <em>gelijk</em> gesteld werd aan die van A of B</li>
<li>En bijgevolg dus ook de <code>instanceof</code> operator naar de zak is:</li>
</ol>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">c</span> <span style="color:#728e00">instanceof</span> <span style="color:#728e00">C</span> <span style="color:#a61717">######</span> <span style="color:#00979d">true</span>
(<span style="color:#728e00">c</span> <span style="color:#728e00">instanceof</span> <span style="color:#728e00">B</span> <span style="color:#728e00">||</span> <span style="color:#728e00">c</span> <span style="color:#728e00">instanceof</span> <span style="color:#728e00">A</span>) <span style="color:#a61717">######</span> <span style="color:#00979d">false</span>
</code></pre></div><p>Als dit echt nodig is kan men zoiets zelf implementeren door weer te loopen via <code>for(prop in x.prototype) { ... }</code> en te checken of alle keys voorkomen in een object.</p>
<p>Zie Mozilla Dev center: <a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Details_of_the_Object_Model#No_Multiple_Inheritance">Details of the Object Model</a></p>
<h1 id="javascript-scoping">Javascript Scoping</h1>
<h3 id="toplevel-scope">Toplevel Scope</h3>
<p>Een stuk Javascript in een HTML pagina, zonder eender welke functie te definiëren, werkt altijd op <strong>top-level scope</strong>. Dat stelt het <code>window</code> object voor, waar we ook resolutie gegevens en dergelijke kunnen uithalen. Dus simpele variabelen declareren om in HTML te kunnen gebruiken werkt altijd op de globale scope:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">customerEmail</span> <span style="color:#728e00">=</span> <span style="color:#728e00">document</span>.<span style="color:#728e00">getElementById</span>(<span style="color:#7f8c8d">&#34;username&#34;</span>) <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34;@&#34;</span> <span style="color:#728e00">+</span> <span style="color:#728e00">document</span>.<span style="color:#728e00">getElementById</span>(<span style="color:#7f8c8d">&#34;domain&#34;</span>) <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#34;.com&#34;</span>;
<span style="color:#728e00">window</span>.<span style="color:#728e00">customerEmail</span> <span style="color:#95a5a6">// what did I do?? (null@null.com if unknown IDs)
</span></code></pre></div><p>Om te vermijden dat we alles op het <code>window</code> object &ldquo;dumpen&rdquo;, schrijven we nette functies die zaken zoals tijdelijke variabelen en private stukken code <em>encapsuleren</em>.</p>
<h4 id="variabele-declaratie">Variabele declaratie</h4>
<p>Variabelen definiëren gaat met <code>var</code> (zoals hierboven), máár <em>globale</em> (window-scope) variabelen kunnen gedeclareerd worden zonder dit. Pas hiermee op:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">woot</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;leet&#34;</span>;
<span style="color:#728e00">function</span> <span style="color:#728e00">yo</span>() {
<span style="color:#728e00">woot</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;omg&#34;</span>; <span style="color:#95a5a6">// whoops, I changed a global var
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">meerWoot</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;leet&#34;</span>;
<span style="color:#728e00">var</span> <span style="color:#728e00">wootwoot</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;one!!1&#34;</span>;
}
<span style="color:#728e00">yo</span>();
<span style="color:#728e00">window</span>.<span style="color:#728e00">woot</span> <span style="color:#a61717">#####</span> <span style="color:#7f8c8d">&#34;leet&#34;</span> <span style="color:#95a5a6">// false
</span><span style="color:#95a5a6"></span><span style="color:#728e00">window</span>.<span style="color:#728e00">meerWoot</span> <span style="color:#a61717">#####</span> <span style="color:#7f8c8d">&#34;leet&#34;</span> <span style="color:#95a5a6">// true
</span><span style="color:#95a5a6"></span><span style="color:#728e00">window</span>.<span style="color:#728e00">wootwoot</span> <span style="color:#a61717">#####</span> <span style="color:#00979d">undefined</span> <span style="color:#95a5a6">// true
</span></code></pre></div><p>Dit verklaart de nood om <code>var</code> te gebruiken om <em>lokale</em> variabelen te definiëren.<br/><br/>
Merk op dat hier <code>wootwoot</code> énkel binnen de functie <code>yo()</code> leeft, dus via de Javascript <em>Garbage Collector</em> weggesmeten wordt zodra die functie volledig geëvalueerd is.</p>
<p>#####= Nested en Block scope #####=</p>
<p>Functies in functies in functies zijn perfect mogelijk, en de binnenste functies hebben toegang tot de scope van alle anderen.</p>
<p>❗ In tegenstelling tot Java e.a. beschikt JS <strong>niet over block scope</strong>. Dit wil zeggen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">f1</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">10</span>;
<span style="color:#728e00">function</span> <span style="color:#728e00">f</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">f1</span>); <span style="color:#95a5a6">// 10? Nope, undefined!
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">var</span> <span style="color:#728e00">f1</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">1</span>;
<span style="color:#728e00">function</span> <span style="color:#728e00">z</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">z1</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">2</span>;
<span style="color:#728e00">if</span>(<span style="color:#728e00">f1</span> <span style="color:#a61717">######</span> <span style="color:#8a7b52">1</span>) {
<span style="color:#728e00">var</span> <span style="color:#728e00">z2</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">2</span>;
}
<span style="color:#728e00">return</span> <span style="color:#728e00">z1</span> <span style="color:#728e00">+</span> <span style="color:#728e00">z2</span>; <span style="color:#95a5a6">// z2 nog steeds toegankelijk
</span><span style="color:#95a5a6"></span> }
}
</code></pre></div><p>Waarom logt dit <code>undefined</code>, terwijl op global scope aan f1 10 toegekend wordt? Omdat een tweede variabele genaamd f1 in de <em>body</em> van de functie gedeclareerd wordt, wordt die versie gebruikt, <strong>ook al is deze nog niet toegekend!</strong>. Wow.</p>
<p>JS Is dus buiten de <em>lexicale scoping</em> ook nog eens <em>function-level scoped</em>.</p>
<p>Een duidelijker voorbeeld via <a href="http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting:">http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting:</a></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#728e00">#include</span> <span style="color:#728e00">&lt;stdio.h&gt; </span><span style="color:#728e00">
</span><span style="color:#728e00"></span><span style="color:#00979d">int</span> <span style="color:#d35400">main</span>() {
<span style="color:#00979d">int</span> <span style="color:#434f54">x</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">1</span>;
<span style="color:#434f54">printf</span>(<span style="color:#7f8c8d">&#34;%d, &#34;</span>, <span style="color:#434f54">x</span>); <span style="color:#95a5a6">// 1
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">if</span> (<span style="color:#8a7b52">1</span>) {
<span style="color:#00979d">int</span> <span style="color:#434f54">x</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">2</span>;
<span style="color:#434f54">printf</span>(<span style="color:#7f8c8d">&#34;%d, &#34;</span>, <span style="color:#434f54">x</span>); <span style="color:#95a5a6">// 2
</span><span style="color:#95a5a6"></span> }
<span style="color:#434f54">printf</span>(<span style="color:#7f8c8d">&#34;%d&lt;br/&gt;n&#34;</span>, <span style="color:#434f54">x</span>); <span style="color:#95a5a6">// 1
</span><span style="color:#95a5a6"></span>}
</code></pre></div><p>Print logischerwijze 1, 2, 1, juist? Doe hetzelfde eens in javascript:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">x</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">1</span>;
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">x</span>); <span style="color:#95a5a6">// 1
</span><span style="color:#95a5a6"></span><span style="color:#728e00">if</span> (<span style="color:#00979d">true</span>) {
<span style="color:#728e00">var</span> <span style="color:#728e00">x</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">2</span>;
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">x</span>); <span style="color:#95a5a6">// 2
</span><span style="color:#95a5a6"></span>}
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">x</span>); <span style="color:#95a5a6">// 2
</span></code></pre></div><p><em>BOOM</em>. <br/><br/>
Dit komt doordat <code>if</code> statements geen nieuwe scope introduceren, enkel <code>function</code> definities! Een oplossing is een anonieme functie gebruiken en die direct evalueren:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">foo</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">x</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">1</span>;
<span style="color:#728e00">if</span> (<span style="color:#728e00">x</span>) {
(<span style="color:#728e00">function</span> () {
<span style="color:#728e00">var</span> <span style="color:#728e00">x</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">2</span>;
<span style="color:#95a5a6">// some other code
</span><span style="color:#95a5a6"></span> }());
}
<span style="color:#95a5a6">// x is still 1.
</span><span style="color:#95a5a6"></span>}
</code></pre></div><h5 id="scope-chain">Scope chain</h5>
<p>Elke JS Executie context heeft een <strong>scope chain</strong> toegekend. Dit is een lijst van objecten waar de interpreter door gaat om een variabele x op te kunnen zoeken (Dit proces heet <em>variable name resolution</em>). Men begint met de huidige context van de functie die opgeroepen wordt. Indien variabele x daar niet gedefiniëerd is, ga een scope hoger, en zo voort.</p>
<p>In <em>top-level</em> JS (op window scope) bevat de scope chain slechts één object, het &ldquo;globaal&rdquo; object. (<code>window</code>)</p>
<h5 id="event-handler-scope-chain">Event handler scope chain</h5>
<p>Bij het uitvoeren van events in de DOM Tree zitten er buiten <code>window</code> nog enkele andere objecten op de scope chain: het object dat het event zelf triggerde. Het is dus mogelijk om rechtstreeks vanuit een <code>onclick</code> event van een <code>input</code> tag, een ander <code>form</code> element aan te spreken zonder dit eerst te resolven via de klassieke <code>getElementById()</code>:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">&lt;<span style="color:#434f54">head</span>&gt;
&lt;<span style="color:#434f54">script</span>&gt;
<span style="color:#728e00">function</span> <span style="color:#728e00">load</span>() {
<span style="color:#728e00">document</span>.<span style="color:#728e00">getElementById</span>(<span style="color:#7f8c8d">&#34;text&#34;</span>).<span style="color:#728e00">onclick</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">alert</span>(<span style="color:#728e00">anders</span>.<span style="color:#728e00">value</span>);
}
}
&lt;/<span style="color:#434f54">script</span>&gt;
&lt;/<span style="color:#434f54">head</span>&gt;
&lt;<span style="color:#434f54">body</span> <span style="color:#434f54">onload</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;load();&#34;</span>&gt;
&lt;<span style="color:#434f54">input</span> <span style="color:#434f54">type</span><span style="color:#a61717">######&#34;</span><span style="color:#434f54">text</span><span style="color:#a61717">&#34;</span> <span style="color:#434f54">id</span><span style="color:#a61717">&#34;</span><span style="color:#434f54">text</span><span style="color:#a61717">&#34;</span> <span style="color:#434f54">value</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;blabla&#34;</span> /&gt;
&lt;<span style="color:#434f54">input</span> <span style="color:#434f54">type</span><span style="color:#a61717">######&#34;</span><span style="color:#434f54">text</span><span style="color:#a61717">&#34;</span> <span style="color:#434f54">id</span><span style="color:#a61717">&#34;</span><span style="color:#434f54">anders</span><span style="color:#a61717">&#34;</span> <span style="color:#434f54">value</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;blieblie&#34;</span> /&gt;
&lt;/<span style="color:#434f54">body</span>&gt;
</code></pre></div><p>merk op dat <code>anders.value</code> mogelijk is doordat het DOM element text mee op de scope chain zit. <br/><br/>
Dit is vanzelfsprekend serieus verwarrend en <strong>bad practice</strong>, Firebug waarschuwt hier ook voor:</p>
<blockquote>
<p>Element referenced by ID/NAME in the global scope. Use W3C standard document.getElementById() instead.</p>
</blockquote>
<p>Dit kan serieuze problemen met zich mee brengen, zeker wanneer mensen niet goed weten hoe javascript te gebruiken en bijvoorbeeld for loopjes schrijven door variabelen op toplevel scope te introduceren:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">
&lt;<span style="color:#434f54">head</span>&gt;
&lt;<span style="color:#434f54">script</span>&gt;
<span style="color:#728e00">function</span> <span style="color:#728e00">Iets</span>(<span style="color:#728e00">e</span>) {
<span style="color:#728e00">return</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">alert</span>(<span style="color:#728e00">j</span>); <span style="color:#95a5a6">// DOM Element: Div met id &#34;j&#34;, al hebben we nergens j gedefiniëerd!!!
</span><span style="color:#95a5a6"></span>
<span style="color:#95a5a6">// j = 0: BOOM in IE: Object doesn&#39;t support this property or method
</span><span style="color:#95a5a6"></span> <span style="color:#95a5a6">// reden =&gt; in IE is dit een readonly property, Gecko parsers zijn lakser hierin
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">for</span>(<span style="color:#728e00">j</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">0</span>; <span style="color:#728e00">j</span> <span style="color:#728e00">&lt;</span> <span style="color:#8a7b52">10</span>; <span style="color:#728e00">j</span><span style="color:#728e00">++</span>) {
<span style="color:#95a5a6">// whatever
</span><span style="color:#95a5a6"></span> }
<span style="color:#728e00">alert</span>(<span style="color:#728e00">j</span>); <span style="color:#95a5a6">// 10
</span><span style="color:#95a5a6"></span> }
}
&lt;/<span style="color:#434f54">script</span>&gt;
&lt;/<span style="color:#434f54">head</span>&gt;
&lt;<span style="color:#434f54">body</span>&gt;
&lt;<span style="color:#434f54">h2</span>&gt;Javascript event scopechain voorbeeld&lt;/<span style="color:#434f54">h2</span>&gt;
&lt;<span style="color:#434f54">div</span> <span style="color:#434f54">id</span><span style="color:#a61717">######&#34;</span><span style="color:#434f54">j</span><span style="color:#a61717">&#34;</span> <span style="color:#434f54">onclick</span><span style="color:#a61717">&#34;</span><span style="color:#434f54">Iets</span><span style="color:#a61717">()()&#34;</span>&gt;
Klik hierop aub
&lt;/<span style="color:#434f54">div</span>&gt;
&lt;/<span style="color:#434f54">body</span>&gt;
</code></pre></div><h5 id="scope-tijdelijk-aanpassen">Scope tijdelijk aanpassen</h5>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">with</span>(<span style="color:#728e00">window</span>.<span style="color:#728e00">screen</span>) {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">width</span>);
}
</code></pre></div><p>Al is <code>var screen = window.screen; screen.width</code> natuurlijk even makkelijk.</p>
<p>#####= Private Member variables #####=</p>
<p>❗ &ldquo;Functies en variabelen in objecten zijn overal en altijd toegankelijk&rdquo;. <strong>DIT IS FOUT</strong>! Bekijk het volgende voorbeeld (zie <a href="http://www.crockford.com/javascript/private.html">private members</a> docs):</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">Func</span>(<span style="color:#728e00">param</span>) {
<span style="color:#728e00">this</span>.<span style="color:#728e00">publicMember</span> <span style="color:#728e00">=</span> <span style="color:#728e00">param</span>;
<span style="color:#728e00">var</span> <span style="color:#728e00">privateMember</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">10</span>;
<span style="color:#728e00">var</span> <span style="color:#728e00">me</span> <span style="color:#728e00">=</span> <span style="color:#728e00">this</span>;
<span style="color:#728e00">this</span>.<span style="color:#728e00">publicFunction</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">this</span>.<span style="color:#728e00">publicMember</span>);
};
<span style="color:#95a5a6">// could be function privateFunction() {
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">var</span> <span style="color:#728e00">privateFunction</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">privateMember</span>);
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">this</span>.<span style="color:#728e00">publicMember</span>); <span style="color:#95a5a6">// BOOM
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">me</span>.<span style="color:#728e00">publicMember</span>); <span style="color:#95a5a6">// OK
</span><span style="color:#95a5a6"></span> };
}
<span style="color:#728e00">new</span> <span style="color:#728e00">Func</span>(<span style="color:#8a7b52">10</span>).<span style="color:#728e00">privateFunction</span>() <span style="color:#95a5a6">// BOEM
</span></code></pre></div><p>Zodra we <code>this</code> gebruiken om members in een constructor functie te steken wordt het publiek. Zodra we gewoon variabelen definiëren, ook al zijn het closures zoals <code>privateFunction</code>, is dit <em>niet</em> toegankelijk voor de buitenwereld! Dit wil zeggen dat het zelfs niet toegankelijk is voor <code>.prototype</code>-toegevoegde functies.</p>
<p>Merk op dat we aan <code>privateMember</code> kunnen zonder <code>this</code> te gebruiken om naar iets te refereren. Dit komt omdat die members in de context van het object zitten.<br/><br/>
Een probleem dat zich voordoet is dat de <code>this</code> pointer binnen private functions natuurlijk weer gereset wordt tot op <code>window</code> scope. Om dit op te lossen kunnen we een private variabele voorzien die refereert naar <code>this</code>, daarvoor dient <code>me</code>.</p>
<h6 id="private-public-en-prototype-functies">Private, Public en prototype functies</h6>
<p>Een <strong>private</strong> functie is een functie die in de constructor functie gedefiniëerd is als <em>member variabele</em>, en dus geldig is binnen de context van die functie. <br/><br/>
Een <strong>privileged</strong> functie is een functie die in de constructor functie gedefiniëerd is met de <em>this accessor</em>. Deze functies kunnen private functies aanroepen omdat ze binnen de context van de constructor functie leven, en zijn ook aanroepbaar van buitenaf.<br/><br/>
Een <strong>public</strong> functie is een functie die in het <em>prototype</em> leeft van een object((privileged en public zijn in feite gelijk, onderscheid wordt gemaakt om public variables te scheidden)). Private members zijn hier niet toegankelijk, privileged wel. Een voorbeeld (vervolg):</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">Func</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">publicThing</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">alert</span>(<span style="color:#728e00">this</span>.<span style="color:#728e00">publicMember</span>);
<span style="color:#728e00">return</span> <span style="color:#728e00">this</span>.<span style="color:#728e00">privateMember</span>; <span style="color:#95a5a6">// BOOM
</span><span style="color:#95a5a6"></span>};
</code></pre></div><p>#####= Object/Class Member variables #####=</p>
<p>In typische OO talen zoals Java en C++ kunnen ook &ldquo;statics&rdquo; gedefiniëerd worden die enkel op klasse niveau leven. Zoiets is heel simpel te realiseren met Javascript, door een property op de constructor functie zelf te steken:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">Const</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">c</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;const&#34;</span>;
<span style="color:#728e00">c</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;globalConst&#34;</span>;
}
<span style="color:#728e00">Const</span>.<span style="color:#728e00">C</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;C&#34;</span>;
<span style="color:#728e00">c</span> <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;globalConst&#34;</span>; <span style="color:#95a5a6">// remember, window scope
</span><span style="color:#95a5a6"></span><span style="color:#728e00">new</span> <span style="color:#728e00">Const</span>().<span style="color:#728e00">c</span> <span style="color:#a61717">######</span> <span style="color:#7f8c8d">&#34;const&#34;</span>;
<span style="color:#728e00">new</span> <span style="color:#728e00">Const</span>().<span style="color:#728e00">C</span> <span style="color:#728e00">!=</span> <span style="color:#00979d">undefined</span>
</code></pre></div><p>Dit noemen we &ldquo;class&rdquo; properties, in plaats van &ldquo;instance&rdquo; properties.</p>
<p>#####= Anonieme functies gebruiken om members private te maken #####=</p>
<p>Probleem: publieke functies die aan een object hangen met <code>this.functie = function() { ... }</code> zijn toegankelijk. Ik wil iets groeperen zonder <code>window</code> scope te vervuilen. Hoe kan ik één functie opsplitsen zonder de andere te <em>exposen</em>?<br/><br/>
Oplossing:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">Stuff</span> <span style="color:#728e00">=</span> (<span style="color:#728e00">function</span>() {
<span style="color:#728e00">function</span> <span style="color:#728e00">doeStap1</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#7f8c8d">&#34;private things in here&#34;</span>);
<span style="color:#728e00">return</span> <span style="color:#8a7b52">3</span>;
}
<span style="color:#728e00">function</span> <span style="color:#728e00">doeStap2Met1</span>(<span style="color:#728e00">een</span>) {
<span style="color:#728e00">return</span> <span style="color:#728e00">een</span> <span style="color:#728e00">*</span> <span style="color:#8a7b52">2</span>;
}
<span style="color:#728e00">return</span> {
<span style="color:#728e00">doeStuff</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">return</span> <span style="color:#728e00">doeStap2Met1</span>(<span style="color:#728e00">doeStap1</span>());
}
}
})()
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">Stuff</span>); <span style="color:#95a5a6">// outputs Object met &#34;doeStuff&#34; key
</span><span style="color:#95a5a6"></span><span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">Stuff</span>.<span style="color:#728e00">doeStuff</span>()); <span style="color:#95a5a6">// 6
</span></code></pre></div><blockquote>
<p>In JavaScript, as opposed to statically scoped languages, all variables are scoped to the function in which they&rsquo;re defined (not the &ldquo;block&rdquo; as defined by curly braces). The above code snippet creates an anonymous function and immediately executes it. This has the effect of creating a scope in which variables can be defined, and anything in the containing scope is still accessible.</p>
</blockquote>
<p>Zie <a href="http://trephine.org/t/index.php?title=Aspect_Oriented_JavaScript">http://trephine.org/t/index.php?title=Aspect_Oriented_JavaScript</a></p>
<p>Wat gebeurt er?</p>
<ol>
<li>Wrap een lege functie in Stuff, waar x aantal functies in zitten die wat werk doen.</li>
<li>In plaats van dat toe te kennen aan Stuff, evalueer direct de nieuwe functie met <code>(function() { ... })()</code>. Wat terugkomt is een closure functie die <code>doeStuff</code> definieert, de rest is niet zichtbaar.</li>
</ol>
<p>#####= Expliciet objecten binden met call/apply #####=</p>
<p>Neem als voorbeeld terug de ezel. Die zal bij het balken &ldquo;iaia met mijn 4 poten&rdquo; op de console afdrukken. Zodra de balk functie aangeroepen wordt, <em>bind</em> Javascript de ezel aan het <code>this</code> keyword, zodat poten correct opgezocht kan worden. Stel nu dat ik een spin wil laten balken, zonder de spin de balk functie te laten refereren/mixen vanuit de ezel:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">Spin</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">poten</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">8</span>;
};
<span style="color:#728e00">var</span> <span style="color:#728e00">tarantula</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Spin</span>();
<span style="color:#728e00">new</span> <span style="color:#728e00">Ezel</span>().<span style="color:#728e00">balk</span>.<span style="color:#728e00">call</span>(<span style="color:#728e00">tarantula</span>); <span style="color:#95a5a6">// iaia met mijn 8 poten
</span></code></pre></div><p>Wat gebeurt hier?</p>
<ol>
<li>Ik maak een nieuw object aan met ook een poten property</li>
<li>balk gebruikt de poten property maar ik wil mijn spin gebruiken in plaats van de 4 poten van de ezel!</li>
<li>gebruik <code>call</code> om balk uit te voeren, en geef als argument mijn spin mee, zodat de balk functie gebind wordt op mijn spin in plaats van de nieuwe ezel instantie</li>
</ol>
<p>Het is ook mogelijk om zonder argument <code>call</code> uit te voeren:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">poten</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">100</span>;
<span style="color:#728e00">new</span> <span style="color:#728e00">Ezel</span>().<span style="color:#728e00">balk</span>.<span style="color:#728e00">call</span>(); <span style="color:#95a5a6">// iaia met mijn 100 poten
</span></code></pre></div><p>Hoezo 100? <code>this</code> wordt dan <code>window</code>, de hoogst mogelijke scope, en daar is net toevallig ook een poten variabele op gedefiniëerd. Als dat niet zo was gaf dit als output &ldquo;iaia met mijn undefined poten&rdquo;.</p>
<h5 id="impliciete-unbound-objecten">Impliciete unbound objecten</h5>
<p>Het vorige voorbeeld toont aan hoe je expliciet <code>this</code> kan &ldquo;unbinden&rdquo;. Dit gebeurt ook regelmatig intern impliciet, bijvoorbeeld met <code>setTimeout</code> of met events zoals <code>blabla.onclick</code>. <br/><br/>
De oplossing hiervoor is <strong>closures</strong> gebruiken. Bekijk dit voorbeeld:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">SomeClass</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">message</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;hallo&#34;</span>;
<span style="color:#728e00">this</span>.<span style="color:#728e00">startLooping</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">setInterval</span>(<span style="color:#728e00">this</span>.<span style="color:#728e00">doeBijInterval</span>, <span style="color:#8a7b52">1000</span>);
};
<span style="color:#728e00">this</span>.<span style="color:#728e00">doeBijInterval</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">this</span>.<span style="color:#728e00">message</span>); <span style="color:#95a5a6">// BOOOEEMM
</span><span style="color:#95a5a6"></span> }
}
<span style="color:#728e00">new</span> <span style="color:#728e00">SomeClass</span>().<span style="color:#728e00">startLooping</span>();
</code></pre></div><p>Wat loopt hier mis? ((Buiten het feit dat setInterval niet altijd mag uitgevoerd worden, er moet een guard clause rond, setInterval retourneert een id!))<br/><br/>
doeBijInterval wordt hier om de seconde uitgevoerd, en this.message wordt afgedrukt. <code>this</code> verwijst op dat moment <em>niet</em> meer naar de instantie van SomeClass!</p>
<p>De oplossing, een closure meegeven aan <code>setInterval</code> die kan werken op de instance:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">SomeClass</span>() {
<span style="color:#728e00">this</span>.<span style="color:#728e00">message</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;hallo&#34;</span>;
<span style="color:#728e00">this</span>.<span style="color:#728e00">startLooping</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">instance</span> <span style="color:#728e00">=</span> <span style="color:#728e00">this</span>; <span style="color:#95a5a6">// OK, SomeClass instance
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">setInterval</span>(<span style="color:#728e00">function</span>() {
<span style="color:#728e00">instance</span>.<span style="color:#728e00">doeBijInterval</span>(); <span style="color:#95a5a6">// this = window scope, gebruik de instance var.
</span><span style="color:#95a5a6"></span> }, <span style="color:#8a7b52">1000</span>);
};
<span style="color:#728e00">this</span>.<span style="color:#728e00">doeBijInterval</span> <span style="color:#728e00">=</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">this</span>.<span style="color:#728e00">message</span>); <span style="color:#95a5a6">// Da werkt ofwa
</span><span style="color:#95a5a6"></span> }
}
<span style="color:#728e00">new</span> <span style="color:#728e00">SomeClass</span>().<span style="color:#728e00">startLooping</span>();
</code></pre></div><h5 id="loop-closures">loop closures</h5>
<p>Een ander voorbeeld waar het mis kan gaan (ref. <a href="http://trephine.org/t/index.php?title=JavaScript_loop_closures">http://trephine.org/t/index.php?title=JavaScript_loop_closures</a> !):</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">list</span> <span style="color:#728e00">=</span> [ <span style="color:#7f8c8d">&#39;a&#39;</span>, <span style="color:#7f8c8d">&#39;b&#39;</span>, <span style="color:#7f8c8d">&#39;c&#39;</span> ];
<span style="color:#728e00">for</span> (<span style="color:#728e00">var</span> <span style="color:#728e00">i</span><span style="color:#a61717">######</span><span style="color:#8a7b52">0</span>, <span style="color:#728e00">llist</span>.<span style="color:#728e00">length</span>; <span style="color:#728e00">i</span><span style="color:#728e00">&lt;</span><span style="color:#728e00">l</span>; <span style="color:#728e00">i</span><span style="color:#728e00">++</span>) {
<span style="color:#728e00">var</span> <span style="color:#728e00">item</span> <span style="color:#728e00">=</span> <span style="color:#728e00">list</span>[<span style="color:#728e00">i</span>];
<span style="color:#728e00">setTimeout</span>( <span style="color:#728e00">function</span>(){ <span style="color:#728e00">alert</span>(<span style="color:#728e00">item</span>); }, <span style="color:#8a7b52">1000</span> ); <span style="color:#95a5a6">// print 3x &#39;c&#39;
</span><span style="color:#95a5a6"></span>}
</code></pre></div><p>Hoe kan dit 3x &lsquo;c&rsquo; afdrukken en niet &lsquo;a&rsquo;, &lsquo;b&rsquo;, &lsquo;c&rsquo;?</p>
<ol>
<li>In de lus ken ik aan item de huidige index van de array toe.</li>
<li>Voer een functie uit die een seconde in de toekomst uitegevoerd wordt. [NOG NIET]. Repeat lus tot klaar.</li>
</ol>
<p>Zodra de events verwerkt worden, is item reeds de laatste in de rij. Oei. De oplossing, weeral closures:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">list</span> <span style="color:#728e00">=</span> [ <span style="color:#7f8c8d">&#39;a&#39;</span>, <span style="color:#7f8c8d">&#39;b&#39;</span>, <span style="color:#7f8c8d">&#39;c&#39;</span> ];
<span style="color:#728e00">for</span> (<span style="color:#728e00">var</span> <span style="color:#728e00">i</span><span style="color:#a61717">######</span><span style="color:#8a7b52">0</span>, <span style="color:#728e00">llist</span>.<span style="color:#728e00">length</span>; <span style="color:#728e00">i</span><span style="color:#728e00">&lt;</span><span style="color:#728e00">l</span>; <span style="color:#728e00">i</span><span style="color:#728e00">++</span>) (<span style="color:#728e00">function</span>(<span style="color:#728e00">item</span>){
<span style="color:#728e00">setTimeout</span>( <span style="color:#728e00">function</span>(){ <span style="color:#728e00">alert</span>(<span style="color:#728e00">item</span>); }, <span style="color:#8a7b52">1000</span> );
})(<span style="color:#728e00">list</span>[<span style="color:#728e00">i</span>]);
</code></pre></div><p>Hier wordt een anonieme functie aangemaakt die <em>direct</em> geëvalueerd wordt met <code>list[i]</code> als parameter, zodat elke closure uniek gebonden is aan de juiste parameter.<br/><br/>
Zie AOP hieronder voor meer uitleg over anonieme functies.</p>
<p>#####= Samenvatting: module pattern #####=</p>
<p>Wanneer we alle bovenstaande technieken toepassen, krijgen we typisch in Javascript iets zoals dit:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">MyGlobalNewModule</span> <span style="color:#728e00">=</span> (<span style="color:#728e00">function</span>(<span style="color:#728e00">module</span>) {
<span style="color:#728e00">var</span> <span style="color:#728e00">privateVar</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">3</span>;
<span style="color:#728e00">function</span> <span style="color:#728e00">privateFn</span>() {
<span style="color:#728e00">privateVar</span> <span style="color:#728e00">+=</span> <span style="color:#8a7b52">3</span>;
}
<span style="color:#95a5a6">// decorate or use module here if wanted.
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">return</span> {
<span style="color:#728e00">publicProperty</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;hello&#34;</span>,
<span style="color:#728e00">publicFn</span><span style="color:#728e00">:</span> <span style="color:#728e00">function</span>() {
<span style="color:#728e00">return</span> <span style="color:#728e00">privateFn</span>() <span style="color:#728e00">-</span> <span style="color:#8a7b52">2</span>;
}
};
})(<span style="color:#728e00">GlobalModule</span>);
</code></pre></div><p>Wat zit hier in verwoven?</p>
<ol>
<li>private variables en functions zitten in de anonieme functie scope</li>
<li>andere modules zijn toegankelijk via een argument, en <em>niet</em> via de directe variabele</li>
<li>publieke functies worden <em>exposed</em> via een object dat teruggegeven wordt.</li>
</ol>
<p>Zo werken bijvoorbeeld de API en plugins van <strong>jQuery</strong>.</p>
<p>❗ Anonieme functies declareren en uitvoeren kan op twee manieren in JS: via <code>(function() { ... })()</code> en via <code>(function() { ... }())</code>. Merk het verschil in <strong>haakjes</strong> op. Het resultaat is exact hetzelfde, er is alleen een semantisch verschil, namelijk dat bij de eerste expressie de haakjes de <em>functie expressie</em> vasthoudt, en bij de tweede expressie de <em>call expressie</em> (het resultaat van de functie)</p>
<p>Zie <a href="http://stackoverflow.com/questions/3783007/is-there-a-difference-between-function-and-function">stackoverflow</a> voor meer uitleg - schematisch:</p>
<pre><code>
CallExpression
| |
FunctionExpression |
| |
V V
(function() { }());
^ ^
|--PrimaryExpression --|
</code></pre><p>VS</p>
<pre><code> PrimaryExpression
|
FunctionExpression
|
V
(function() { })();
^ ^
|-- CallExpression --|
</code></pre><h1 id="testing-js-code">Testing JS Code</h1>
<h2 id="testen-schrijven">Testen schrijven</h2>
<h3 id="klassieke-unit-testen">Klassieke Unit testen</h3>
<p>Frameworks gebruiken zoals jQuery&rsquo;s <a href="http://docs.jquery.com/Qunit">QUnit</a> die het makkelijk maken modulair te testen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">test</span>(<span style="color:#7f8c8d">&#34;dit zou dat moeten doen blabla&#34;</span>, <span style="color:#728e00">function</span>() {
<span style="color:#728e00">equal</span>(<span style="color:#728e00">expected</span>, <span style="color:#728e00">actual</span>);
<span style="color:#728e00">ok</span>(<span style="color:#728e00">someThingExpectedToBeTrue</span>);
});
</code></pre></div><p>Mocking van bijvoorbeeld <code>$</code> mogelijk via <a href="http://johanneslink.net/projects/mockme.html">MockMe</a>, een door Mockito geïnspireerde Javascript Object spy API. Iets van:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">when</span>(<span style="color:#728e00">f</span>)(<span style="color:#7f8c8d">&#39;in&#39;</span>).<span style="color:#728e00">thenReturn</span>(<span style="color:#7f8c8d">&#39;out&#39;</span>);
<span style="color:#728e00">assertEqual</span>(<span style="color:#7f8c8d">&#39;out&#39;</span>, <span style="color:#728e00">f</span>(<span style="color:#7f8c8d">&#39;in&#39;</span>));
</code></pre></div><p>❗ Vereist <code>Prototype JS</code>, en <code>JsUnit</code> om de <code>assert</code> functions te kunnen gebruiken</p>
<h3 id="gedrag-testen-met-jasmine">Gedrag testen met Jasmine</h3>
<p>Inspiratie van de <em>Ruby</em> community gehaald, met name <strong>RSpec</strong>-based.<br/><br/>
Frameworks gebruiken zoals <a href="http://pivotal.github.com/jasmine/">Jasmine</a> ((Niet afhankelijk van andere JS Frameworks, vereist geen DOM dus geen Envjs nodig serverside!)):</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">describe</span>(<span style="color:#7f8c8d">&#34;Rekenmasjien&#34;</span>, <span style="color:#728e00">function</span>() {
<span style="color:#728e00">it</span>(<span style="color:#7f8c8d">&#34;should add one number&#34;</span>, <span style="color:#728e00">function</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">calc</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Calc</span>(<span style="color:#8a7b52">0</span>);
<span style="color:#728e00">expect</span>(<span style="color:#728e00">calc</span>.<span style="color:#728e00">increase</span>()).<span style="color:#728e00">toEqual</span>(<span style="color:#8a7b52">1</span>);
});
});
</code></pre></div><p>Krachten:</p>
<ul>
<li>Schrijf code door <em>expectations</em> (<a href="https://github.com/pivotal/jasmine/wiki/Matchers">Matchers vbs</a>) op te bouwen, in dezelfde trand als <code>FESTAssert</code>.</li>
<li>Bundel expectations in een suite (&ldquo;beschrijvend&rdquo;)</li>
<li>Schrijf makkelijk extenties om eigen expectation functions op te bouwen als de standaard API niet volstaat</li>
<li><code>beforeEach()</code> en <code>afterEach()</code> functions binnen suites</li>
<li>Snel disablen van testen via <code>xit()</code> (<code>@Ignore</code> zogezegd)</li>
<li><strong>mocking</strong> en <strong>spying</strong> heel eenvoudig mogelijk: zie <a href="https://github.com/pivotal/jasmine/wiki/Spies">https://github.com/pivotal/jasmine/wiki/Spies</a></li>
<li>Plugins voor reporting, custom matching, &hellip;</li>
</ul>
<p>Zwakheden:</p>
<ul>
<li>Async testen vereist <code>waitsFor()</code> ea. Zie onder</li>
<li>Vereist specRunner.html files, standaard altijd in een browser runnen. <strong>Genereer specRunners</strong>!</li>
</ul>
<p>Betere matchers speciaal voor jQuery ea zijn beschikbaar: <a href="https://github.com/velesin/jasmine-jquery">https://github.com/velesin/jasmine-jquery</a></p>
<h5 id="aynschrone-code-testen">Aynschrone code testen</h5>
<p>Zie async stuff</p>
<h5 id="jasmine-integreren-met-jstestdriver">Jasmine integreren met jsTestDriver</h5>
<p>Zie <a href="http://skaug.no/ingvald/2010/10/javascript-unit-testing.html">http://skaug.no/ingvald/2010/10/javascript-unit-testing.html</a></p>
<p>Er is een <strong>Jasmine adapter</strong> beschikbaar: <a href="https://github.com/ibolmo/jasmine-jstd-adapter">https://github.com/ibolmo/jasmine-jstd-adapter</a></p>
<p>Het kan ook handig zijn om een <strong>Junit XML Reporter</strong> te gebruiken om bijvoorbeeld voor Hudson het makkelijker te maken om de test output files te verwerken. Er zijn reeds enkele reporter plugins zoals deze beschikbaar, hier: <a href="https://github.com/larrymyers/jasmine-reporters">https://github.com/larrymyers/jasmine-reporters</a></p>
<p>❗ Integratie met Hudson, EnvJS en Rhino ea: zie eigen junit test runner: <a href="https://github.com/wgroeneveld/jasmine-junit-runner">https://github.com/wgroeneveld/jasmine-junit-runner</a></p>
<h3 id="andere-js-test-frameworks">Andere JS Test frameworks</h3>
<p>Interessante links:</p>
<ol>
<li><a href="http://tddjs.com/">http://tddjs.com/</a></li>
<li><a href="http://stackoverflow.com/questions/300855/looking-for-a-better-javascript-unit-test-tool">Stack overflow: Looking for a better Javascript unit test tool</a></li>
<li></li>
</ol>
<h2 id="testen-automatiseren">Testen automatiseren</h2>
<h3 id="distributed-testing-in-browser">Distributed testing in-browser</h3>
<h4 id="jstestdriver">jsTestDriver</h4>
<p><a href="http://code.google.com/p/js-test-driver/">http://code.google.com/p/js-test-driver/</a></p>
<p>Wat doet dit?</p>
<ul>
<li>Een jar dat een <strong>server</strong> opstart die een browser bestuurt en bepaalde <strong>JS</strong> files (uw testen en uw productiecode) automatisch inlaadt en uitvoert</li>
<li>Bevat een API met asserts</li>
<li>Reportgeneratie met plugins voor eclipse om ze JUnit-like te tonen</li>
<li>Integratie met build etc mogelijk</li>
<li>Integratie met Jasmine mogelijk: <a href="https://github.com/ibolmo/jasmine-jstd-adapter">https://github.com/ibolmo/jasmine-jstd-adapter</a></li>
</ul>
<p><strong>jsTestDriver integreren met Hudson</strong></p>
<p>Zie <a href="http://cjohansen.no/en/javascript/javascript_continuous_integration_with_hudson_and_jstestdriver">http://cjohansen.no/en/javascript/javascript_continuous_integration_with_hudson_and_jstestdriver</a></p>
<p>Het komt eigenlijk hierop neer: maak een nieuw target, voer extern dit commando uit:</p>
<pre><code>java -jar test/JsTestDriver-1.2.2.jar &lt;br/&gt;
--config jsTestDriver.conf &lt;br/&gt;
--server http://localhost:4223
--tests all --testOutput . --reset
</code></pre><p>Dit neemt aan dat de server reeds gestart is, kan met een shell script op de Hudson server bak: <code>java -jar test/JsTestDriver-1.2.2.jar --port 4223</code>.</p>
<h4 id="jsunit-server">JsUnit Server</h4>
<p><a href="http://www.jsunit.net/documentation/index.html">http://www.jsunit.net/documentation/index.html</a></p>
<p>Wat doet dit?</p>
<ul>
<li>Een jar dat een <strong>Jetty Server</strong> opstart die een browser bestuurt en bepaalde <strong>HTML</strong> files inlaadt en uitvoert, waar testen in zitten</li>
<li>Afhankelijk van <code>Prototype JS</code> om asserts uit te voeren</li>
<li>Integratie met ant zeer eenvoudig</li>
</ul>
<h4 id="testswarm">TestSwarm</h4>
<p>Zie http:*swarm.jquery.org/ en https:*github.com/jquery/testswarm/wiki</p>
<h3 id="headless-testen">Headless testen</h3>
<h4 id="mogelijkheid-1-envjs">Mogelijkheid 1: EnvJS</h4>
<p><em>EnvJS</em> is een <em>gesimuleerde</em> browser omgeving geschreven in JS. Zie <a href="http://www.envjs.com/">http://www.envjs.com/</a></p>
<p><strong>Voordeel</strong>: heel snel</p>
<p><strong>Nadeel</strong>: <code>Java</code> ofzoiets nodig om JS te evalueren (<strong>Rhino</strong> of <strong>V8</strong> in C++ van Google), plus kan onregelmatigheden vertonen met hevig gebruik maken van UI frameworks -&gt; dit zou moeten werken allemaal, maar het blijft een gesimuleerde omgeving.</p>
<p>❗ Zie <a href="https://github.com/wgroeneveld/jasmine-junit-runner">https://github.com/wgroeneveld/jasmine-junit-runner</a></p>
<p>Integreren met hudson als extern commando:</p>
<pre><code>java -cp lib/envjs/js.jar:lib/envjs/jline.jar org.mozilla.javascript.tools.shell.Main -opt -1 -f lib/envjs/envjs.bootstrap.js -f test.js
</code></pre><p><code>test.js</code> heeft dan maar 1 regel die naar de juiste specRunner.html gaat met <code>window.location</code>.</p>
<h4 id="mogelijkheid-2-qt-webkit-widget">Mogelijkheid 2: Qt Webkit widget</h4>
<p><em>Webkit</em> is een opensource web renderer, en er is een implementatie in <code>Qt</code> beschikbaar (vereist libs geïnstalleerd te hebben). Zie <a href="http://trac.webkit.org/wiki/QtWebKit">http://trac.webkit.org/wiki/QtWebKit</a></p>
<p><strong>Voordeel</strong>: gedrag volledig in een &ldquo;echte&rdquo; website rendered, in plaats van via een omweg. Aangezien het een Qt Widget is, hoeft het niet expliciet op het scherm gerendered te worden (dit pollt gewoon totdat bvb <em>&ldquo;Jasmine tests run&rdquo;</em> ofzoiets van tekst verschijnt, om dan de HTML te retourneren als resultaat.</p>
<p><strong>Nadeel</strong>: Qt libs vereist, nog altijd niet volledig &ldquo;headless&rdquo;, aparte widget spec runner in de achtergrond die draait.</p>
<p>Zie <a href="http://johnbintz.github.com/jasmine-headless-webkit/">http://johnbintz.github.com/jasmine-headless-webkit/</a> (Implementatie in Ruby met nogal veel nadruk op gems ea&hellip; Handig?)</p>
<p><a href="http://www.phantomjs.org/">Phantom JS</a> is een full stack headless browser implementatie gebaseerd op WebKit (C++/Python implementatie).</p>
<h1 id="pitfalls">Pitfalls</h1>
<p>❗ Gebruik aub <strong><a href="http://www.jslint.com">JSLint</a></strong> om onderstaande &ldquo;probleempjes&rdquo; makkelijker te kunnen tracen en aanpassen.</p>
<p><a href="https://developer.mozilla.org/en/JavaScript/Strict_mode">Strict mode</a> in ECMA5 is ook iets héél handig.</p>
<p>-&gt; Meer (al dan niet grappige) pitfalls/weetjes: <a href="http://www.wtfjs.com/">http://www.wtfjs.com/</a></p>
<h3 id="objecten">Objecten</h3>
<p>Javascript gebruikt intern de <code>toString()</code> functie wanneer objecten als keys worden toegekend. Dit wil zeggen dat eigenlijk de string representatie als key gebruikt wordt. Bijvoorbeeld:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">obj</span> <span style="color:#728e00">=</span> {};
<span style="color:#728e00">var</span> <span style="color:#728e00">key1</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Object</span>();
<span style="color:#728e00">var</span> <span style="color:#728e00">key2</span> <span style="color:#728e00">=</span> <span style="color:#728e00">new</span> <span style="color:#728e00">Object</span>();
<span style="color:#728e00">obj</span>[<span style="color:#728e00">key1</span>] <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;hi&#34;</span>;
<span style="color:#728e00">obj</span>[<span style="color:#728e00">key2</span>] <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;yo&#34;</span>;
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">obj</span>[<span style="color:#728e00">key1</span>]); <span style="color:#95a5a6">// ##### yo???
</span></code></pre></div><p>#####= arguments #####=</p>
<h5 id="arguments-on-the-fly-veranderen">arguments on-the-fly veranderen</h5>
<p>Zonder <code>use strict</code> (ES5) kan je een binnenkomend argument ook toekennen aan een andere waarde. Hierdoor verandert de waarde van <code>arguments[0]</code>! De <code>arguments</code> lijst houdt dus een pointer bij naar de variabele die de value van het argument vasthoudt, en niet naar de value zelf. In strict mode wel. Voorbeeld:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">bla</span>(<span style="color:#728e00">a</span>) {
<span style="color:#728e00">a</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">5</span>;
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">arguments</span>[<span style="color:#8a7b52">0</span>]);
}
<span style="color:#728e00">bla</span>(<span style="color:#8a7b52">1</span>); <span style="color:#95a5a6">// 5, in strict mode 1
</span></code></pre></div><h5 id="arguments-is-geen-array">arguments is geen array</h5>
<p>Snel &ldquo;effe&rdquo; lopen over alle argumentjes:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">aha</span>() {
<span style="color:#728e00">arguments</span>.<span style="color:#728e00">forEach</span>(<span style="color:#728e00">function</span>(<span style="color:#728e00">itm</span>) { <span style="color:#95a5a6">// syntax error ???
</span><span style="color:#95a5a6"></span> <span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">itm</span>);
});
}
<span style="color:#728e00">aha</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">2</span>, <span style="color:#8a7b52">3</span>);
</code></pre></div><p>Inderdaad: <code>Array.isPrototypeOf(arguments) ##### false</code>. Dus de <code>.length</code> property werkt op een andere manier, en van die hidden <code>.callee</code> dingen (die niet werken in strict mode) zitten er ook op&hellip;</p>
<p>Oplossing:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">aha</span>() {
<span style="color:#728e00">var</span> <span style="color:#728e00">args</span> <span style="color:#728e00">=</span> <span style="color:#728e00">Array</span>.<span style="color:#728e00">prototype</span>.<span style="color:#728e00">slice</span>.<span style="color:#728e00">call</span>(<span style="color:#728e00">arguments</span>);
<span style="color:#728e00">args</span>.<span style="color:#728e00">forEach</span>(<span style="color:#728e00">function</span>(<span style="color:#728e00">itm</span>) {
<span style="color:#728e00">console</span>.<span style="color:#728e00">log</span>(<span style="color:#728e00">itm</span>);
});
}
<span style="color:#728e00">aha</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">2</span>, <span style="color:#8a7b52">3</span>);
</code></pre></div><p>#####= Falsey values #####=</p>
<p>De volgende values evalueren allemaal naar <code>false</code> in bvb een <code>if()</code> block:</p>
<ol>
<li><code>null</code></li>
<li><code>0</code> als <code>number</code></li>
<li><code>&quot;&quot;</code> als <code>string</code></li>
<li><code>false</code> als <code>boolean</code></li>
<li><code>undefined</code></li>
<li><code>NaN</code></li>
</ol>
<p>Deze dingen lukken ook niet:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">if</span>(<span style="color:#728e00">new</span> <span style="color:#728e00">Boolean</span>(<span style="color:#00979d">false</span>)) {
<span style="color:#728e00">alert</span>(<span style="color:#7f8c8d">&#34;ik ben false jong!&#34;</span>); <span style="color:#95a5a6">// oei tis nie waar hé?
</span><span style="color:#95a5a6"></span>}
</code></pre></div><p>Mogelijke Oplossingen:</p>
<ol>
<li>gebruik altijd <code>.valueOf()</code> van de object counterparts van alle primitives!</li>
<li>gebruik <code>Boolean(false)</code> (zonder new), zie <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Boolean">Mozilla Boolean Dev docs</a></li>
</ol>
<p>Lees hier meer over in <a href="http:*javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/">The secret life of Javascript Primitives</a> en <a href="http:*javascriptweblog.wordpress.com/2010/05/03/the-value-of-valueof/">the value of valueOf</a>.</p>
<p>#####= Typecasting #####=</p>
<p>^ code ^ resultaat ^
| [] + 23 | de string &ldquo;23&rdquo; |
| [1, 2] + 23 | de string &ldquo;1, 223&rdquo; |
| false + 23 | het getal 23 |
| true + 23 | het getal 24 |
| &ldquo;kadootje&rdquo; + 23 | de string &ldquo;kadootje23&rdquo; |
| undefined + 23 | NaN |
| null + 23 | het getal 23 |</p>
<p>#####= Parsing #####=</p>
<p><code>parseInt(&quot;08&quot;)</code> neemt automatisch aan dat de waarde naar octal values omgezet moet worden. Dit evalueert naar het getal <code>0</code>.<br/><br/>
Oplossing: <code>parseInt(&quot;08&quot;, 10)</code> - het tweede argument geeft de eenheid aan (10 = decimaal).</p>
<p>#####= de wereld breken (undefined) #####=</p>
<p><code>undefined</code> is een toplevel variabele die als value de primitive value <code>undefined</code> heeft. <br/><br/>
Zodra je <code>undefined</code> (de variabele) toekent aan iets anders, is die primitive value weg en is alles naar de zak. Voorbeeld:</p>
<p>Dit is opgelost in ECMA5 door sommige properties al dan niet writable te maken. <code>undefined</code> is daar dus readonly. Check dit in Firefox 4:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">undefinedProps</span> <span style="color:#728e00">=</span> <span style="color:#728e00">Object</span>.<span style="color:#728e00">getOwnPropertyDescriptor</span>(<span style="color:#728e00">window</span>, <span style="color:#7f8c8d">&#34;undefined&#34;</span>)
<span style="color:#728e00">undefinedProps</span>.<span style="color:#728e00">writable</span> <span style="color:#a61717">#####</span> <span style="color:#00979d">false</span>; <span style="color:#95a5a6">// locked down!
</span></code></pre></div><p>#####= Javascript en puntkomma&rsquo;s #####=</p>
<p>Geen enkele lijn hoeft een <code>;</code> te bevatten, javascript voegt deze automatisch toe bij het evalueren. Dit kan ook miserie veroorzaken:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">function</span> <span style="color:#728e00">geefIets</span>() {
<span style="color:#728e00">return</span>
{
<span style="color:#728e00">iets</span><span style="color:#728e00">:</span> <span style="color:#7f8c8d">&#34;wow&#34;</span>
};
}
<span style="color:#728e00">geefIets</span>(); <span style="color:#95a5a6">// undefined: unreachable code!
</span></code></pre></div><p>Los dit op door de accolade na de return te plaatsen in plaats van de newline.</p>
<p>#####= ECMA5: map, forEach, filter: de 3 parameters #####=</p>
<p>Sinds ECMA5 is het héél handig om bijvoorbeeld voor een array van strings elk element individueel te manipuleren en een nieuwe array terug te geven.<br/><br/>
Stel, ik wil <code>string</code>s naar <code>number</code>s omvormen:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript">[<span style="color:#7f8c8d">&#34;1&#34;</span>, <span style="color:#7f8c8d">&#34;2&#34;</span>, <span style="color:#7f8c8d">&#34;3&#34;</span>].<span style="color:#728e00">map</span>(<span style="color:#728e00">parseInt</span>); <span style="color:#95a5a6">// returns [1, NaN, NaN ] ???
</span></code></pre></div><p>Whoops? <code>parseInt</code> heeft als tweede variabele de eenheid (decimaal, hexa, &hellip;) en alle array manipulatie functies geven altijd 3 argumenten mee: het element, de index en de array zelf. Conflict!</p>
<p>Oplossing: closures!</p>
<p>#####= Arrays zijn &ldquo;speciale&rdquo; associatieve objecten #####=</p>
<p>Dit zegt de [http:*bclary.com/2004/11/07/#a-15.4ECMAScript specificatie](http:*bclary.com/2004/11/07/#a-15.4ECMAScript specificatie):</p>
<blockquote>
<p>Array objects give special treatment to a certain class of property names. A property name P (in the form of a string value) is an array index if and only if <strong>ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 2^32 - 1</strong>. Every Array object has a length property whose value is always a nonnegative integer less than 2^32. The value of the length property is numerically greater than the name of every property whose name is an array index; whenever a property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant. Specifically, whenever a property is added whose name is an array index, the length property is changed, if necessary, to be one more than the numeric value of that array index; and whenever the length property is changed, every property whose name is an array index whose value is not smaller than the new length is automatically deleted. This constraint applies only to properties of the Array object itself and is unaffected by length or array index properties that may be inherited from its prototype.</p>
</blockquote>
<p>Dat wil zeggen dat:</p>
<ol>
<li>zodra de <code>.length</code> property gewijzigd wordt, er verschillende dingen gebeuren:
1. Indien kleiner wordt: alle properties kleiner dan de lengte worden automatisch verwijderd
2. Indien groter wordt: allemaal nieuwe elementen met <code>undefined</code> als value (<em>impliciet</em>!)</li>
<li>Alle &ldquo;integer&rdquo; values (zie geweldige formule) zijn &ldquo;speciale&rdquo; properties die de <code>length</code> property ook aanpassen.</li>
</ol>
<p>Wat gebeurt er als ik de <code>length</code> property boven het maximum zet?</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#728e00">var</span> <span style="color:#728e00">arr</span> <span style="color:#728e00">=</span> [<span style="color:#8a7b52">1</span>];
<span style="color:#728e00">arr</span>.<span style="color:#728e00">length</span> <span style="color:#728e00">=</span> <span style="color:#728e00">Math</span>.<span style="color:#728e00">pow</span>(<span style="color:#8a7b52">2</span>, <span style="color:#8a7b52">32</span>) <span style="color:#728e00">-</span> <span style="color:#8a7b52">1</span>; <span style="color:#95a5a6">// max allowed
</span><span style="color:#95a5a6"></span><span style="color:#728e00">arr</span>.<span style="color:#728e00">length</span><span style="color:#728e00">++</span>; <span style="color:#95a5a6">// RangeError: invalid array length (na lang denken van de parser)
</span></code></pre></div><p>❗ de <code>length</code> property wordt gebruikt door utility functies zoals <code>push</code>, <code>concat</code> etc, dus als deze niet correct werkt zoals hierboven beschreven gebeuren en vreemde dingen!</p>
<p>Meer info: zie <a href="http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/">How to subclass an Array</a></p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>Python Class structure basics</title>
<link>https://brainbaking.com/post/2013/10/python-basics/</link>
<comments>https://brainbaking.com/post/2013/10/python-basics/#commento</comments>
<pubDate>Tue, 01 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/python-basics/</guid>
<category domain="https://brainbaking.com/tags/python">python</category>
<category domain="https://brainbaking.com/tags/ruby">ruby</category>
<category domain="https://brainbaking.com/tags/classes">classes</category>
<description>
<![CDATA[
<p>Handy links:</p>
<ul>
<li><a href="http://www.diveintopython.net/object_oriented_framework/special_class_methods2.html">special class methods like _ <em>getattr</em> _ and _ <em>new</em> _</a></li>
<li><a href="http://www.diveintopython3.net/native-datatypes.html#tuples">dive into python - native datatypes</a></li>
<li><a href="http://python-history.blogspot.be/2010/06/inside-story-on-new-style-classes.html">Inside story on new style classes</a> - ter info: Python3 heeft <strong>enkel</strong> &ldquo;newstyle&rdquo; classes!</li>
</ul>
<h3 id="method-overriding">Method overriding</h3>
<p>Is <strong>niet mogelijk</strong>. Gebruik default values!</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#728e00">def</span> <span style="color:#d35400">func</span>(<span style="color:#434f54">i</span>, <span style="color:#434f54">j</span> <span style="color:#728e00">=</span> <span style="color:#8a7b52">2</span>, <span style="color:#434f54">k</span> <span style="color:#8a7b52">3</span>):
<span style="color:#728e00">return</span> <span style="color:#434f54">i</span> <span style="color:#728e00">+</span> <span style="color:#434f54">j</span> <span style="color:#728e00">+</span> <span style="color:#434f54">k</span>
<span style="color:#434f54">func</span>(<span style="color:#8a7b52">1</span>) <span style="color:#95a5a6"># 6</span>
<span style="color:#434f54">func</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">1</span>) <span style="color:#95a5a6"># 5</span>
<span style="color:#434f54">func</span>(<span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">1</span>, <span style="color:#8a7b52">1</span>) <span style="color:#95a5a6"># 3</span>
</code></pre></div><p>Wat wel gaat, evt met decorators, zie <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=101605">Five-minute multimethods in Python</a> - is <code>__call__</code> implementeren en dan met metaprogrammeren te loopen over alle methods en te kijken of de argumenten overeen komen met het type dat required is. Fancypancy!</p>
<h5 id="opgelet-met-pitfalls">Opgelet met pitfalls</h5>
<p><strong>Nummer 1</strong>: default variables worden herbruikt:</p>
<blockquote>
<p>When Python executes a “def” statement, it takes some ready-made pieces (including the compiled code for the function body and the current namespace), and creates a new function object. When it does this, it also evaluates the default values. [&hellip;] Another way to reset the defaults is to simply re-execute the same “def” statement. Python will then create a new binding to the code object, evaluate the defaults, and assign the function object to the same variable as before. But again, only do that if you know exactly what youre doing.</p>
</blockquote>
<p>Default als <code>arr = []</code> Gaat de array muteren. Heel handig voor memoization, heel verwarrend anders. Oplossing? <code>arr None</code> en dan <code>arr = [] if arr is None</code>.</p>
<p>Zie ook <a href="http://effbot.org/zone/default-values.htm">Default parameter values in Python</a> voor in-depth uitleg.</p>
<p><strong>Nummer 2</strong>: <em>Pythons nested scopes bind to variables, not object values</em>.</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#728e00">for</span> <span style="color:#434f54">i</span> <span style="color:#728e00">in</span> <span style="color:#728e00">range</span>(<span style="color:#8a7b52">10</span>):
<span style="color:#728e00">def</span> <span style="color:#d35400">callback</span>():
<span style="color:#728e00">print</span> <span style="color:#7f8c8d">&#34;clicked button&#34;</span>, <span style="color:#434f54">i</span>
<span style="color:#434f54">UI</span><span style="color:#728e00">.</span><span style="color:#434f54">Button</span>(<span style="color:#7f8c8d">&#34;button </span><span style="color:#7f8c8d">%s</span><span style="color:#7f8c8d">&#34;</span> <span style="color:#728e00">%</span> <span style="color:#434f54">i</span>, <span style="color:#434f54">callback</span>)
</code></pre></div><p>variabele <code>i</code> gaat altijd 9 zijn - wordt niet op value gebind. Oplossing is explicit binding door de functie definitie van <code>callback():</code> te veranderen naar <code>callback(i=i):</code>.</p>
<h3 id="fields-dynamisch-definiëren">Fields dynamisch definiëren</h3>
<p><code>Thing(a=1, b2)</code> kan op een paar manieren gedefiniëerd worden.</p>
<h5 id="fields-expliciet-declareren">fields expliciet declareren</h5>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#728e00">class</span> <span style="color:#434f54">Thing</span>:
<span style="color:#728e00">def</span> <span style="color:#434f54">__init__</span>(<span style="color:#434f54">self</span>, <span style="color:#434f54">a</span>, <span style="color:#434f54">b</span>):
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">a</span>, <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">b</span> <span style="color:#728e00">=</span> <span style="color:#434f54">a</span>, <span style="color:#434f54">b</span>
</code></pre></div><h5 id="dynamisch-uw-eigen-dictionary-updaten">dynamisch uw eigen dictionary updaten</h5>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#728e00">class</span> <span style="color:#434f54">Thing</span>:
<span style="color:#728e00">def</span> <span style="color:#434f54">__init__</span>(<span style="color:#434f54">self</span>, <span style="color:#728e00">**</span><span style="color:#434f54">kwargs</span>):
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">__dict__</span><span style="color:#728e00">.</span><span style="color:#434f54">update</span>(<span style="color:#434f54">kwargs</span>)
</code></pre></div><p>❗ Dit is uiteraard heel gevaarlijk aangezien het al uw method bodies kan vervangen door een param value. BOEM.</p>
<p><code>* *name</code>(zonder spatie, wiki markup, nvdr) geeft alle argumenten in een <a href="http://docs.python.org/2/library/stdtypes.html#typesmapping">dict</a> terug. <code>*name</code> gaat ook, geeft u een lijst van argumenten terug. Combinatie gaat ook, één ster moet voor de tweede komen. Zoiets is dus mogelijk: <code>def _ _init_ _(self, arg1, arg2, *allargs, * *allargsasdict)</code>.</p>
<h5 id="alles-als-een-message-passing-systeem-zien">Alles als een message passing systeem zien</h5>
<p>In Ruby is er een andere manier om <code>def name block end</code> te schrijven, hoe het geïnterpreteerd wordt: <code>self.class.send(:name, args) { block }</code></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#728e00">def</span> <span style="color:#d35400">opt_to_s</span> <span style="color:#434f54">opt</span><span style="color:#728e00">=</span>{}
<span style="color:#434f54">opt</span><span style="color:#728e00">.</span><span style="color:#434f54">empty?</span> ? <span style="color:#7f8c8d">&#39;&#39;</span> : <span style="color:#7f8c8d">&#39; &#39;</span> <span style="color:#728e00">+</span> <span style="color:#434f54">opt</span><span style="color:#728e00">.</span><span style="color:#434f54">map</span> {<span style="color:#728e00">|</span><span style="color:#434f54">e</span>,<span style="color:#434f54">v</span><span style="color:#728e00">|</span> <span style="color:#7f8c8d">&#34;</span><span style="color:#7f8c8d">#{</span><span style="color:#434f54">e</span><span style="color:#7f8c8d">}</span><span style="color:#7f8c8d">=&lt;br/&gt;&#34;</span><span style="color:#95a5a6">#{v}&lt;br/&gt;&#34;&#34;}.join(&#39;, &#39;)</span>
<span style="color:#728e00">end</span>
<span style="color:#728e00">[</span><span style="color:#7f8c8d">:html</span>, <span style="color:#7f8c8d">:body</span>, <span style="color:#7f8c8d">:h1</span><span style="color:#728e00">].</span><span style="color:#434f54">each</span> <span style="color:#728e00">do</span> <span style="color:#728e00">|</span><span style="color:#434f54">el</span><span style="color:#728e00">|</span>
<span style="color:#434f54">start</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;&lt;</span><span style="color:#7f8c8d">#{</span><span style="color:#434f54">el</span><span style="color:#7f8c8d">}</span><span style="color:#7f8c8d">&#34;</span>
<span style="color:#434f54">fin</span><span style="color:#728e00">=</span><span style="color:#7f8c8d">&#34;&lt;/</span><span style="color:#7f8c8d">#{</span><span style="color:#434f54">el</span><span style="color:#7f8c8d">}</span><span style="color:#7f8c8d">&gt;&#34;</span>
<span style="color:#728e00">self</span><span style="color:#728e00">.</span><span style="color:#434f54">class</span><span style="color:#728e00">.</span><span style="color:#434f54">send</span>(<span style="color:#7f8c8d">:define_method</span>, <span style="color:#434f54">el</span>) {<span style="color:#728e00">|</span><span style="color:#434f54">options</span><span style="color:#728e00">=</span>{}, <span style="color:#728e00">&amp;</span><span style="color:#434f54">blk</span><span style="color:#728e00">|</span> <span style="color:#434f54">start</span> <span style="color:#728e00">+</span> <span style="color:#434f54">opt_to_s</span>(<span style="color:#434f54">options</span>) <span style="color:#728e00">+</span> <span style="color:#7f8c8d">&#39;&gt;&#39;</span> <span style="color:#728e00">+</span> <span style="color:#434f54">blk</span><span style="color:#728e00">.</span><span style="color:#434f54">call</span> <span style="color:#728e00">+</span> <span style="color:#434f54">fin</span>}
<span style="color:#728e00">end</span>
<span style="color:#95a5a6"># Now, we can neatly nest tags and content</span>
<span style="color:#434f54">html</span> <span style="color:#728e00">do</span>
<span style="color:#434f54">body</span> <span style="color:#728e00">do</span>
<span style="color:#434f54">h1</span> <span style="color:#7f8c8d">:class</span><span style="color:#728e00">=&gt;</span><span style="color:#7f8c8d">&#34;bold-h1&#34;</span>, <span style="color:#7f8c8d">:id</span><span style="color:#728e00">&gt;</span><span style="color:#7f8c8d">&#34;h1_99&#34;</span> <span style="color:#728e00">do</span>
<span style="color:#7f8c8d">&#34;header&#34;</span>
<span style="color:#728e00">end</span>
<span style="color:#728e00">end</span>
<span style="color:#728e00">end</span>
<span style="color:#728e00">=&gt;</span> <span style="color:#7f8c8d">&#34;&lt;body&gt;&lt;h1 class&lt;br/&gt;&#34;</span><span style="color:#434f54">bold</span><span style="color:#728e00">-</span><span style="color:#434f54">h1</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">br</span><span style="color:#728e00">/&gt;</span><span style="color:#7f8c8d">&#34;, id=&lt;br/&gt;&#34;</span><span style="color:#434f54">h1_99</span><span style="color:#728e00">&lt;</span><span style="color:#434f54">br</span><span style="color:#728e00">/&gt;</span><span style="color:#7f8c8d">&#34;&gt;header&lt;/h1&gt;&lt;/body&gt;&#34;</span>
</code></pre></div><p>Voilà, een DSL in no-time. Holy crap. <a href="http://rubylearning.com/blog/2010/11/03/do-you-understand-rubys-objects-messages-and-blocks/">Bron: do you understand ruby&rsquo;s objects messages and blocks?</a></p>
<h3 id="superclassing">Superclassing</h3>
<p>Klassen aanmaken is niet al te moeilijk, maar een call uitvoeren naar de overridden method is iets minder evident: zie <a href="http://docs.python.org/2/library/functions.html#super">super() in python docs</a></p>
<p>Een voorbeeld van een custom http handler:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#728e00">class</span> <span style="color:#434f54">HttpHandler</span>(<span style="color:#434f54">SimpleHTTPRequestHandler</span>):
<span style="color:#728e00">def</span> <span style="color:#d35400">readStatus</span>(<span style="color:#434f54">self</span>):
<span style="color:#728e00">return</span> {
<span style="color:#7f8c8d">&#34;Status&#34;</span>: <span style="color:#7f8c8d">&#34;blabla&#34;</span>,
<span style="color:#7f8c8d">&#34;StartTime&#34;</span>: <span style="color:#7f8c8d">&#34;&#34;</span>
}
<span style="color:#728e00">def</span> <span style="color:#d35400">do_GET</span>(<span style="color:#434f54">self</span>):
<span style="color:#728e00">try</span>:
<span style="color:#728e00">print</span>(<span style="color:#7f8c8d">&#39;serving </span><span style="color:#7f8c8d">%s</span><span style="color:#7f8c8d"> now&#39;</span> <span style="color:#728e00">%</span> <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">path</span>)
<span style="color:#728e00">if</span> <span style="color:#7f8c8d">&#34;status.json&#34;</span> <span style="color:#728e00">in</span> <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">path</span>:
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">send_response</span>(<span style="color:#8a7b52">200</span>)
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">send_header</span>(<span style="color:#7f8c8d">&#39;Content-type&#39;</span>, <span style="color:#7f8c8d">&#39;text/json&#39;</span>)
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">end_headers</span>()
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">wfile</span><span style="color:#728e00">.</span><span style="color:#434f54">write</span>(<span style="color:#434f54">json</span><span style="color:#728e00">.</span><span style="color:#434f54">dumps</span>(<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">readStatus</span>())<span style="color:#728e00">.</span><span style="color:#434f54">encode</span>())
<span style="color:#728e00">else</span>:
<span style="color:#434f54">SimpleHTTPRequestHandler</span><span style="color:#728e00">.</span><span style="color:#434f54">do_GET</span>(<span style="color:#434f54">self</span>)
<span style="color:#728e00">except</span> <span style="color:#434f54">IOError</span>:
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">send_error</span>(<span style="color:#8a7b52">500</span>, <span style="color:#7f8c8d">&#39;internal server error in server python source: </span><span style="color:#7f8c8d">%s</span><span style="color:#7f8c8d">&#39;</span> <span style="color:#728e00">%</span> <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">path</span>)
</code></pre></div><p>Wat is hier speciaal aan:</p>
<ul>
<li><code>super.do_GET(self)</code> =&gt; <code>SimpleHTTPRequestHandler.do_GET(self)</code></li>
<li>eigen method aanroepen: <code>self.readStatus()</code> met de <code>self</code> prefix</li>
</ul>
<h4 id="diamond-inheritance">Diamond inheritance</h4>
<p><code>BaseClass.method()</code> is impliciet hetzelfde als <code>super().method()</code>, behalve dat je met <code>super</code> een argument kan meegeven, over welke superklasse het gaat.</p>
<p>Zie ook <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=236275">Things to know about Python&rsquo;s super()</a></p>
<h3 id="closures-en-lambdas">Closures en lambda&rsquo;s</h3>
<p>functies in functies aanmaken werkt perfect, &ldquo;closed over&rdquo; die lexicale scope, net zoals je zou verwachten zoals bijvoorbeeld in javascript:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"> <span style="color:#728e00">def</span> <span style="color:#d35400">readBuildStatus</span>(<span style="color:#434f54">self</span>):
<span style="color:#434f54">html</span> <span style="color:#728e00">=</span> <span style="color:#434f54">urllib</span><span style="color:#728e00">.</span><span style="color:#434f54">request</span><span style="color:#728e00">.</span><span style="color:#434f54">urlopen</span>(<span style="color:#7f8c8d">&#34;http://bla/lastbuildstatus.htm&#34;</span>)<span style="color:#728e00">.</span><span style="color:#434f54">read</span>()<span style="color:#728e00">.</span><span style="color:#434f54">decode</span>()
<span style="color:#728e00">def</span> <span style="color:#d35400">extractVersion</span>():
<span style="color:#434f54">versionString</span> <span style="color:#728e00">=</span> <span style="color:#7f8c8d">&#34;Version: &#34;</span>
<span style="color:#434f54">versionIndex</span> <span style="color:#728e00">=</span> <span style="color:#434f54">html</span><span style="color:#728e00">.</span><span style="color:#434f54">find</span>(<span style="color:#7f8c8d">&#34;Version: &#34;</span>)
<span style="color:#728e00">return</span> <span style="color:#434f54">html</span>[<span style="color:#434f54">versionIndex</span> <span style="color:#728e00">+</span> <span style="color:#728e00">len</span>(<span style="color:#434f54">versionString</span>) : <span style="color:#434f54">versionIndex</span> <span style="color:#728e00">+</span> <span style="color:#728e00">len</span>(<span style="color:#434f54">versionString</span>) <span style="color:#728e00">+</span> <span style="color:#728e00">len</span>(<span style="color:#7f8c8d">&#34;YYYY.MM&#34;</span>)]
<span style="color:#728e00">def</span> <span style="color:#d35400">extractStatus</span>():
<span style="color:#728e00">return</span> <span style="color:#7f8c8d">&#34;Succeeded&#34;</span> <span style="color:#728e00">if</span> <span style="color:#434f54">html</span><span style="color:#728e00">.</span><span style="color:#434f54">find</span>(<span style="color:#7f8c8d">&#34;SUCCESS&#34;</span>) <span style="color:#728e00">!=</span> <span style="color:#728e00">-</span><span style="color:#8a7b52">1</span> <span style="color:#728e00">else</span> <span style="color:#7f8c8d">&#34;Failed&#34;</span>
</code></pre></div><p>de twee andere methods lezen de <code>html</code> variabele uit. Hier hoef je geen <code>self.</code> prefix te gebruiken, binnen de <code>readBuildStatus()</code> functie zelf - hierbuiten zijn de closures verdwenen natuurlijk (out of scope).</p>
<h2 id="unittest-module">unittest module</h2>
<p>Spreekt voor zich:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#728e00">import</span> <span style="color:#434f54">unittest</span>
<span style="color:#728e00">from</span> <span style="color:#434f54">calculator</span> <span style="color:#728e00">import</span> <span style="color:#434f54">Calculator</span>
<span style="color:#728e00">class</span> <span style="color:#434f54">TestCalculator</span>(<span style="color:#434f54">unittest</span><span style="color:#728e00">.</span><span style="color:#434f54">TestCase</span>):
<span style="color:#728e00">def</span> <span style="color:#d35400">setUp</span>(<span style="color:#434f54">self</span>):
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">calc</span> <span style="color:#728e00">=</span> <span style="color:#434f54">Calculator</span>()<span style="color:#728e00">.</span><span style="color:#434f54">calculate</span>;
<span style="color:#728e00">def</span> <span style="color:#d35400">test_calculateBasicNumberReturnsNumber</span>(<span style="color:#434f54">self</span>):
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">assertEqual</span>(<span style="color:#8a7b52">3</span>, <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">calc</span>(<span style="color:#7f8c8d">&#39;3&#39;</span>))
<span style="color:#728e00">def</span> <span style="color:#d35400">test_calculateSimpleMultiplicationReturnsResult</span>(<span style="color:#434f54">self</span>):
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">assertEqual</span>(<span style="color:#8a7b52">10</span>, <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">calc</span>(<span style="color:#7f8c8d">&#39;5*2&#39;</span>))
<span style="color:#728e00">def</span> <span style="color:#d35400">test_calculateInvalidStringShouldThrowException</span>(<span style="color:#434f54">self</span>):
<span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">assertRaises</span>(<span style="color:#434f54">ValueError</span>, <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#434f54">calc</span>, (<span style="color:#7f8c8d">&#39;blabl&#39;</span>))
</code></pre></div><p>Zie <a href="http://docs.python.org/3/library/unittest.html">http://docs.python.org/3/library/unittest.html</a></p>
<ul>
<li><code>setUp</code> wordt automatisch aangeroepen. Beforeclass, aftereach etc etc bestaat ook.</li>
<li>alle methods met <code>test_</code> worden automatisch herkend.</li>
</ul>
<h4 id="hoe-voer-ik-dit-nu-uit">Hoe voer ik dit nu uit?</h4>
<p>Dit stuk onder uw py file plakken:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#728e00">if</span> <span style="color:#434f54">__name__</span> <span style="color:#728e00">==</span> <span style="color:#7f8c8d">&#39;__main__&#39;</span>:
<span style="color:#434f54">unittest</span><span style="color:#728e00">.</span><span style="color:#434f54">main</span>()
</code></pre></div><p>En dan <code>python -m unittest -v calculatorTest</code>. de v flag geeft wat extra output, anders staat er gewoon OK. De test op zich builden in bijvoorbeeld sublime met de main method erin zorgt er ook voor dat deze automatisch uitgevoerd wordt.</p>
<h4 id="automatic-test-case-discovery">automatic test case discovery</h4>
<p><code>python -m unittest discover</code> gaat alle unit testen vanaf huidig dir scannen en uitvoeren (instelbaar met params). Moet voldoen aan:</p>
<ol>
<li>extenden van <code>unittest.TestCase</code></li>
<li>voldoen aan python module structuur. Testen in files met prefix &ldquo;test_x.py&rdquo;.</li>
<li>Indien in subfolder &ldquo;test&rdquo;: vergeet geen &ldquo;<strong>init</strong>.py&rdquo; file.</li>
</ol>
<h5 id="autotest">autotest</h5>
<p>Mogelijk met onder andere <code>autonose</code> (nose is een alternatief voor unittest) en <code>sniffer</code>. Om die te installeren moet je via de pip package manager gaan, en dan gewoon sniffer uitvoeren in uw base directory.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>Ruby Class structures basics</title>
<link>https://brainbaking.com/post/2013/10/ruby-classes/</link>
<comments>https://brainbaking.com/post/2013/10/ruby-classes/#commento</comments>
<pubDate>Tue, 01 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/ruby-classes/</guid>
<category domain="https://brainbaking.com/tags/ruby">ruby</category>
<category domain="https://brainbaking.com/tags/classes">classes</category>
<description>
<![CDATA[
<h1 id="ruby-classes">Ruby Classes</h1>
<h3 id="closures-and-lambdas">Closures and lambda&rsquo;s</h3>
<p>Weer 4 verschillende mogelijkheden in Ruby, zie <a href="http://techspry.com/ruby_and_rails/proc-and-lambda-in-ruby/">Proc and Lambda in Ruby</a></p>
<h5 id="native-blocks-aanmaken">Native &ldquo;blocks&rdquo; aanmaken</h5>
<p>Is niet mogelijk. <code>a = { puts &quot;hello&quot; }</code> geeft een Syntax error; dit moet effectief met <code>Proc.new</code> gebeuren.</p>
<h5 id="lambdas-aanmaken">Lambdas aanmaken</h5>
<p>Kan ook weer op twee manieren:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#434f54">a</span> <span style="color:#728e00">=</span> <span style="color:#728e00">lambda</span> { <span style="color:#728e00">puts</span> <span style="color:#7f8c8d">&#34;hello&#34;</span> }
<span style="color:#434f54">b</span> <span style="color:#728e00">=</span> <span style="color:#728e00">-&gt;</span> { <span style="color:#728e00">puts</span> <span style="color:#7f8c8d">&#34;hello&#34;</span> }
</code></pre></div><h5 id="blocks-als-argumenten-doorgeven">Blocks als argumenten doorgeven</h5>
<p>Wordt slechts één aanvaard, <code>Proc</code>s zijn objecten en kan dus op eender welke manier. Een block is eerder deel van de taal als syntax. (zoals bij <code>do</code>)</p>
<h5 id="een-lambda-is-een-proc">Een lambda is een Proc</h5>
<p>Met twee grote verschillen (zie <a href="http://awaxman11.github.io/blog/2013/08/05/what-is-the-difference-between-a-block/">What is the difference between a block, a proc and a lambda in ruby?</a>):</p>
<ol>
<li>een <code>lambda</code> controleert argumenten, een <code>Proc</code> kan het niet schelen.</li>
<li>een <code>return</code> statement in een <code>lambda</code> stopt slechts de closure. In een <code>Proc</code> stopt het de hele enclosing method ❗</li>
</ol>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#728e00">def</span> <span style="color:#d35400">proc_test</span>
<span style="color:#728e00">proc</span> <span style="color:#728e00">=</span> <span style="color:#434f54">Proc</span><span style="color:#728e00">.</span><span style="color:#434f54">new</span> { <span style="color:#728e00">return</span> }
<span style="color:#728e00">proc</span><span style="color:#728e00">.</span><span style="color:#434f54">call</span>
<span style="color:#728e00">puts</span> <span style="color:#7f8c8d">&#34;Hello world&#34;</span>
<span style="color:#728e00">end</span>
<span style="color:#434f54">proc_test</span> <span style="color:#95a5a6"># calling proc_test prints nothing</span>
</code></pre></div><h3 id="class-methods">Class methods</h3>
<p>Zie <a href="http://www.railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/">Class and instance methods in Ruby</a>. Er zijn verschillende manieren om een class method te maken in ruby:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#95a5a6"># Way 1</span>
<span style="color:#728e00">class</span> <span style="color:#434f54">Foo</span>
<span style="color:#728e00">def</span> <span style="color:#434f54">self</span><span style="color:#728e00">.</span><span style="color:#d35400">bar</span>
<span style="color:#728e00">puts</span> <span style="color:#7f8c8d">&#39;class method&#39;</span>
<span style="color:#728e00">end</span>
<span style="color:#728e00">end</span>
<span style="color:#434f54">Foo</span><span style="color:#728e00">.</span><span style="color:#434f54">bar</span> <span style="color:#95a5a6"># &#34;class method&#34;</span>
<span style="color:#95a5a6"># Way 2</span>
<span style="color:#728e00">class</span> <span style="color:#434f54">Foo</span>
<span style="color:#728e00">class</span> <span style="color:#728e00">&lt;&lt;</span> <span style="color:#728e00">self</span>
<span style="color:#728e00">def</span> <span style="color:#d35400">bar</span>
<span style="color:#728e00">puts</span> <span style="color:#7f8c8d">&#39;class method&#39;</span>
<span style="color:#728e00">end</span>
<span style="color:#728e00">end</span>
<span style="color:#728e00">end</span>
<span style="color:#434f54">Foo</span><span style="color:#728e00">.</span><span style="color:#434f54">bar</span> <span style="color:#95a5a6"># &#34;class method&#34;</span>
<span style="color:#95a5a6"># Way 3</span>
<span style="color:#728e00">class</span> <span style="color:#434f54">Foo</span>; <span style="color:#728e00">end</span>
<span style="color:#728e00">def</span> <span style="color:#434f54">Foo</span><span style="color:#728e00">.</span><span style="color:#d35400">bar</span>
<span style="color:#728e00">puts</span> <span style="color:#7f8c8d">&#39;class method&#39;</span>
<span style="color:#728e00">end</span>
<span style="color:#434f54">Foo</span><span style="color:#728e00">.</span><span style="color:#434f54">bar</span> <span style="color:#95a5a6"># &#34;class method&#34;</span>
</code></pre></div><p>Instance methods worden met <code>def name</code> gedefiniëerd, zoals men intuïtief zou aannemen (wow).</p>
<h3 id="reflectie-methods-accessen">&ldquo;Reflectie&rdquo;: Methods accessen</h3>
<p>Dit kan op twee manieren: op een object <strong>instance</strong> of op een <strong>class</strong>, met <code>.method</code> of <code>.static_method</code>, zie <a href="http://www.ruby-doc.org/core-2.1.1/Method.html">Ruby Method doc</a>.</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#8a7b52">1</span><span style="color:#728e00">.</span><span style="color:#434f54">method</span>(<span style="color:#7f8c8d">:+</span>)<span style="color:#728e00">.</span><span style="color:#434f54">call</span> <span style="color:#8a7b52">2</span> <span style="color:#95a5a6"># output: 3</span>
<span style="color:#434f54">Fixnum</span><span style="color:#728e00">.</span><span style="color:#434f54">static_method</span>(<span style="color:#7f8c8d">:+</span>)<span style="color:#728e00">.</span><span style="color:#434f54">bind</span>(<span style="color:#8a7b52">1</span>)<span style="color:#728e00">.</span><span style="color:#434f54">call</span> <span style="color:#8a7b52">2</span> <span style="color:#95a5a6"># output: 3</span>
<span style="color:#8a7b52">1</span><span style="color:#728e00">.</span><span style="color:#434f54">method</span>(<span style="color:#7f8c8d">&#34;+&#34;</span>)<span style="color:#728e00">.</span><span style="color:#434f54">unbind</span>()<span style="color:#728e00">.</span><span style="color:#434f54">bind</span>(<span style="color:#8a7b52">1</span>)<span style="color:#728e00">.</span><span style="color:#434f54">call</span>(<span style="color:#8a7b52">2</span>) <span style="color:#95a5a6"># output: 3</span>
</code></pre></div><p>Object Methods zijn al gebind en kan je dus losmaken van hun reference indien gewenst - zelfde effect als de <code>static_method</code> call. Je kan blijkbaar zowel een string als een ref meegeven om de naam van de method te resolven.</p>
<h5 id="ik-wil-meer">Ik wil meer</h5>
<p><code>1.methods.each{|x| puts x}</code></p>
<p>of <code>.static_methods</code> natuurlijk. Enkel public of protected, ook van subklassen.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>Scheme tips and tricks</title>
<link>https://brainbaking.com/post/2013/10/scheme/</link>
<comments>https://brainbaking.com/post/2013/10/scheme/#commento</comments>
<pubDate>Tue, 01 Oct 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/10/scheme/</guid>
<category domain="https://brainbaking.com/tags/scheme">scheme</category>
<category domain="https://brainbaking.com/tags/Unit Testing">Unit Testing</category>
<description>
<![CDATA[
<h3 id="variable-arguments">Variable arguments</h3>
<p>Bron: <a href="http://www.cs.utexas.edu/ftp/garbage/cs345/schintro-v14/schintro_68.html">http://www.cs.utexas.edu/ftp/garbage/cs345/schintro-v14/schintro_68.html</a></p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#728e00">define </span>(<span style="color:#d35400">stack</span> <span style="color:#728e00">.</span> <span style="color:#434f54">args</span>)
(<span style="color:#728e00">display </span><span style="color:#434f54">args</span>))
(<span style="color:#728e00">define </span>(<span style="color:#d35400">plus</span> <span style="color:#434f54">a</span> <span style="color:#434f54">b</span>)
(<span style="color:#d35400">stack</span> <span style="color:#434f54">a</span> <span style="color:#434f54">b</span>)
(<span style="color:#728e00">+ </span><span style="color:#434f54">a</span> <span style="color:#434f54">b</span>))
(<span style="color:#d35400">plus</span> <span style="color:#8a7b52">1</span> <span style="color:#8a7b52">2</span>)
</code></pre></div><p>Print in een lijst <code>(1 2)</code> af. In scheme is het mogelijk om args op te splitsen, alles dat na de &ldquo;.&rdquo; komt, wordt samengenomen als een lijst in een speciale variabele die de rest van de argumenten binnen pakt. Je kan dus ook x aantal argumenten &ldquo;vast&rdquo; zetten en de rest laten opvangen door een lijst. <code>display</code> print alles in lijst vorm af.</p>
<h3 id="conditional-expressions-and-predicates">Conditional Expressions and Predicates</h3>
<h5 id="debugging-purposes">Debugging purposes</h5>
<ul>
<li><code>(display arg)</code> print argument in de <code>*scheme*</code> buffer af. (pakt een <strong>lijst</strong> binnen: bvb <code>(display '(&quot;bezig met afdrukken van &quot; arg1 arg2))</code></li>
<li><code>(newline)</code> maakt een nieuwe lijn in diezelfde buffer.</li>
</ul>
<h5 id="de-undefined-variabele">de &lsquo;undefined&rsquo; variabele</h5>
<p>Een conditional operator die door alle gevallen heen valt (zoals een switch zonder default), retourneert de variabele <strong>unspecific</strong>. Dit is een reserved keyword:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#728e00">load </span><span style="color:#7f8c8d">&#34;./test-manager/load.scm&#34;</span>)
(<span style="color:#d35400">in-test-group</span> <span style="color:#434f54">conditionals</span>
(<span style="color:#728e00">define </span><span style="color:#434f54">x</span> <span style="color:#8a7b52">0</span>)
(<span style="color:#d35400">define-test</span> (<span style="color:#d35400">case-fall-through-returns-undefined</span>)
(<span style="color:#d35400">assert-equals</span> <span style="color:#434f54">unspecific</span>
(<span style="color:#728e00">cond </span>((<span style="color:#728e00">&lt; </span><span style="color:#434f54">x</span> <span style="color:#8a7b52">0</span>) <span style="color:#8a7b52">1</span>)
((<span style="color:#728e00">&gt; </span><span style="color:#434f54">x</span> <span style="color:#8a7b52">0</span>) <span style="color:#8a7b52">1</span>)))
))
(<span style="color:#d35400">run-registered-tests</span>)
</code></pre></div><p>Het is niet mogelijk om die variabele te overschrijven met <code>(define unspecific 8934)</code>, volgende fout wordt dan gegenereerd: &ldquo;Premature reference to reserved name: unspecific.&rdquo;</p>
<h3 id="implementaties">Implementaties</h3>
<ul>
<li>MIT-Scheme: <a href="http://www.gnu.org/s/mit-scheme/">http://www.gnu.org/s/mit-scheme/</a> -&gt; ingebouwde emacs evaluator</li>
<li>Racket: <a href="http://racket-lang.org/">http://racket-lang.org/</a></li>
</ul>
<h3 id="testen-schrijven">Testen schrijven</h3>
<p>Testing framework: Zie <a href="http://web.mit.edu/~axch/www/testing-1.2.html">http://web.mit.edu/~axch/www/testing-1.2.html</a></p>
<p>Inladen test-manager &amp; testen definen en kunnen wrappen in elkaar à-la Jasmine in JS:</p>
<div class="highlight"><pre style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scheme" data-lang="scheme">(<span style="color:#728e00">load </span><span style="color:#7f8c8d">&#34;./test-manager/load.scm&#34;</span>)
(<span style="color:#d35400">in-test-group</span> <span style="color:#434f54">my-first-tests</span>
(<span style="color:#d35400">in-test-group</span> <span style="color:#434f54">getallekes</span>
(<span style="color:#d35400">define-test</span> (<span style="color:#d35400">add-simple-numbers</span>)
(<span style="color:#d35400">assert-equals</span> (<span style="color:#d35400">my-add</span> <span style="color:#8a7b52">1</span> <span style="color:#8a7b52">2</span>) <span style="color:#8a7b52">3</span>)))
(<span style="color:#d35400">in-test-group</span> <span style="color:#434f54">meer-getallekes</span>
(<span style="color:#d35400">define-test</span> (<span style="color:#d35400">add-more-complex-numbers</span>)
(<span style="color:#d35400">assert-equals</span> (<span style="color:#d35400">my-add</span> <span style="color:#8a7b52">3</span> <span style="color:#8a7b52">7</span>) <span style="color:#8a7b52">10</span>))))
(<span style="color:#d35400">run-registered-tests</span>)
</code></pre></div><p>Achteraf altijd <strong><code>run-registered-tests</code></strong> evalueren, in de default scheme editor wordt dan de test output getoond. (Default editor = <strong>scheme</strong>*, gewoon enter drukken bij open doen nieuwe editor)</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 October 2013.
</p>
]]>
</description>
</item>
<item>
<title>No, vegetarians do not eat fish!</title>
<link>https://brainbaking.com/post/2013/09/vegetarians-do-not-eat-fish/</link>
<comments>https://brainbaking.com/post/2013/09/vegetarians-do-not-eat-fish/#commento</comments>
<pubDate>Fri, 06 Sep 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/09/vegetarians-do-not-eat-fish/</guid>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/peppersheader.jpg"/>
</p>
<p>Originally posted on <a href="https://medium.com/this-happened-to-me/no-vegetarians-do-not-eat-fish-403bc03781ab">Medium</a>.</p>
<h3 id="the-amateurs">The amateurs</h3>
<blockquote>
<p>“So, you do eat a juicy peace of grilled salmon, right?”<br/>
“No, I already told you, Im a vegetarian.” (<em>sigh</em>)<br/>
Frowning. You can almost hear them thinking “thats what I meant”.<br/>
“If youre a pescatarian, you eat seafood but not other animals”.<br/>
“Oh, right right, sorry!”.</p>
</blockquote>
<p>It must have been the fourth conversation with somebody, where I have to explain what “being a vegetarian” actually means. Not that I get upset by that, its fine if somebody who doesnt have a lot of knowledge on that matter asks about it. Two things can happen after that.</p>
<p>Onethe person accepts my choice and carries on.</p>
<p>Twothe person starts misbehaving (I have written the word “dick” here but dont really know what is appropriate to use).</p>
<blockquote>
<p>“Stop trying to save the world dude, you simply cant by yourself!”<br/>
“But the spareribs are very good, try some, haha!”<br/>
“Ohmygosh youll have a lot of problems with vitamins and stuff!”<br/>
&hellip;</p>
</blockquote>
<p>Even most vegetarian cookbooks include a section about nutrition and diet, where it also gives the reader some advice on how to counter such silliness. Thats the main reason why I dont even like simply saying that Im a vegetarianeven people which you judged as fairly reasonable start acting stupid. And Im not even a vegan.</p>
<h3 id="the-professionals">The professionals</h3>
<p>Its not that hard to see something like that comingmost people who eat to eat (Filling instead of Feeding) and who arent really interested in the subject of food in general will act like that.
But people who work in the catering sector should know better. I expect every single restaurant to offer at least one vegetarian option (sorry vegans, youre fucked, as always. Enjoy the sauce, wanna bet it contains milk? <em>sigh</em>). And most places Ive visited luckily do. There are some really great vegetarian restaurants, but there are also very good steakhouses which offer a lot of decent vegetarian dishes.</p>
<p>Last week, we went to an Italian restaurant for my birthday. Its actually also an Hotel, quite posh, nicely decorated, you know what Im talking about. And I thought “hey, its Italian”surely they do offer some vegetarian dishes, right? Like… Pizzas? Pastas? Sure.
Well guess again. Nothing on the menu. Okay, so I ask a waiter.</p>
<blockquote>
<p>“Well, we do have a pasta with scampi”she looks at me and waits for my nod to quickly write the order down. I frown. She blinks and starts to get impatient.<br/>
“Im sorry but fish is not vegetarian. Is it possible to get the lasagne without ham?”<br/>
She starts clicking with her pen. “No.”<br/>
“What do you mean, no? Do you have a pasta with vegetables?”<br/>
“No.”</p>
</blockquote>
<p>Urgh. I really, <em>really</em> hate that. Especially because my grandparents came along and they dont approve of my choice of being vegetarianthey simply dont get it. So another discussion follows “why dont you simply eat blahblah and I told you blahblah”. Thank you very much, Italian restaurant, just what I needed.</p>
<p>In the end, I managed to get a simple boiled spaghetti with some baked vegetables and olive oil. For 15 EUR. Cant be bad, I hear you thinking. It wasnt, but it wasnt good either. It was bland and I was upset.</p>
<p>I expect people who serve other people dinner to know what it means to be a vegetarian or vegan or whatever you like or dislike, especially in a place like that. I can hardly believe I was the very first person in that place to ask something stupid like that.</p>
<p>I know this story might sound weird if you live in an area where vegetarianism is more acceptedI thought it was here too. Theres still a lot of work to do on educating people and spreading the message that its okay to eat whatever the hell you want to, even if its not the same as what your parents or great-grandparents ate and even if its not according to tradition. I live my own life and decide myself what goes down my stomach, thank you very much.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 6 September 2013.
</p>
]]>
</description>
</item>
<item>
<title>On finding your inner zen in big cities</title>
<link>https://brainbaking.com/post/2013/08/on-finding-your-inner-zen-in-big-cities/</link>
<comments>https://brainbaking.com/post/2013/08/on-finding-your-inner-zen-in-big-cities/#commento</comments>
<pubDate>Thu, 29 Aug 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/08/on-finding-your-inner-zen-in-big-cities/</guid>
<category domain="https://brainbaking.com/tags/braindump">braindump</category>
<category domain="https://brainbaking.com/tags/learning">learning</category>
<category domain="https://brainbaking.com/tags/zen">zen</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/innerzenheader.jpg"/>
</p>
<p>Originally posted on <a href="https://medium.com/@woutergroenev/on-finding-your-inner-zen-in-big-cities-c2be933114e3">Medium</a>.</p>
<p>There have been a lot of love letters to big cities here on Medium recently. I never really understood the love for those busy places, but that should not be a big surprise as we grew up in a relatively small village in Belgium. Our country must be one of the smallest in the worldyou can drive from one edge to the other in less than 2 hours (excluding traffic jams of course).</p>
<p>And yet Brussels, the capital city of Europe, lies within Belgium. When I worked there, I used to hate that citybut for the wrong reasons. I was one of the thousand usual daily train travellers, taking the same route to and from work every single day. When you pass the central station, you need to work your way through a relatively dirty street with beggars and a lot of puke pools (horray for late night city clubs). I actually did not know Brussels at all, until I started exploring the center on my own at noon.</p>
<p>Every large city has its multicultural neighbourhoods which you might not want to pass at a certain time, but limiting yourself to only those areas narrows your vision of the city.
So I found an organic bakery which only sells <a href="http://www.redzuurdesem.be">sourdough bread</a> (an exception to the rule in Belgium). I discovered little tea shops or jummy places to eat. I actually started to enjoy strolling through the center.</p>
<h3 id="sensory-input-overload">Sensory input overload</h3>
<p>As much as I liked discovering special places in Brussels, I was also very glad I could go home at 17H PM, and enjoy the peace of the environment where we live. Its not exactly easy to describe, but I sometimes have the feeling that visiting a large city drains me in some way. There is so much to see, there are so many people in such a small place, after a while its difficult to concentrate. It feels like Im getting a sensor overload, and I need to retreat, to a silent hotel room or back to the office.
And Im not the only one feeling that way, as my girlfriend actually made me think about this while she explained there was “too much info coming at once”. That might sound reasonable as she grew up in the same neighbourhood as I did.</p>
<p><figure>
<a href="/img/koe.jpg" class="lbox">
<img loading="lazy" src="/img/koe.jpg" alt="100 meters from our home, following a hiking trail." >
</a>
</figure>
<em>100 meters from our home, following a hiking trail.</em></p>
<p>Curious. My sister currently lives in Australia and loves big cities and a skyscraper view. Her opinion on our local (little) town completely changed as shes used to something much bigger now. When she visits us, shes usually bored quite quicklyeven if theres enough to do locally. Of course everything has to be seen in perspective.</p>
<p>I do admit living in a big city makes things a lot easier (and more difficult) but Id miss the peace and quietness. As much as I like Steven Johnsons concept of “liquid networks” from “<a href="http://www.goodreads.com/book/show/8034188-where-good-ideas-come-from?from_search=true">where good ideas come from</a>”, I still think I wouldnt be fit to live right in the middle of it.</p>
<p>Maybe its my <a href="http://www.goodreads.com/book/show/8520610-quiet?from_search=true">introvert</a> part speaking. Most people who know me well would say Im an extravert who isnt scared of saying what he thinks. Ive been thinking about these personality stereotypes a lot lately, and a colleage gave me another piece of the puzzle. She suggested that I spend a lot of energy on my extravert part at work, and to regain that energy I need my quiet, peaceful time. I call it being “work sociable”in my spare time Im not social at all, it drains too much energy. I dont have the feeling that Im required to behave like that during the day, but maybe my work as teamcoach requires me to do so without me even noticing.</p>
<p>So maybe I could conclude that the way I see big cities shifts as my job changes? Never thought about that. Thank you Medium!</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 29 August 2013.
</p>
]]>
</description>
</item>
<item>
<title>Ending your day with happy thoughts</title>
<link>https://brainbaking.com/post/2013/08/can-i-haz-happy-thoughts/</link>
<comments>https://brainbaking.com/post/2013/08/can-i-haz-happy-thoughts/#commento</comments>
<pubDate>Tue, 13 Aug 2013 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/08/can-i-haz-happy-thoughts/</guid>
<category domain="https://brainbaking.com/tags/self improvement">self improvement</category>
<category domain="https://brainbaking.com/tags/journaling">journaling</category>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/Ending%20your%20day%20with%20happy%20thoughts.jpg"/>
</p>
<p>Past new year, I stopped promising silly things to myself. “This year, Ill for sure go jogging several times a week!”or “This year, Ill really get into learning another language!”. We all know how these things go. Not that I made something up on the very day, these ideas are usually carefully crafted in my sketchbook and are lingering there to be exposed and finally executed.</p>
<p>But there was someting I came across to on the internet I really, really liked. Something small and seemingly insignificant. These 365 things are not exactly new, I know. And “keeping notes to sort out your thoughts” is something I already do for years using my sketchbook which I carry with me everywhere.</p>
<p>I found another tiny sketchbook I did not use, grabbed a pencil and put these two objects beside my bed. I labelled the book “365&quot;, sewed a little hedgehog friend to give the booklet a fluffy look and started writing before actually going to sleep. You should write one sentence, every day. In this sentence, you should be thankful of someone or somethingthat happened to you today.</p>
<p>Sounds easy? Right. Put it to practice. It sometimes is extremely easy. It sometimes is extremely hard. Really, really hard.</p>
<p>Frustrated? Write.
You should. And by “write”, I dont mean whole pages. Just one sentence: what happened to you today, what did you like? Focus on the good stuff.</p>
<p>I have to admit, sometimes more than other times, I have trouble finding good the good stuff. Some days, my work can be really frustrating, the lawn mower got jammed halfway through the lawn, the bycicle chain broke, … I think you recognize these days.</p>
<p>When I go to sleep, I mull over things that happened that dayits not some deliberate action, and sometimes I cant seem to get rid of certain thoughts. Like how to convince your colleage to use method x and not method y to do work z.
No worriesgrab that pencil and write in your 365 booklet. Start with 2 simple words: “thank you”. These can end in “thank you dear x for retweeting about a meetup I will attend” or “thank you mother for dropping by and cooking hot soup”. (Yes they sound very cliché, make up your own!)</p>
<p>In my experience, mindfully going through your day and thinking about what you liked most gives me happy thoughts and a sort of satisfaction feeling. It helps me sleep. Its interesting to reread previous months.</p>
<p>So, thank you internet for all those amazing blogs and great ideas, even if its as simple as writing down what you liked that day.</p>
<p>Oh, and heres a pro-tip: use a pencil.That way, you can write while lying down in your bed.</p>
<p>Originally posted on <a href="https://medium.com/writers-on-writing/6a9dbf4d8212">Medium</a>.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 13 August 2013.
</p>
]]>
</description>
</item>
<item>
<title>Archive by year: 2013</title>
<link>https://brainbaking.com/post/2013/</link>
<comments>https://brainbaking.com/post/2013/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2013/</guid>
<description>
<![CDATA[
Not finding what you're looking for? <a href="/tags">Browse the archives</a>.
<div class="list">
<h2>2013</h2>
<h3>Nov</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">14</span>
<div class="list-title">
<h4>
<a href="/post/2013/11/builders-dsl/">Enhancing the builder pattern with closures</a>
</h4>
the trainwreck/builder/chaining pattern can be dangerous and here&#39;s why
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/closures"><kbd class="item-tag">closures</kbd></a>
<a href="https://brainbaking.com/tags/groovy"><kbd class="item-tag">groovy</kbd></a>
<a href="https://brainbaking.com/tags/csharp"><kbd class="item-tag">CSharp</kbd></a>
<a href="https://brainbaking.com/tags/javascript"><kbd class="item-tag">javascript</kbd></a>
<a href="https://brainbaking.com/tags/java"><kbd class="item-tag">java</kbd></a>
<a href="https://brainbaking.com/tags/functional-programming"><kbd class="item-tag">functional programming</kbd></a>
</div>
</li>
<li>
<span class="list-date">04</span>
<div class="list-title">
<h4>
<a href="/post/2013/11/integration-testing-sqlite/">Integration Testing with SQLite</a>
</h4>
Decoupling your integrated database environment from your development.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/unit-testing"><kbd class="item-tag">unit testing</kbd></a>
<a href="https://brainbaking.com/tags/sql"><kbd class="item-tag">sql</kbd></a>
<a href="https://brainbaking.com/tags/csharp"><kbd class="item-tag">CSharp</kbd></a>
<a href="https://brainbaking.com/tags/sqlite"><kbd class="item-tag">sqlite</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Oct</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">14</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/vstudio-missing-features/">Visual Studio 2012 for Eclipse users</a>
</h4>
Trying to fill the gap of missing features in VStudio.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/software">software</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/visual-studio"><kbd class="item-tag">visual studio</kbd></a>
<a href="https://brainbaking.com/tags/eclipse"><kbd class="item-tag">eclipse</kbd></a>
</div>
</li>
<li>
<span class="list-date">13</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/learning-to-become-a-baker/">Learning to become a baker</a>
</h4>
Why there are more and more industrial bakers who dont care what they sell.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/braindump"><kbd class="item-tag">braindump</kbd></a>
<a href="https://brainbaking.com/tags/learning"><kbd class="item-tag">learning</kbd></a>
<a href="https://brainbaking.com/tags/baking"><kbd class="item-tag">baking</kbd></a>
<a href="https://brainbaking.com/tags/bread"><kbd class="item-tag">bread</kbd></a>
</div>
</li>
<li>
<span class="list-date">10</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/unit-testing-stored-procedures/">Unit Testing Stored Procedures</a>
</h4>
And a pragmatic guide on how to include them into your build system.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/unit-testing"><kbd class="item-tag">unit testing</kbd></a>
<a href="https://brainbaking.com/tags/sql"><kbd class="item-tag">sql</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/dynamic-languages/">A look at dynamic languages</a>
</h4>
A comparison on some dynamic languages
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/javascript"><kbd class="item-tag">javascript</kbd></a>
<a href="https://brainbaking.com/tags/ruby"><kbd class="item-tag">ruby</kbd></a>
<a href="https://brainbaking.com/tags/dynamiclangs"><kbd class="item-tag">dynamiclangs</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/cplusplus-basics/">C&#43;&#43; Basics</a>
</h4>
C&#43;&#43; basics for a Java developer
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/c&#43;&#43;"><kbd class="item-tag">c&#43;&#43;</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/unix-cmd/">Heavily used Unix Commands</a>
</h4>
Unix Commandline stuff in here!
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/software">software</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/unix"><kbd class="item-tag">unix</kbd></a>
<a href="https://brainbaking.com/tags/cmd"><kbd class="item-tag">cmd</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/introduction-to-js/">Introduction to JavaScript</a>
</h4>
Writing JS, Pre-ES5 era.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/javascript"><kbd class="item-tag">javascript</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/python-basics/">Python Class structure basics</a>
</h4>
A crash course in Python classes
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/python"><kbd class="item-tag">python</kbd></a>
<a href="https://brainbaking.com/tags/ruby"><kbd class="item-tag">ruby</kbd></a>
<a href="https://brainbaking.com/tags/classes"><kbd class="item-tag">classes</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/ruby-classes/">Ruby Class structures basics</a>
</h4>
A look at ruby&#39;s lambda&#39;s
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/ruby"><kbd class="item-tag">ruby</kbd></a>
<a href="https://brainbaking.com/tags/classes"><kbd class="item-tag">classes</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2013/10/scheme/">Scheme tips and tricks</a>
</h4>
Unit testing in Scheme
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/scheme"><kbd class="item-tag">scheme</kbd></a>
<a href="https://brainbaking.com/tags/unit-testing"><kbd class="item-tag">Unit Testing</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Sep</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">06</span>
<div class="list-title">
<h4>
<a href="/post/2013/09/vegetarians-do-not-eat-fish/">No, vegetarians do not eat fish!</a>
</h4>
The sad state of knowledge in your typical restaurant
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
</div>
</li>
</ul>
</article>
<h3>Aug</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">29</span>
<div class="list-title">
<h4>
<a href="/post/2013/08/on-finding-your-inner-zen-in-big-cities/">On finding your inner zen in big cities</a>
</h4>
Coping with crowded places when youre used to peaceful villages
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/braindump"><kbd class="item-tag">braindump</kbd></a>
<a href="https://brainbaking.com/tags/learning"><kbd class="item-tag">learning</kbd></a>
<a href="https://brainbaking.com/tags/zen"><kbd class="item-tag">zen</kbd></a>
</div>
</li>
<li>
<span class="list-date">13</span>
<div class="list-title">
<h4>
<a href="/post/2013/08/can-i-haz-happy-thoughts/">Ending your day with happy thoughts</a>
</h4>
Or how a tiny thing can really help you sleep better
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/self-improvement"><kbd class="item-tag">self improvement</kbd></a>
<a href="https://brainbaking.com/tags/journaling"><kbd class="item-tag">journaling</kbd></a>
</div>
</li>
</ul>
</article>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Archive by year: 2014</title>
<link>https://brainbaking.com/post/2014/</link>
<comments>https://brainbaking.com/post/2014/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2014/</guid>
<description>
<![CDATA[
Not finding what you're looking for? <a href="/tags">Browse the archives</a>.
<div class="list">
<h2>2014</h2>
<h3>Dec</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">23</span>
<div class="list-title">
<h4>
<a href="/post/2014/12/unit-testing-extjs-ui/">Unit Testing Extjs UI with Siesta</a>
</h4>
An attempt to replace instable Webdriver tests with Siesta UI tests
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/unit-testing"><kbd class="item-tag">unit testing</kbd></a>
<a href="https://brainbaking.com/tags/javascript"><kbd class="item-tag">javascript</kbd></a>
<a href="https://brainbaking.com/tags/extjs"><kbd class="item-tag">extjs</kbd></a>
<a href="https://brainbaking.com/tags/siesta"><kbd class="item-tag">siesta</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Oct</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">24</span>
<div class="list-title">
<h4>
<a href="/post/2014/10/memory-management-vs-java/">.NET Memory management VS JVM Memory management</a>
</h4>
Increasing your maximum heap size in .NET? Tough luck.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/memory-management"><kbd class="item-tag">memory management</kbd></a>
<a href="https://brainbaking.com/tags/clr"><kbd class="item-tag">CLR</kbd></a>
<a href="https://brainbaking.com/tags/.net"><kbd class="item-tag">.NET</kbd></a>
<a href="https://brainbaking.com/tags/jvm"><kbd class="item-tag">JVM</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Sep</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">23</span>
<div class="list-title">
<h4>
<a href="/post/2014/09/faking-domain-logic/">Faking domain logic</a>
</h4>
Using C# extensions to create the illusion of domain logic
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/domain-driven-design"><kbd class="item-tag">domain driven design</kbd></a>
<a href="https://brainbaking.com/tags/csharp"><kbd class="item-tag">CSharp</kbd></a>
<a href="https://brainbaking.com/tags/code-smells"><kbd class="item-tag">code smells</kbd></a>
</div>
</li>
<li>
<span class="list-date">22</span>
<div class="list-title">
<h4>
<a href="/post/2014/09/custom-webdriver-page-factories/">Custom Webdriver Page Factories</a>
</h4>
Wrapping WebElements to reduce boilerplate clutter
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/unit-testing"><kbd class="item-tag">unit testing</kbd></a>
<a href="https://brainbaking.com/tags/java"><kbd class="item-tag">java</kbd></a>
<a href="https://brainbaking.com/tags/csharp"><kbd class="item-tag">CSharp</kbd></a>
<a href="https://brainbaking.com/tags/webdriver"><kbd class="item-tag">webdriver</kbd></a>
<a href="https://brainbaking.com/tags/scenario-testing"><kbd class="item-tag">scenario testing</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Mar</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">26</span>
<div class="list-title">
<h4>
<a href="/post/2014/03/scons-building/">Bye autotools hello Scons</a>
</h4>
Building C&#43;&#43; projects with Scons
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/c&#43;&#43;"><kbd class="item-tag">C&#43;&#43;</kbd></a>
<a href="https://brainbaking.com/tags/python"><kbd class="item-tag">python</kbd></a>
<a href="https://brainbaking.com/tags/build-ecosystem"><kbd class="item-tag">build ecosystem</kbd></a>
</div>
</li>
<li>
<span class="list-date">14</span>
<div class="list-title">
<h4>
<a href="/post/2014/03/metaprogramming-convention-dry/">Metaprogramming instead of duplication</a>
</h4>
convention over duplication, good or bad?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/csharp"><kbd class="item-tag">CSharp</kbd></a>
<a href="https://brainbaking.com/tags/java"><kbd class="item-tag">java</kbd></a>
<a href="https://brainbaking.com/tags/metaprogramming"><kbd class="item-tag">metaprogramming</kbd></a>
<a href="https://brainbaking.com/tags/reflection"><kbd class="item-tag">reflection</kbd></a>
<a href="https://brainbaking.com/tags/unit-testing"><kbd class="item-tag">unit testing</kbd></a>
<a href="https://brainbaking.com/tags/mocking"><kbd class="item-tag">mocking</kbd></a>
</div>
</li>
</ul>
</article>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Archive by year: 2015</title>
<link>https://brainbaking.com/post/2015/</link>
<comments>https://brainbaking.com/post/2015/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2015/</guid>
<description>
<![CDATA[
Not finding what you're looking for? <a href="/tags">Browse the archives</a>.
<div class="list">
<h2>2015</h2>
<h3>Jan</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">14</span>
<div class="list-title">
<h4>
<a href="/post/2015/01/webdriver-exception-handling/">Webdriver Exception Handling</a>
</h4>
What should you do when something goes wrong with your scenario tests
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/unit-testing"><kbd class="item-tag">unit testing</kbd></a>
<a href="https://brainbaking.com/tags/csharp"><kbd class="item-tag">CSharp</kbd></a>
<a href="https://brainbaking.com/tags/webdriver"><kbd class="item-tag">webdriver</kbd></a>
<a href="https://brainbaking.com/tags/scenario-testing"><kbd class="item-tag">scenario testing</kbd></a>
</div>
</li>
</ul>
</article>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Archive by year: 2016</title>
<link>https://brainbaking.com/post/2016/</link>
<comments>https://brainbaking.com/post/2016/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2016/</guid>
<description>
<![CDATA[
Not finding what you're looking for? <a href="/tags">Browse the archives</a>.
<div class="list">
<h2>2016</h2>
<h3>Dec</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">27</span>
<div class="list-title">
<h4>
<a href="/post/2016/12/vb6-unit-testing/">Unit testing in Legacy Projects: VB6</a>
</h4>
Even older 4GL languages have unit testing capabilities
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/unit-testing"><kbd class="item-tag">unit testing</kbd></a>
<a href="https://brainbaking.com/tags/vb6"><kbd class="item-tag">VB6</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Jan</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">26</span>
<div class="list-title">
<h4>
<a href="/post/2016/01/react-in-extjs/">Migrating from Extjs to React gradually</a>
</h4>
Migrating from Extjs to React gradually
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/javascript"><kbd class="item-tag">javascript</kbd></a>
<a href="https://brainbaking.com/tags/extjs"><kbd class="item-tag">extjs</kbd></a>
<a href="https://brainbaking.com/tags/react"><kbd class="item-tag">react</kbd></a>
</div>
</li>
</ul>
</article>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Archive by year: 2017</title>
<link>https://brainbaking.com/post/2017/</link>
<comments>https://brainbaking.com/post/2017/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2017/</guid>
<description>
<![CDATA[
Not finding what you're looking for? <a href="/tags">Browse the archives</a>.
<div class="list">
<h2>2017</h2>
<h3>Dec</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">30</span>
<div class="list-title">
<h4>
<a href="/post/2017/12/inventing-for-the-worse/">Inventing - for the worse?</a>
</h4>
Is inventing always a good thing?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/craftsmanship"><kbd class="item-tag">craftsmanship</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Aug</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">17</span>
<div class="list-title">
<h4>
<a href="/post/2017/08/i-am-jealous-of-my-dog/">I&#39;m jealous of my dog</a>
</h4>
Getting rid of garbage in your head
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
</div>
</li>
</ul>
</article>
<h3>Jul</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">18</span>
<div class="list-title">
<h4>
<a href="/post/2017/07/fountain-pens-first-look/">A quick look at 6 fountain pens</a>
</h4>
A test drive from a drawing perspective
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/fountain-pens"><kbd class="item-tag">fountain pens</kbd></a>
</div>
</li>
<li>
<span class="list-date">10</span>
<div class="list-title">
<h4>
<a href="/post/2017/07/journaling-in-practice/">Journaling in practice</a>
</h4>
My guide to keeping a journal
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/journaling"><kbd class="item-tag">journaling</kbd></a>
<a href="https://brainbaking.com/tags/fountain-pens"><kbd class="item-tag">fountain pens</kbd></a>
</div>
</li>
<li>
<span class="list-date">03</span>
<div class="list-title">
<h4>
<a href="/post/2017/07/nuts-about-local-nuts/">Nuts about local nuts</a>
</h4>
A case for local food
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/cooking"><kbd class="item-tag">cooking</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Jun</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">25</span>
<div class="list-title">
<h4>
<a href="/post/2017/06/healing-creative-scars/">Healing creative scars</a>
</h4>
My ultimate secret weapon for self improvement
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/journaling"><kbd class="item-tag">journaling</kbd></a>
<a href="https://brainbaking.com/tags/self-improvement"><kbd class="item-tag">self improvement</kbd></a>
<a href="https://brainbaking.com/tags/learning"><kbd class="item-tag">learning</kbd></a>
</div>
</li>
<li>
<span class="list-date">20</span>
<div class="list-title">
<h4>
<a href="/post/2017/06/a-samurai-learning-mindset/">A samurai learning mindset</a>
</h4>
Bushido and the ever learning spirit, techniques for 1600 and 2017?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
</div>
</li>
<li>
<span class="list-date">09</span>
<div class="list-title">
<h4>
<a href="/post/2017/06/development-principles-in-cooking/">Development principles in cooking</a>
</h4>
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/cooking"><kbd class="item-tag">cooking</kbd></a>
<a href="https://brainbaking.com/tags/development"><kbd class="item-tag">development</kbd></a>
<a href="https://brainbaking.com/tags/principles"><kbd class="item-tag">principles</kbd></a>
</div>
</li>
</ul>
</article>
<h3>May</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">30</span>
<div class="list-title">
<h4>
<a href="/post/2017/05/handing-over-enough-when-inspiring/">Are you handing over enough when inspiring someone?</a>
</h4>
What info to convey, when to stop?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/inspiring"><kbd class="item-tag">inspiring</kbd></a>
<a href="https://brainbaking.com/tags/giving"><kbd class="item-tag">giving</kbd></a>
</div>
</li>
<li>
<span class="list-date">25</span>
<div class="list-title">
<h4>
<a href="/post/2017/05/teaching-kids-how-to-program/">How to teach kids to program</a>
</h4>
Usable tips also applyable to grownups?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/techorama"><kbd class="item-tag">techorama</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Feb</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2017/02/teaching-yourself-to-draw/">Teaching yourself to draw</a>
</h4>
A year of spilling lots of ink
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
</div>
</li>
</ul>
</article>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Archive by year: 2018</title>
<link>https://brainbaking.com/post/2018/</link>
<comments>https://brainbaking.com/post/2018/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2018/</guid>
<description>
<![CDATA[
Not finding what you're looking for? <a href="/tags">Browse the archives</a>.
<div class="list">
<h2>2018</h2>
<h3>Dec</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">22</span>
<div class="list-title">
<h4>
<a href="/post/2018/12/over-analoog-en-digitaal/">Over analoog en digitaal</a>
</h4>
Waarom een fysieke handeling niet vervangbaar is
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/games"><kbd class="item-tag">games</kbd></a>
</div>
</li>
<li>
<span class="list-date">05</span>
<div class="list-title">
<h4>
<a href="/post/2018/12/unit-testing-picoblaze-assembly/">Unit Testing PicoBlaze Assembly files</a>
</h4>
Writing Psm Assembly test-first, because why wouldn&#39;t you?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/unit-testing"><kbd class="item-tag">unit testing</kbd></a>
<a href="https://brainbaking.com/tags/assembly"><kbd class="item-tag">assembly</kbd></a>
<a href="https://brainbaking.com/tags/picoblaze"><kbd class="item-tag">picoblaze</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Oct</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">27</span>
<div class="list-title">
<h4>
<a href="/post/2018/10/a-decade-in-the-industry/">A Decade in the Software Engineering industry</a>
</h4>
Everything I&#39;ve learned in 10 &#43; 1 years on the job
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/jobs"><kbd class="item-tag">jobs</kbd></a>
<a href="https://brainbaking.com/tags/craftsmanship"><kbd class="item-tag">craftsmanship</kbd></a>
<a href="https://brainbaking.com/tags/development"><kbd class="item-tag">development</kbd></a>
</div>
</li>
<li>
<span class="list-date">19</span>
<div class="list-title">
<h4>
<a href="/post/2018/10/lean-doctorate/">The Startup of a Lean Doctorate</a>
</h4>
Using agile practices to tacle a long-term research project
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/phd"><kbd class="item-tag">phd</kbd></a>
<a href="https://brainbaking.com/tags/tools"><kbd class="item-tag">tools</kbd></a>
<a href="https://brainbaking.com/tags/academia"><kbd class="item-tag">academia</kbd></a>
<a href="https://brainbaking.com/tags/agile"><kbd class="item-tag">agile</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Aug</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">28</span>
<div class="list-title">
<h4>
<a href="/post/2018/08/productivity-tools-multiplatform/">Productivity Tools on all platforms</a>
</h4>
Matching my most frequently used tools on OSX, Linux and Windows
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/software">software</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/productivity"><kbd class="item-tag">Productivity</kbd></a>
<a href="https://brainbaking.com/tags/tools"><kbd class="item-tag">tools</kbd></a>
</div>
</li>
<li>
<span class="list-date">20</span>
<div class="list-title">
<h4>
<a href="/post/2018/08/boeken-die-mij-gevormd-hebben/">Boeken die mij gevormd hebben tot wie ik ben</a>
</h4>
Deze teksten lieten een blijvende indruk na
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
</div>
</li>
<li>
<span class="list-date">03</span>
<div class="list-title">
<h4>
<a href="/post/2018/08/domain-driven-design-in-c/">Domain Driven Design in C</a>
</h4>
Who says imperative languages don&#39;t do DDD?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/domain-driven-design"><kbd class="item-tag">domain driven design</kbd></a>
<a href="https://brainbaking.com/tags/c"><kbd class="item-tag">C</kbd></a>
<a href="https://brainbaking.com/tags/c&#43;&#43;"><kbd class="item-tag">C&#43;&#43;</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Jul</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">24</span>
<div class="list-title">
<h4>
<a href="/post/2018/07/over-intellect/">Over de inflatie van intellect</a>
</h4>
De McDonaldisering van cultuur?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
</div>
</li>
<li>
<span class="list-date">10</span>
<div class="list-title">
<h4>
<a href="/post/2018/07/over-tijdsbesef/">Over tijdsbesef</a>
</h4>
Beroepen met een ander gevoel van tijd
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
</div>
</li>
</ul>
</article>
<h3>Jun</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">29</span>
<div class="list-title">
<h4>
<a href="/post/2018/06/informatics-education-modules/">Computer Science learning pathways</a>
</h4>
Categorizing essential Computer Science knowledge
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/teaching"><kbd class="item-tag">teaching</kbd></a>
<a href="https://brainbaking.com/tags/phd"><kbd class="item-tag">phd</kbd></a>
</div>
</li>
<li>
<span class="list-date">15</span>
<div class="list-title">
<h4>
<a href="/post/2018/06/reverse-engineering-a-curriculum/">Reverse engineering a curriculum</a>
</h4>
Can a unified software engineering philosopy shape the right context in a curriculum?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/teaching"><kbd class="item-tag">teaching</kbd></a>
<a href="https://brainbaking.com/tags/phd"><kbd class="item-tag">phd</kbd></a>
</div>
</li>
<li>
<span class="list-date">11</span>
<div class="list-title">
<h4>
<a href="/post/2018/06/over-bedrijfsethiek/">Over het introduceren van bedrijfsethiek</a>
</h4>
Een cultuur aanbrengen en onderhouden
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
</div>
</li>
<li>
<span class="list-date">04</span>
<div class="list-title">
<h4>
<a href="/post/2018/06/phd-proposal/">A Ph.D. Thesis Proposal</a>
</h4>
Bridging the gap between software development requirements in the industry and eudcations in the academia
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/phd"><kbd class="item-tag">phd</kbd></a>
</div>
</li>
</ul>
</article>
<h3>May</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">31</span>
<div class="list-title">
<h4>
<a href="/post/2018/05/teaching-philosophy-first/">Teaching by philosophy</a>
</h4>
On explaining the why before the how
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/teaching"><kbd class="item-tag">teaching</kbd></a>
<a href="https://brainbaking.com/tags/philosophy"><kbd class="item-tag">philosophy</kbd></a>
</div>
</li>
<li>
<span class="list-date">20</span>
<div class="list-title">
<h4>
<a href="/post/2018/05/over-entropie/">Over entropie</a>
</h4>
Hoe gaan wij om met chaos?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
</div>
</li>
</ul>
</article>
<h3>Apr</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">28</span>
<div class="list-title">
<h4>
<a href="/post/2018/04/thinking-in-terms-of-objects/">Thinking in terms of objects</a>
</h4>
An introduction to software design in terms of objects
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/teaching"><kbd class="item-tag">teaching</kbd></a>
</div>
</li>
<li>
<span class="list-date">06</span>
<div class="list-title">
<h4>
<a href="/post/2018/04/pseudocode/">Death to pseudocode?</a>
</h4>
Clean code, pseudocode or real code?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/java"><kbd class="item-tag">java</kbd></a>
<a href="https://brainbaking.com/tags/functional-programming"><kbd class="item-tag">functional programming</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Mar</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">25</span>
<div class="list-title">
<h4>
<a href="/post/serendipitous-creativity/">Concentrating on serendipitous creativity</a>
</h4>
Focused or collaborative attention?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/collaboration"><kbd class="item-tag">collaboration</kbd></a>
<a href="https://brainbaking.com/tags/concentration"><kbd class="item-tag">concentration</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Feb</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">26</span>
<div class="list-title">
<h4>
<a href="/post/2018/02/hiding-complexity/">Hiding Code Complexity</a>
</h4>
Do make it easy to read. Don&#39;t expose inner workings.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/domain-driven-design"><kbd class="item-tag">domain driven design</kbd></a>
</div>
</li>
<li>
<span class="list-date">16</span>
<div class="list-title">
<h4>
<a href="/post/take-your-time/">Take your time.</a>
</h4>
Stop rushing. Start watching.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/journaling"><kbd class="item-tag">journaling</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Jan</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">27</span>
<div class="list-title">
<h4>
<a href="/post/2018/01/2017-in-books/">2017 in books</a>
</h4>
Pattern recognition in books
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/journaling"><kbd class="item-tag">journaling</kbd></a>
<a href="https://brainbaking.com/tags/reading"><kbd class="item-tag">reading</kbd></a>
</div>
</li>
</ul>
</article>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Archive by year: 2019</title>
<link>https://brainbaking.com/post/2019/</link>
<comments>https://brainbaking.com/post/2019/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2019/</guid>
<description>
<![CDATA[
Not finding what you're looking for? <a href="/tags">Browse the archives</a>.
<div class="list">
<h2>2019</h2>
<h3>Dec</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">02</span>
<div class="list-title">
<h4>
<a href="/post/2019/12/over-onmiddellijke-voldoening/">Over Onmiddellijke Voldoening</a>
</h4>
Het ik-MOET-het-nu-hebben gevoel zijn zin geven
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
</div>
</li>
</ul>
</article>
<h3>Oct</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">08</span>
<div class="list-title">
<h4>
<a href="/post/2019/10/creative-cognitive-processes/">Programming: a Creative Cognitive Process</a>
</h4>
Mapping creativity models to software development
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/creativity"><kbd class="item-tag">creativity</kbd></a>
<a href="https://brainbaking.com/tags/phd"><kbd class="item-tag">phd</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Sep</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">23</span>
<div class="list-title">
<h4>
<a href="/post/2019/09/de-zin-en-onzin-van-conferenties/">De zin en onzin van conferenties</a>
</h4>
Een verspilling van tijd en middelen, of juist niet?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/conference"><kbd class="item-tag">conference</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Apr</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">15</span>
<div class="list-title">
<h4>
<a href="/post/2019/04/teaching-oo-with-gba/">Teaching Object-Oriented design using the GBA</a>
</h4>
C&#43;&#43; and a GBA engine. Let&#39;s learn to create a game!
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/teaching"><kbd class="item-tag">teaching</kbd></a>
<a href="https://brainbaking.com/tags/gba"><kbd class="item-tag">gba</kbd></a>
<a href="https://brainbaking.com/tags/c&#43;&#43;"><kbd class="item-tag">C&#43;&#43;</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Feb</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">05</span>
<div class="list-title">
<h4>
<a href="/post/2019/02/competences-and-certificates/">IT Competences and Certificates</a>
</h4>
A dark and murky path to tread
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/competences"><kbd class="item-tag">competences</kbd></a>
<a href="https://brainbaking.com/tags/certificates"><kbd class="item-tag">certificates</kbd></a>
<a href="https://brainbaking.com/tags/phd"><kbd class="item-tag">phd</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Jan</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">03</span>
<div class="list-title">
<h4>
<a href="/post/2019/01/phd-iteration-2/">A Ph.D. Thesis: Iteration 2</a>
</h4>
On Mastering Lean Skills in Software Engineering Education
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/phd"><kbd class="item-tag">phd</kbd></a>
</div>
</li>
</ul>
</article>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Archive by year: 2020</title>
<link>https://brainbaking.com/post/2020/</link>
<comments>https://brainbaking.com/post/2020/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/</guid>
<description>
<![CDATA[
Not finding what you're looking for? <a href="/tags">Browse the archives</a>.
<div class="list">
<h2>2020</h2>
<h3>Dec</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">27</span>
<div class="list-title">
<h4>
<a href="/post/2020/12/developing-on-apple-m1-silicon/">Programming on the Apple M1 Silicon</a>
</h4>
Is early adoption a good idea as a software developer?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/apple"><kbd class="item-tag">apple</kbd></a>
<a href="https://brainbaking.com/tags/macbook-air"><kbd class="item-tag">macbook air</kbd></a>
</div>
</li>
<li>
<span class="list-date">20</span>
<div class="list-title">
<h4>
<a href="/post/2020/12/thoughts-on-bullshit-jobs/">Thoughts on Bullshit Jobs</a>
</h4>
Remarks on David Graeber&#39;s 2013 Work Rant
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/jobs"><kbd class="item-tag">jobs</kbd></a>
<a href="https://brainbaking.com/tags/academia"><kbd class="item-tag">academia</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Nov</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">24</span>
<div class="list-title">
<h4>
<a href="/post/2020/11/win98-upgrade-sound-blaster-audigy/">Win98 Upgrade: Sound Blaster Audigy</a>
</h4>
From a Cheap PCI128 To EAX Advanced HD
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/soundblaster"><kbd class="item-tag">soundblaster</kbd></a>
<a href="https://brainbaking.com/tags/win98"><kbd class="item-tag">win98</kbd></a>
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
<li>
<span class="list-date">19</span>
<div class="list-title">
<h4>
<a href="/post/2020/11/the-internet-killed-secrets-in-games/">The Internet Killed Secrets in Games</a>
</h4>
What&#39;s the &#39;secret&#39; of the secret cow level in Diablo II?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
</div>
</li>
<li>
<span class="list-date">08</span>
<div class="list-title">
<h4>
<a href="/post/2020/11/winxp-upgrade-sound-blaster-xfi/">WinXP Upgrade: Sound Blaster X-Fi</a>
</h4>
From Embedded Realtek To EAX 5 Blasting Sound
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/soundblaster"><kbd class="item-tag">soundblaster</kbd></a>
<a href="https://brainbaking.com/tags/winxp"><kbd class="item-tag">winxp</kbd></a>
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2020/11/desktop-screenshots-of-olde/">Personal Desktop Screenshots of Olde</a>
</h4>
The result of HDD Treasure diving
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/software">software</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/linux"><kbd class="item-tag">linux</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Oct</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">25</span>
<div class="list-title">
<h4>
<a href="/post/2020/10/building-a-core2duo-winxp-retro-pc/">Building a Core2Duo Windows XP Retro PC</a>
</h4>
Gaming from UT2004 to (almost) The Witcher 2!
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/winxp"><kbd class="item-tag">winxp</kbd></a>
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
<li>
<span class="list-date">17</span>
<div class="list-title">
<h4>
<a href="/post/2020/10/building-an-athlon-win98-retro-pc/">Building an Athlon Windows 98 Retro PC</a>
</h4>
Gaming from Quake to Quake III: Arena!
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/win98"><kbd class="item-tag">win98</kbd></a>
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
<li>
<span class="list-date">04</span>
<div class="list-title">
<h4>
<a href="/post/2020/10/a-personal-journey-through-the-history-of-webdesign/">A journey through the history of webdesign</a>
</h4>
Using personal websites and the Internet Archive
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/webdesign">webdesign</a>
&nbsp;
</div>
</li>
</ul>
</article>
<h3>Sep</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">26</span>
<div class="list-title">
<h4>
<a href="/post/2020/09/486-performance-analysis/">An am486 Performance Analysis</a>
</h4>
DX-40 VS DX2-66. What&#39;s it like, pressing that Turbo button?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/486"><kbd class="item-tag">486</kbd></a>
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
<li>
<span class="list-date">23</span>
<div class="list-title">
<h4>
<a href="/post/2020/09/486-upgrade-sd-hdd/">486 Upgrade 2: The SD Card HDD</a>
</h4>
Getting tired of loud hard drives? Here&#39;s a flash solution.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/486"><kbd class="item-tag">486</kbd></a>
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
<li>
<span class="list-date">18</span>
<div class="list-title">
<h4>
<a href="/post/2020/09/486-upgrade-sound-blaster/">486 Upgrade 1: Sound Blaster 16</a>
</h4>
A Classic ISA sound card, including MIDI daughter board!
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/soundblaster"><kbd class="item-tag">soundblaster</kbd></a>
<a href="https://brainbaking.com/tags/486"><kbd class="item-tag">486</kbd></a>
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
<li>
<span class="list-date">03</span>
<div class="list-title">
<h4>
<a href="/post/2020/09/reviving-a-80486/">Reviving an old 80486 PC</a>
</h4>
27 years later, does it still work?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/486"><kbd class="item-tag">486</kbd></a>
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Aug</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">14</span>
<div class="list-title">
<h4>
<a href="/post/2020/08/education-and-collaboration/">Thoughts on collaboration in education</a>
</h4>
One of the most social and isolating professions?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/collaboration"><kbd class="item-tag">collaboration</kbd></a>
<a href="https://brainbaking.com/tags/teaching"><kbd class="item-tag">teaching</kbd></a>
<a href="https://brainbaking.com/tags/agile"><kbd class="item-tag">agile</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Jul</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">21</span>
<div class="list-title">
<h4>
<a href="/post/2020/07/3d-software-rendering-on-gba/">3D Software Rendering on the GBA</a>
</h4>
Game Boy Advance Fixed-point math, here we come...
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/gba"><kbd class="item-tag">gba</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Jun</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">22</span>
<div class="list-title">
<h4>
<a href="/post/2020/06/iticse-2020/">ITiCSE 2020: A Report</a>
</h4>
Findings from the first Virtual SIGCSE Conference
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/conference"><kbd class="item-tag">conference</kbd></a>
</div>
</li>
<li>
<span class="list-date">16</span>
<div class="list-title">
<h4>
<a href="/post/2020/06/about-perseverance/">Project Warlock: About Perseverance</a>
</h4>
What happens when a game developer maintains his stubbornness.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/games"><kbd class="item-tag">games</kbd></a>
</div>
</li>
<li>
<span class="list-date">11</span>
<div class="list-title">
<h4>
<a href="/post/2020/06/combining-async-with-generators-in-node/">Combining async with generators in Node 11</a>
</h4>
Feel like blowing up your colleagues heads? Use async function*!
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/javascript"><kbd class="item-tag">javascript</kbd></a>
<a href="https://brainbaking.com/tags/node"><kbd class="item-tag">node</kbd></a>
</div>
</li>
<li>
<span class="list-date">04</span>
<div class="list-title">
<h4>
<a href="/post/2020/06/designing-with-accessibility-in-mind/">Designing websites with accessibility in mind</a>
</h4>
A little bit of effort makes your site more inclusive for everyone.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/webdesign">webdesign</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/accessibility"><kbd class="item-tag">accessibility</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2020/06/tracking-and-privacy-on-websites/">Tracking and privacy concerns on websites</a>
</h4>
I redesigned Brain Baking to get rid of trackers!
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/webdesign">webdesign</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/privacy"><kbd class="item-tag">privacy</kbd></a>
</div>
</li>
</ul>
</article>
<h3>May</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">26</span>
<div class="list-title">
<h4>
<a href="/post/2020/05/page-building-with-brizy-in-wordpress/">Page Building with Brizy in Wordpress</a>
</h4>
Shortcodes and custom hacks incoming...
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/webdesign">webdesign</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/php"><kbd class="item-tag">php</kbd></a>
<a href="https://brainbaking.com/tags/wordpress"><kbd class="item-tag">wordpress</kbd></a>
<a href="https://brainbaking.com/tags/brizy"><kbd class="item-tag">brizy</kbd></a>
</div>
</li>
<li>
<span class="list-date">15</span>
<div class="list-title">
<h4>
<a href="/post/2020/05/hugo-extended/">Hugo Extended: More static site processing power!</a>
</h4>
Sass, Transpiling, Search functionality - what&#39;s not to like?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/webdesign">webdesign</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/hugo"><kbd class="item-tag">hugo</kbd></a>
<a href="https://brainbaking.com/tags/babel"><kbd class="item-tag">babel</kbd></a>
<a href="https://brainbaking.com/tags/sass"><kbd class="item-tag">sass</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2020/05/using-pandoc/">Using Pandoc to publish a book</a>
</h4>
Successfully combining writing and LaTeX skills
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/software">software</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/publishing"><kbd class="item-tag">publishing</kbd></a>
<a href="https://brainbaking.com/tags/book"><kbd class="item-tag">book</kbd></a>
<a href="https://brainbaking.com/tags/pandoc"><kbd class="item-tag">pandoc</kbd></a>
<a href="https://brainbaking.com/tags/markdown"><kbd class="item-tag">markdown</kbd></a>
<a href="https://brainbaking.com/tags/latex"><kbd class="item-tag">latex</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Apr</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">13</span>
<div class="list-title">
<h4>
<a href="/post/2020/04/vps/">DIY: Hosting stuff on your own VPS</a>
</h4>
Migrating to, securing, and backing up your own server.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/webdesign">webdesign</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/server"><kbd class="item-tag">server</kbd></a>
<a href="https://brainbaking.com/tags/linux"><kbd class="item-tag">linux</kbd></a>
<a href="https://brainbaking.com/tags/vps"><kbd class="item-tag">vps</kbd></a>
<a href="https://brainbaking.com/tags/security"><kbd class="item-tag">security</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Feb</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">25</span>
<div class="list-title">
<h4>
<a href="/post/2020/02/agile-academia/">Five reasons why agile and academia don&#39;t go together</a>
</h4>
Iterative methods in the academic world? Nope.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/education">education</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/agile"><kbd class="item-tag">agile</kbd></a>
<a href="https://brainbaking.com/tags/academia"><kbd class="item-tag">academia</kbd></a>
<a href="https://brainbaking.com/tags/development"><kbd class="item-tag">development</kbd></a>
</div>
</li>
</ul>
</article>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Archive by year: 2021</title>
<link>https://brainbaking.com/post/2021/</link>
<comments>https://brainbaking.com/post/2021/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2021/</guid>
<description>
<![CDATA[
Not finding what you're looking for? <a href="/tags">Browse the archives</a>.
<div class="list">
<h2>2021</h2>
<h3>Mar</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">11</span>
<div class="list-title">
<h4>
<a href="/post/2021/03/always-have-a-disaster-recovery-plan/">Always have a Diaster Recovery Plan</a>
</h4>
One OVH data center was destroyed by fire last night
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/vps"><kbd class="item-tag">vps</kbd></a>
</div>
</li>
<li>
<span class="list-date">09</span>
<div class="list-title">
<h4>
<a href="/post/2021/03/the-indieweb-mixed-bag/">The IndieWeb Mixed Bag</a>
</h4>
Thoughts about the (d)evolution of blog interactions
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/webdesign">webdesign</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/privacy"><kbd class="item-tag">privacy</kbd></a>
<a href="https://brainbaking.com/tags/accessibility"><kbd class="item-tag">accessibility</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2021/03/getting-rid-of-tracking-using-lineageos/">Getting rid of trackers using LineageOS</a>
</h4>
Exit Google. Enter Life.
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/privacy"><kbd class="item-tag">privacy</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Feb</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">21</span>
<div class="list-title">
<h4>
<a href="/post/2021/02/the-insanity-of-retro-game-collecting/">The insanity of collecting retro games</a>
</h4>
Is a physical collection really worth it?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
<a href="https://brainbaking.com/tags/games"><kbd class="item-tag">games</kbd></a>
</div>
</li>
<li>
<span class="list-date">14</span>
<div class="list-title">
<h4>
<a href="/post/2021/02/writing-academic-papers-in-markdown/">How to write academic papers in Markdown</a>
</h4>
Tired of that silly LaTeX syntax?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/software">software</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/publishing"><kbd class="item-tag">publishing</kbd></a>
<a href="https://brainbaking.com/tags/pandoc"><kbd class="item-tag">pandoc</kbd></a>
<a href="https://brainbaking.com/tags/markdown"><kbd class="item-tag">Markdown</kbd></a>
<a href="https://brainbaking.com/tags/latex"><kbd class="item-tag">latex</kbd></a>
</div>
</li>
<li>
<span class="list-date">09</span>
<div class="list-title">
<h4>
<a href="/post/2021/02/you-shouldnt-use-spotify/">You Shouldn&#39;t Use Spotify</a>
</h4>
Why do creators earn so little without actions of consumers?
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/braindump">braindump</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/music"><kbd class="item-tag">music</kbd></a>
</div>
</li>
<li>
<span class="list-date">02</span>
<div class="list-title">
<h4>
<a href="/post/2021/02/my-retro-desktop-setup/">My Retro Desk/Gaming Setup in 2021</a>
</h4>
A peaceful co-existence of old and new
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
</ul>
</article>
<h3>Jan</h3>
<article>
<ul class="list-ul">
<li>
<span class="list-date">28</span>
<div class="list-title">
<h4>
<a href="/post/2021/01/win98-upgrade-geforce3/">Win98 Upgrade: GeForce 3 Ti200 vs Riva TNT2</a>
</h4>
Get more out of that AGPx4 slot!
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/hardware">hardware</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/geforce"><kbd class="item-tag">geforce</kbd></a>
<a href="https://brainbaking.com/tags/win98"><kbd class="item-tag">win98</kbd></a>
<a href="https://brainbaking.com/tags/retro"><kbd class="item-tag">retro</kbd></a>
</div>
</li>
<li>
<span class="list-date">20</span>
<div class="list-title">
<h4>
<a href="/post/2021/01/what-is-creativity-in-software-engineering/">What is Creativity in Software Engineering?</a>
</h4>
A Focus Group of Creative Programmers
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/creativity"><kbd class="item-tag">creativity</kbd></a>
<a href="https://brainbaking.com/tags/phd"><kbd class="item-tag">phd</kbd></a>
</div>
</li>
<li>
<span class="list-date">13</span>
<div class="list-title">
<h4>
<a href="/post/2021/01/the-productive-programmer-on-mac/">The Productive Programmer on Mac</a>
</h4>
A tribute to the ideas of Neal Ford
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/programming">programming</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/productivity"><kbd class="item-tag">productivity</kbd></a>
</div>
</li>
<li>
<span class="list-date">05</span>
<div class="list-title">
<h4>
<a href="/post/2021/01/hugo-rss-feeds-and-lazy-image-loading/">RSS Feeds, Hugo, and Lazy Image Loading</a>
</h4>
Where&#39;s my content? It&#39;s a tarp!
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/webdesign">webdesign</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/hugo"><kbd class="item-tag">hugo</kbd></a>
<a href="https://brainbaking.com/tags/rss"><kbd class="item-tag">rss</kbd></a>
</div>
</li>
<li>
<span class="list-date">01</span>
<div class="list-title">
<h4>
<a href="/post/2021/01/digitizing-journals-using-devonthink/">Digitizing journals using DEVONthink</a>
</h4>
Migrating from Evernote to a secure and decentralized solution
</div>
<div class="list-tags">
<svg class='icon icon-text icon-gray'><use xlink:href="#folder"></use></svg>
<a href="https://brainbaking.com/categories/learning">learning</a>
&nbsp;
<svg class='icon icon-text icon-gray'><use xlink:href="#tag"></use></svg>&nbsp;
<a href="https://brainbaking.com/tags/journaling"><kbd class="item-tag">journaling</kbd></a>
<a href="https://brainbaking.com/tags/privacy"><kbd class="item-tag">privacy</kbd></a>
</div>
</li>
</ul>
</article>
</div>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Hi, Im Wouter Groeneveld</title>
<link>https://brainbaking.com/about/</link>
<comments>https://brainbaking.com/about/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/about/</guid>
<description>
<![CDATA[
<p>
<img align="left" hspace="5" src="https://brainbaking.com/bigimg/About%20Me.jpg"/>
</p>
<h2 id="-baker">&hellip; Baker</h2>
<ul>
<li>I hold a <a href="/post/learning-to-become-a-baker/">professional bread baker&rsquo;s degree</a> so naturally I love to think of myself as a real baker. I highly respect the craft and enjoy kneading dough with my hands.</li>
<li>I specialize in <em>sourdough bread</em>, as you can read at my <a href="https://redzuurdesem.be">bread baking blog</a>. I love to rekindle the interest in sourdough by organizing workshops.</li>
<li>I&rsquo;ve written a book on <a href="https://redzuurdesem.be/het-boek">the science of sourdough bread</a>.</li>
</ul>
<h2 id="-researcher">&hellip; Researcher</h2>
<ul>
<li>I am a PhD researcher at the <a href="https://iiw.kuleuven.be/english">Faculty of Engineering Technology</a>, KU Leuven.</li>
<li>My <a href="/projects#research">academic research</a> focuses on identifying and amplifying non-technical skills in software engineering education, primarily targetting <em>creative problem solving</em>.</li>
<li>I mainly employ qualitative methods and prefer to mix disciplines such as computing education, cognitive psychology, and architecture.</li>
</ul>
<h2 id="-programmer">&hellip; Programmer</h2>
<ul>
<li>I&rsquo;m an experienced software engineer and took on various roles from agile coaching to technical lead. I hold a Master of Computer Science from <a href="https://www.uhasselt.be/edm">Hasselt Univeristy</a>. Take a look at my <a href="https://github.com/wgroeneveld"><svg class='icon'><use xlink:href='#github'></use></svg>Github account</a>.</li>
<li>Im a heavy Test Driven Development fan and I bark at those who dont. I taught agile software engineering techniques in both industry and academia.</li>
<li>I dislike specializing in one particular programming language: the more there is to learn, the better, although I prefer dynamic languages.</li>
</ul>
<h2 id="-writer">&hellip; Writer</h2>
<ul>
<li>I&rsquo;m a <a href="/post/fountain-pens-first-look/">fountain pen addict</a> and avid <a href="/post/journaling-in-practice/"><svg class='icon icon-text'><use xlink:href='#book'></use></svg>journaler</a>. I love jotting down stuff.</li>
<li><a href="/post">This blog</a> is the ideal place to write down my <em>freshly baked thoughts</em> about virtually anything, primarily intended to amuse myself, and hopefully also others.</li>
<li>Oh, and as said, I&rsquo;ve published a book on <a href="https://redzuurdesem.be/het-boek">the science of sourdough bread</a> and occasionally take part in <a href="https://nanowrimo.org">National Novel Writing Months</a> - with varying results.</li>
</ul>
<h2 id="-teacher">&hellip; Teacher</h2>
<ul>
<li>Transforming knowledge into well-digestible material is my mission. As they say: <em>the best way to learn something is to teach it</em> - I couldn&rsquo;t agree more.</li>
<li>Besides various formal <a href="/projects#teaching">teaching assignments</a> at KU Leuven, I&rsquo;ve also coached software developers in different companies, and occasionally organize bread baking workshops.</li>
</ul>
<hr>
<a href='https://ko-fi.com/woutergroeneveld' class='inmargin'>
<img height='36' style='border:0px !important;height:36px;' src='/img/kofi.png' border='0' alt='Buy Me a Coffee' />
</a>
<p>If you found my work amusing and/or helpful, you can <a href="https://ko-fi.com/woutergroeneveld">buy me a coffee</a> - if you don&rsquo;t mind I&rsquo;ll use it to drink a cup of tea instead. I also like to hear your feedback via:</p>
<ul>
<li><svg class='icon icon-text'><use xlink:href='#discuss'></use></svg>Mastodon: <a href="https://chat.brainbaking.com/@wouter">@wouter@chat.brainbaking.com</a></li>
<li><svg class='icon icon-text'><use xlink:href='#mail'></use></svg>(encrypted) e-mail: <span class="link meel">say hello</span>.</li>
</ul>
<noscript>
JavaScript is disabled. I use it to obfuscate my e-mail, keeping spambots at bay. <br/>
Reach me using: <code>[firstname] at [this-domain] dot [you-know]</code>.
</noscript>
<p>Thanks!</p>
<hr>
<h2 id="whats-a-_multiclass_">What&rsquo;s a <em>multiclass</em>?</h2>
<p><a href="https://en.wikipedia.org/wiki/Character_class_(Dungeons_%26_Dragons)#Multiclassing">Multiclassing</a> in Dungeons &amp; Dragons (yes, I&rsquo;m also a nerd) allows your character to advance in more than one class. Instead of playing as the conventional mage or fighter, you can be both. This concept neatly summarizes my vision of a profession.</p>
<p>There are multiple concepts all defining the same thing:</p>
<ul>
<li>Emilie Wapnick uses the term <a href="https://puttylike.com/terminology/">multipotentialite</a>. A multipotentialite is <em>someone with many interests and creative pursuits</em>.</li>
<li>Philosopher Johann von Wowern wrote in 1603 about <a href="https://en.wikipedia.org/wiki/Polymath"><em>polymaths</em></a>: <em>knowledge of various matters, drawn from all kinds of studies [&hellip;] ranging freely through all the fields of the disciplines, as far as the human mind, with unwearied industry, is able to pursue them</em>.</li>
<li>Another lovely term is <em>renaissance men</em>: <em>a person with many talents or areas of knowledge</em>. Da Vinci is the prime example of such a man. Of course I couldn&rsquo;t possibly live up to these expectations. The notion of a <a href="https://it.wikipedia.org/wiki/Uomo_universale">homo universalis</a> might also be stretching it a bit too far.</li>
</ul>
<p>I used to be only good at programming because I thought, as a Computer Scientist, you specialize instead of generalize. But the more I worked with computers, the more my hands itched to do something else. So nowadays I love to go wide and pass on that enthusiasm for knowledge on any level.</p>
<hr>
<h2 id="where-good-ideas-come-from-books">Where good ideas come from: books</h2>
<p>I keep an active <a href="https://www.goodreads.com/user/show/5451893-wouter" target="_blank"><svg class='icon'><use xlink:href='#goodreads'></use></svg>Goodreads</a> account where I manage everything I&rsquo;ve read and want to read. I invite you to join the community there. Marking a book as read and writing a (short) review never was that satisfying&hellip;</p>
<p>I used to be almost exclusively a fantasy reader. Now I mostly read non-fiction on the most diverse topics, but I do have a soft spot for things like philosophy, art, mindful food and software engineering.</p>
<p>These are the latest 12 books I&rsquo;ve read:</p>
</main>
<div id="gr_grid_widget_1496758344" class="goodreadswidget">
</div>
<script src="/js/goodreads.js" type="text/javascript" charset="utf-8"></script>
<main>
<p style="clear: both;">&nbsp;</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>No copyright - No Tracking</title>
<link>https://brainbaking.com/no-copyright-no-tracking/</link>
<comments>https://brainbaking.com/no-copyright-no-tracking/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/no-copyright-no-tracking/</guid>
<description>
<![CDATA[
<h2 id="no-copyright">No Copyright</h2>
<p>Inspired by Leo Babauta&rsquo;s <a href="https://mnmlist.com/uncopyright-and-a-minimalist-mindset/">&ldquo;uncopyright and the minimalist mindset&rdquo;</a>, I decided to apply this to my own website.</p>
<p>I&rsquo;ve always detested the <em>&lsquo;this is mine!'</em>-mindset, especially when it comes to intellectual property. Everyone benefits if everything is open and everyone can build upon each other&rsquo;s work. A possible financial loss is not an excuse. Leo has found copyrights not to be particularly helpful, so he simply got rid of them. He sells thousands of ebooks monthly. You have the right to share them with friends. He would rather have you buy them, but this way his work reaches a broader audience.</p>
<p>The source of this website is available at my Brain Baking <a href="https://github.com/wgroeneveld/brainbaking"><svg class='icon'><use xlink:href='#github'></use></svg>Github repository</a>. Feel free to do with it whatever you want: copy excerpts, republish images, use code partials, rip the theme, &hellip; There&rsquo;s a reason the repository is <strong>public</strong>.</p>
<blockquote>
<p>Love only grows by sharing. You can only have more for yourself by giving it away to others. <span>Brian Tracy</span></p>
</blockquote>
<p>Of course I would be really grateful if you would still attribute Brain Baking as the source of your used material. However, I do not want to oblige you to do so using a confusing Creative Commons licence.</p>
<h2 id="no-tracking">No Tracking</h2>
<p>Who doesn&rsquo;t like cookies? I&rsquo;m <a href="https://redzuurdesem.be/">a baker</a> - I would know. Well, I don&rsquo;t like cookies on websites, because they rise privacy concerns. That is why, inspired by <a href="https://laurakalbag.com/i-dont-track-you/">Laura Kalbag&rsquo;s &ldquo;I don&rsquo;t track you&rdquo;</a> philosophy, I do everything I can to <em>not</em> track you, but to track <strong>traffic</strong> instead.</p>
<p>I achieved this by ditching Google Analytics and hosting third-party libraries myself. So <em>rest assured</em>, Google does not know you were here! Instead, I use <a href="https://www.goatcounter.com">GoatCounter</a>, a simple and privacy-focused analytics system that is self-hosted. It does <em>not</em> require any cookie and runs on my own SSL-verified domain.</p>
<p>There is no commenting system anymore. One less thing to be worried about. Simply reply via e-mail or Mastodon instead. There are no YouTube-embedded videos that come with free tracking cookies.</p>
<p>Read more about how tracking works in <a href="/post/2020/06/tracking-and-privacy-on-websites/">this blog post</a>.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Screen aspect ratios and DOS Games</title>
<link>https://brainbaking.com/post/2020/10/dos-aspect-ratios/</link>
<comments>https://brainbaking.com/post/2020/10/dos-aspect-ratios/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/post/2020/10/dos-aspect-ratios/</guid>
<description>
<![CDATA[
<p>Links:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=YvckyWxHAIw">Displaced Gamers YouTube video</a></li>
<li><a href="https://www.vogons.org/viewtopic.php?f=46&amp;t=44877&amp;start=20">LCD Monitor compatibility DB</a> (<a href="https://www.vogons.org/viewtopic.php?f=46&amp;t=39136&amp;hilit=widescreen%2Bresolution&amp;page=8&amp;per_page=20">more</a>)</li>
<li><a href="https://videogameperfection.com/products/open-source-scan-converter/">Open Source Scan Converter</a> (OSSC)</li>
<li><a href="https://www.startech.com/fr-fr/audio-video-products/vsedidhd">EDID VGA/DVI Emulators</a></li>
</ul>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Search</title>
<link>https://brainbaking.com/search/</link>
<comments>https://brainbaking.com/search/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/search/</guid>
<description>
<![CDATA[
<p>Not finding what youre looking for? Try your luck here.</p>
<p>Use <code>*</code> to partially match terms.</p>
<article>
<form method="get" action="" class="search-form">
<input id="zoekentxt" placeholder="philosophy" aria-label="Search terms" name="q" type="text" style="width: 56%" />
<button type="submit" class="button" style="width: 36%">Search!</button>
</form>
</article>
<div id="resultaten">
<hr/>
<h2>
Search results
<span class="pages"></span> &raquo;
</h2>
<div id="searchapp">Searching, please wait... </div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>
<script src="/js/lunr.min.js"></script>
<script>
window.searchposts = JSON.parse(
"[{\"content\":\"@celia @kev I have read both you and Kev\\u0026rsquo;s post on this and agree on some points indeed! But I\\u0026rsquo;m not yet ready to give up webmentions. As an academic, the idea of citing/mentioning each ot\",\"link\":\"/notes/2021/03/16h17m07s14/\",\"title\":\"@celia @kev I have read both you and Kev's post on...\"},{\"content\":\"@robert @kev @celia I run an instance-of-one Pleroma server and ps tells me it\\u0026rsquo;s using 8% of the 2GB RAM (postgres takes up even less). Also happy with the clean Soapbox UI. If you\\u0026rsquo;re alre\",\"link\":\"/notes/2021/03/16h12m38s27/\",\"title\":\"@robert @kev @celia I run an instance-of-one Plero...\"},{\"content\":\"So, we rewrote our CS courses in Markdown. I\\u0026rsquo;m looking for ways to make things more interactive for students, e.g. by embedding replit.com snippets. However, I dont\\u0026rsquo;t want to create 34235 \",\"link\":\"/notes/2021/03/15h14m43s49/\",\"title\":\"So, we rewrote our CS courses in Markdown. I'm loo...\"},{\"content\":\"Enjoyed an afternoon of oldskool Diablo II on the Europebattle servers. We did a few Mephisto runs, managed to hit Hell, and I re-converetd my druid into a windy one. Good times!\\n \",\"link\":\"/notes/2021/03/14h17m41s53/\",\"title\":\"Enjoyed an afternoon of oldskool Diablo II on the ...\"},{\"content\":\"@rsolva whoops overlooked the word \\u0026lsquo;native\\u0026rsquo;.Well, all I can say is: it works!\\n\",\"link\":\"/notes/2021/03/13h12m44s29/\",\"title\":\"@rsolva whoops overlooked the word 'native'.Well, ...\"},{\"content\":\"@rsolva that\\u0026rsquo;s a lie indeed 😁 see https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/ I use davx5 and it works flawlessly\\n\",\"link\":\"/notes/2021/03/13h09m58s25/\",\"title\":\"@rsolva that's a lie indeed 😁 see https://brainba...\"},{\"content\":\"@rsolva @aral @laura Great incentive Ruben, I chimed in and also became a backer! Loving what you guys do. Hopefully the latest video will be online shortly, I missed the live stream.\\n\",\"link\":\"/notes/2021/03/12h19m17s26/\",\"title\":\"@rsolva @aral @laura Great incentive Ruben, I chim...\"},{\"content\":\"Great, I can ditch lazysizes.js! Didn\\u0026rsquo;t know about this before: https://web.dev/browser-level-image-lazy-loading/ and browser support is \\u0026ldquo;good enough\\u0026rdquo;: https://caniuse.com/loading-la\",\"link\":\"/notes/2021/03/12h18m06s14/\",\"title\":\"Great, I can ditch lazysizes.js! Didn't know about...\"},{\"content\":\"A relatively quiet Wednesday morning. I wrote a few JS files, fiddled a bit more with my attempts to get Webmentions working. Timeouts appeared. Huh? Check brainbaking.com. No response. Huh? Try to lo\",\"link\":\"/post/2021/03/always-have-a-disaster-recovery-plan/\",\"title\":\"Always have a Diaster Recovery Plan\"},{\"content\":\"@eli_oat a serious fire destroyed the data center of my VPS last night: https://twitter.com/olesovhcom/status/1369478732247932929 - guess what I did NOT backup: my Mastodon instance. What a disaster. \",\"link\":\"/notes/2021/03/10h16m24s22/\",\"title\":\"@eli_oat a serious fire destroyed the data center ...\"},{\"content\":\"I've been fiddling with IndieWeb stuff the last week and all in all, I think it's a mixed bag: https://brainbaking.com/post/2021/03/the-indieweb-mixed-bag/\\n@kev after I published it, I found out your \",\"link\":\"/notes/2021/03/09h15m17s30/\",\"title\":\"I\\u0026#39;ve been fiddling with IndieWeb stuff the last week and all in all, I think it\\u0026#39;s a mixed...\"},{\"content\":\"https://forth-standard.org/ - yet another programming language I need to take a look at? That list is becoming ridiculously long\\u0026hellip;\\n\",\"link\":\"/notes/2021/03/09h08m09s04/\",\"title\":\"https://forth-standard.org/ - yet another programming language I need to take a look at? That lis...\"},{\"content\":\"It\\u0026rsquo;s that time again: I started fiddling with my blog code - for the nth time. Kev Quirk calls it pissing around with the code. That was meant negatively, and one of the reasons for him to switc\",\"link\":\"/post/2021/03/the-indieweb-mixed-bag/\",\"title\":\"The IndieWeb Mixed Bag\"},{\"content\":\"I just learned about https://www.inklestudios.com/ink/ a scripting language used in story-heavy adventurelite games such as Heaven's Vault. It reminds me of a mention of http://www.squirrel-lang.org/ \",\"link\":\"/notes/2021/03/06h12m41s48/\",\"title\":\"I just learned about https://www.inklestudios.com/ink/ a scripting language used in story-heavy a...\"},{\"content\":\"I spent some time with Yarn/Jest/ES2019, it felt good to be programming again. I am developing a serious JavaScript FOMO since switching from the software engineering industry to academia, and I'm not\",\"link\":\"/notes/2021/03/05h08m51s41/\",\"title\":\"I spent some time with Yarn/Jest/ES2019, it felt good to be programming again. I am developing a ...\"},{\"content\":\"@rubenerd out of curiosity: are both synced in any way? If not, are you sure the migraine isnt from checking both walls? 😇\\n\",\"link\":\"/notes/2021/03/04h14m52s55/\",\"title\":\"@rubenerd out of curiosity: are both synced in any way? If not, are you sure the migraine isnt fr...\"},{\"content\":\"Dog-walk thought: how cool would it be if the Nintendo Switch would support publishing screenshots through https://indieweb.org/Micropub ? Instead, I'm left to fiddling with Birdsite to manually https\",\"link\":\"/notes/2021/03/04h08m47s31/\",\"title\":\"Dog-walk thought: how cool would it be if the Nintendo Switch would support publishing screenshot...\"},{\"content\":\"Heads up RSS feed readers of brainbaking.com! Federated half-baked thoughts (https://brainbaking.com/notes/) are now integrated in /index.xml 🤓. Don't like that? Subscribe to /post/index.xml instead! \",\"link\":\"/notes/2021/03/03h16m00s44/\",\"title\":\"Heads up RSS feed readers of brainbaking.com! Federated half-baked thoughts (https://brainbaking....\"},{\"content\":\"@StampedingLonghorn I tried to chase him away, but you know how that turned out\\u0026hellip; 😼 There's even cat hair inside the cases\\u0026hellip; (to be clear: also unintentional)\\n\",\"link\":\"/notes/2021/03/02h17m18s46/\",\"title\":\"@StampedingLonghorn I tried to chase him away, but you know how that turned out... 😼 There\\u0026#39;s ...\"},{\"content\":\"@StampedingLonghorn @256 Don't forget the cleverly hidden Roland MT-32, a majestic piece of pre-MIDI standardized era synthesizer. What else would you use to run Sierra Online games, and monkey1? I re\",\"link\":\"/notes/2021/03/02h17m13s27/\",\"title\":\"@StampedingLonghorn @256 Don\\u0026#39;t forget the cleverly hidden Roland MT-32, a majestic piece of p...\"},{\"content\":\"@aussocialadmin Great! I didn't even know https://joinmobilizon.org/ existed, thanks for sharing! So many superb alternatives. If only the userbase would follow\\u0026hellip;\\n\",\"link\":\"/notes/2021/03/02h13m18s54/\",\"title\":\"@aussocialadmin Great! I didn\\u0026#39;t even know https://joinmobilizon.org/ existed, thanks for shar...\"},{\"content\":\"I pulled the Google plug and installed LineageOS: https://brainbaking.com/post/2021/03/getting-rid-of-tracking-using-lineageos/ Very impressed so far! Also rely on my own CalDAV server to replace GCal\",\"link\":\"/notes/2021/03/01h20m03s35/\",\"title\":\"I pulled the Google plug and installed LineageOS: https://brainbaking.com/post/2021/03/getting-ri...\"},{\"content\":\"Since dipping my toes into the subject of privacy, I kept on exploring more opportunities to take back my own data. This started out quite innocent with a few changes to this site, that evolved into t\",\"link\":\"/post/2021/03/getting-rid-of-tracking-using-lineageos/\",\"title\":\"Getting rid of trackers using LineageOS\"},{\"content\":\"@darth_mall Interesting, did you use Bridgy to convert Mastodon posts into webmentions? Many sites seem to use it, but it of course only scans your own Twitter/Masto feed. IMO, this renders it a bit u\",\"link\":\"/notes/2021/02/28h11m47s37/\",\"title\":\"@darth_mall Interesting, did you use Bridgy to convert Mastodon posts into webmentions? Many site...\"},{\"content\":\"Okay, so sending involves Webmention.app and IFTTT to poll my RSS feed (According to https://www.jayeless.net/2021/02/integrating-webmentions-into-hugo.html). Holy shit. Is it even worth it\\u0026hellip;\\n\",\"link\":\"/notes/2021/02/27h18m00s19/\",\"title\":\"Okay, so sending involves Webmention.app and IFTTT to poll my RSS feed (According to https://www....\"},{\"content\":\"Trying to wrap my mind around WebMentions and how I could implement them without resorting to a third-party provider\\u0026hellip; https://sebastiandedeyne.com/adding-webmentions-to-my-blog/ I wonder if a l\",\"link\":\"/notes/2021/02/27h17m51s39/\",\"title\":\"Trying to wrap my mind around WebMentions and how I could implement them without resorting to a t...\"},{\"content\":\"Has anyone else noticed posted links on Twitter get re-encoded into t.co URLs in order to gather even more 'insight' data? That said, I'm having trouble finding anyone on the Fediverse\\u0026hellip; Any hin\",\"link\":\"/notes/2021/02/27h14m25s16/\",\"title\":\"Has anyone else noticed posted links on Twitter get re-encoded into t.co URLs in order to gather ...\"},{\"content\":\"@laura It did more than helping! I'm slowly but surely taking back my data. Started with Evernote -\\u0026gt; DEVONThink, got to Gmail -\\u0026gt; ProtonMail, and now to Android -\\u0026gt; LineageOS. All your fault 😂\\n\",\"link\":\"/notes/2021/02/26h19m55s59/\",\"title\":\"@laura It did more than helping! I\\u0026#39;m slowly but surely taking back my data. Started with Ever...\"},{\"content\":\"Just saying hi @kogakure 👋 getting my feet wet with decentralized “tooting” (although I opted for Pleroma, less drama to install in my own VPS it seemed)\\n\",\"link\":\"/notes/2021/02/26h13m48s06/\",\"title\":\"Just saying hi @kogakure 👋 getting my feet wet with decentralized “tooting” (although I opted for...\"},{\"content\":\"Hi @laura thanks to your https://laurakalbag.com/what-is-mastodon-and-why-should-i-use-it/ I dipped my toes into decentralized social networks 😅 FYI The “Whats wrong with Twitter” link on there is br\",\"link\":\"/notes/2021/02/26h13m08s52/\",\"title\":\"Hi @laura thanks to your https://laurakalbag.com/what-is-mastodon-and-why-should-i-use-it/ I dipp...\"},{\"content\":\"@rubenerd just installed my own Pleroma server to say hi! Big fan of your micro-blog for ages here.\\n\",\"link\":\"/notes/2021/02/26h13m04s14/\",\"title\":\"@rubenerd just installed my own Pleroma server to say hi! Big fan of your micro-blog for ages here.\"},{\"content\":\"When I posted my retro 2021 desktop setup at the beginning of this month, I unintentionally left out a photo of my SNES/Game Boy/whatever physical cartridge collection. You can marvel at my very limit\",\"link\":\"/post/2021/02/the-insanity-of-retro-game-collecting/\",\"title\":\"The insanity of collecting retro games\"},{\"content\":\"In 2020, I explained how to use pandoc to publish a book. Essentially, I use the same workflow to write papers in academia. A couple of colleagues asked me how this was done, although they suspected i\",\"link\":\"/post/2021/02/writing-academic-papers-in-markdown/\",\"title\":\"How to write academic papers in Markdown\"},{\"content\":\"Ruben Schade recently posted on his lovely micro-blog Rubenerd that you shouldn\\u0026rsquo;t use Spotify. That was new to me. I\\u0026rsquo;ve been a (paid) Spotify user since 2014, but I honestly never focused \",\"link\":\"/post/2021/02/you-shouldnt-use-spotify/\",\"title\":\"You Shouldn't Use Spotify\"},{\"content\":\"Thanks to my resurgent interest in retro computing, I discovered others' setups and blogs that inspired me to completely rework my home office. Of course, COVID-19 also made sure I invested in better \",\"link\":\"/post/2021/02/my-retro-desktop-setup/\",\"title\":\"My Retro Desk/Gaming Setup in 2021\"},{\"content\":\"After building a Windows 98SE retro PC in October 2020, I\\u0026rsquo;ve upgraded the sound card to a proper SoundBlaster. Yet, little games made use of that capability because my graphics card lagged behin\",\"link\":\"/post/2021/01/win98-upgrade-geforce3/\",\"title\":\"Win98 Upgrade: GeForce 3 Ti200 vs Riva TNT2\"},{\"content\":\"Last month, our paper entitled \\u0026ldquo;Exploring the Role of Creativity in Software Engineering\\u0026rdquo; got accepted for publication in the proceedings of the 43nd International Conference on Software E\",\"link\":\"/post/2021/01/what-is-creativity-in-software-engineering/\",\"title\":\"What is Creativity in Software Engineering?\"},{\"content\":\"In 2010, I attended a Devoxx Conference talk by Neal Ford called \\u0026ldquo;Productive Programming\\u0026rdquo;. Of course, I also bought the accompanying book, published in 2008. Eleven years ago, I also gaine\",\"link\":\"/post/2021/01/the-productive-programmer-on-mac/\",\"title\":\"The Productive Programmer on Mac\"},{\"content\":\"Full RSS Content in Hugo Just a quick one I wanted to get out there in case you are, like me, using Hugo to power a blog. Apparently, in 2017, the default behavior changed from using the .Content to t\",\"link\":\"/post/2021/01/hugo-rss-feeds-and-lazy-image-loading/\",\"title\":\"RSS Feeds, Hugo, and Lazy Image Loading\"},{\"content\":\"In 2017, I wrote a practical guide to keeping a journal, which also contained a digitalizing part involving Evernote. Since then, a few things happened that ultimately made me close my Evernote accoun\",\"link\":\"/post/2021/01/digitizing-journals-using-devonthink/\",\"title\":\"Digitizing journals using DEVONthink\"},{\"content\":\"Ever since I read Kay Singh\\u0026rsquo;s Apple Silicon M1: Black. Magic. Fuckery article, I couldn\\u0026rsquo;t stop wanting one. My 2012 MacBook Air was in need of a replacement, and although still very servic\",\"link\":\"/post/2020/12/developing-on-apple-m1-silicon/\",\"title\":\"Programming on the Apple M1 Silicon\"},{\"content\":\"In 2013, David Graeber, a professor of Anthropology, published an essay on the phenomenon of Bullshit Jobs in Strike! Magazine. This work was further expanded in his 2018 book Bullshit Jobs: A Theory.\",\"link\":\"/post/2020/12/thoughts-on-bullshit-jobs/\",\"title\":\"Thoughts on Bullshit Jobs\"},{\"content\":\"My initial Windows 98SE retro PC build came with a free Ensoniq AudioPCI based card, a cheap 1998 OEM alternative to the AWE64 or the Sound Blaster Live!_ line. The Sound Blaster PCI128 or _Vibra128_ \",\"link\":\"/post/2020/11/win98-upgrade-sound-blaster-audigy/\",\"title\":\"Win98 Upgrade: Sound Blaster Audigy\"},{\"content\":\"After finishing Sacred and planning to replay other nostalgic hack \\u0026amp; slash games, I am currently working my way through 2002\\u0026rsquo;s Dungeon Siege for the second time. Somewhere deep in the crysta\",\"link\":\"/post/2020/11/the-internet-killed-secrets-in-games/\",\"title\":\"The Internet Killed Secrets in Games\"},{\"content\":\"Ever since the \\u0026ldquo;Sound Blaster\\u0026rdquo; brand became iconic in those 486 PCs, I became a big fan of most products Creative brought to the market. Their iconic big boxes that accompanied new sound c\",\"link\":\"/post/2020/11/winxp-upgrade-sound-blaster-xfi/\",\"title\":\"WinXP Upgrade: Sound Blaster X-Fi\"},{\"content\":\"Rummaging through old data is fun. It\\u0026rsquo;s like rediscovering a part of yourself you have long forgotten. Since the last few months I\\u0026rsquo;m in a nostalgic hardware mood, let\\u0026rsquo;s revisit some \",\"link\":\"/post/2020/11/desktop-screenshots-of-olde/\",\"title\":\"Personal Desktop Screenshots of Olde\"},{\"content\":\"Earlier in October, I blogged about building an athlon win98 PC which allowed me to replay Quake 1, 2, and 3 on original hardware. It is time to move on from Windows 98 and take the leap of faith, fro\",\"link\":\"/post/2020/10/building-a-core2duo-winxp-retro-pc/\",\"title\":\"Building a Core2Duo Windows XP Retro PC\"},{\"content\":\"After the previous months' reviving of a 80486 PC, including upgrade 1 and upgrade 2, it is time to revisit the last decent DOS-based Windows operating system: Windows 98 Second Edition. Earlier, I ad\",\"link\":\"/post/2020/10/building-an-athlon-win98-retro-pc/\",\"title\":\"Building an Athlon Windows 98 Retro PC\"},{\"content\":\"While browsing through archives of very old files, I rediscovered backups of websites I once made. It felt a bit like scrolling thehistoryofweb.design, an interactive journey through the history of we\",\"link\":\"/post/2020/10/a-personal-journey-through-the-history-of-webdesign/\",\"title\":\"A journey through the history of webdesign\"},{\"content\":\"After the Sound Blaster and SD-to-IDE upgrades, it was time to do a decent performance analysis on the vintage DOS computer I now proudly own. The original 80486 blog post mentioned a CPU upgrade from\",\"link\":\"/post/2020/09/486-performance-analysis/\",\"title\":\"An am486 Performance Analysis\"},{\"content\":\"The revived 486 PC came with a Conner CFS210A 213 MB hard drive. As mentioned then, I like silent computers, so the first thing I did was flick out the low-end 12V PSU fan. That improved next to nothi\",\"link\":\"/post/2020/09/486-upgrade-sd-hdd/\",\"title\":\"486 Upgrade 2: The SD Card HDD\"},{\"content\":\"The first in hopefully many to come retro 486 PC update posts! As mentioned then, the PC I received did not come with a sound card. For retro gaming, unless you want to be stuck replaying the same lev\",\"link\":\"/post/2020/09/486-upgrade-sound-blaster/\",\"title\":\"486 Upgrade 1: Sound Blaster 16\"},{\"content\":\"What better birthday present to wish for as rapidly too old growing nostalgic computer nerd than a too old PC? \\u0026ldquo;Here, take this. At least now we don\\u0026rsquo;t have to haul it to the container park\",\"link\":\"/post/2020/09/reviving-a-80486/\",\"title\":\"Reviving an old 80486 PC\"},{\"content\":\"While digging through the usual daily stack of academic papers, in pursuit of that one report that might help me understand my own research questions, I stumbled upon the work of Kathleen Ofstedal and\",\"link\":\"/post/2020/08/education-and-collaboration/\",\"title\":\"Thoughts on collaboration in education\"},{\"content\":\"When I started programming the gba-sprite-engine two years ago, I knew I would be getting myself into trouble. The Game Boy Advance only has 16Mhz and it\\u0026rsquo;s whole software library is written in l\",\"link\":\"/post/2020/07/3d-software-rendering-on-gba/\",\"title\":\"3D Software Rendering on the GBA\"},{\"content\":\"I was supposed to fly out to Norway - and then COVID came along and said \\u0026ldquo;nope\\u0026rdquo;. Too bad, as the appealing photographs of Trondheim certainly made the ITiCSE (Innovation and Technology in \",\"link\":\"/post/2020/06/iticse-2020/\",\"title\":\"ITiCSE 2020: A Report\"},{\"content\":\"In November 2016, Polish teen game developer Jakub Cislo, by then migrated to Germany, created a kickstarter project for a retro first person dungeon crawler game called Exitium. It is a game dedicate\",\"link\":\"/post/2020/06/about-perseverance/\",\"title\":\"Project Warlock: About Perseverance\"},{\"content\":\"Whizbang time! So, I was in need of a simple resursive Javascript function that iterates over all directories to look for .md Markdown files, to feed it to a search indexer. This is a node script my d\",\"link\":\"/post/2020/06/combining-async-with-generators-in-node/\",\"title\":\"Combining async with generators in Node 11\"},{\"content\":\"In my last post about webdesign called \\u0026ldquo;tracking and privacy on websites\\u0026rdquo;, I ended with a list of things you need to take into account when building a website - of which accessibility is o\",\"link\":\"/post/2020/06/designing-with-accessibility-in-mind/\",\"title\":\"Designing websites with accessibility in mind\"},{\"content\":\"Thanks to another great \\u0026ldquo;internet stumble\\u0026rdquo;, I came across Laura Kalbag\\u0026rsquo;s blog and her stance on privacy and tracking. She\\u0026rsquo;s been giving talks on the subject and created ad- and\",\"link\":\"/post/2020/06/tracking-and-privacy-on-websites/\",\"title\":\"Tracking and privacy concerns on websites\"},{\"content\":\"As you may have read, I\\u0026rsquo;m quite the Hugo.io fan and I build all my websites using this static website generator. As cool and tech-savvy it is, projects like forestry.io exist to leverage Hugo\\u0026rs\",\"link\":\"/post/2020/05/page-building-with-brizy-in-wordpress/\",\"title\":\"Page Building with Brizy in Wordpress\"},{\"content\":\"This week, Hugo 0.7 has been released. And while it\\u0026rsquo;s a minor release, it\\u0026rsquo;s nonetheless something to be excited about: finally a babel pipeline is available. That means transpiling new ES6\",\"link\":\"/post/2020/05/hugo-extended/\",\"title\":\"Hugo Extended: More static site processing power!\"},{\"content\":\"So, I wrote a book about bread baking.\\nAnd it did not happen overnight. I started working on the idea in 2017, but was using Google Docs at that time, which frustrated more than it was a joy to work w\",\"link\":\"/post/2020/05/using-pandoc/\",\"title\":\"Using Pandoc to publish a book\"},{\"content\":\"Hosting static websites on Github Pages is not a chore - on the contrary, it\\u0026rsquo;s free and very easy to set up: you only need a CNAME file with your domain in, and some plan to serve files from a b\",\"link\":\"/post/2020/04/vps/\",\"title\":\"DIY: Hosting stuff on your own VPS\"},{\"content\":\"I wish the word \\u0026ldquo;don\\u0026rsquo;t\\u0026rdquo; in the title of this post could go away, but after years of trying, I have to say it cannot. There are so many aspects of the academic world that speak agains\",\"link\":\"/post/2020/02/agile-academia/\",\"title\":\"Five reasons why agile and academia don't go together\"},{\"content\":\"Spring jij onmiddellijk in je wagen als die plotse zin in tomatensoep op komt en je zelf niets in huis hebt? \\u0026lsquo;Snel even een blikje lenen, ik ben zo terug schat!\\u0026rsquo; Het lijkt als een onschuld\",\"link\":\"/post/2019/12/over-onmiddellijke-voldoening/\",\"title\":\"Over Onmiddellijke Voldoening\"},{\"content\":\"My previous studies investigated which non-technical skills are currently being taught in software engineering education, and which are perceived as needed to excel in the industry. We found creativit\",\"link\":\"/post/2019/10/creative-cognitive-processes/\",\"title\":\"Programming: a Creative Cognitive Process\"},{\"content\":\"Bedrijven zien conferenties vaak als een onnodige kost waar hun werknemers nauwelijks worden naar toe gestuurd. Meestal gaat dit keurig af van het jaarlijks opleidingsbudget, ook weer keurig verrekend\",\"link\":\"/post/2019/09/de-zin-en-onzin-van-conferenties/\",\"title\":\"De zin en onzin van conferenties\"},{\"content\":\"Electrical Engineering students have to work through a programming course in their third year at KU Leuven, a course called \\u0026lsquo;Software Design in C/C++\\u0026rsquo;. This course is one of the things I i\",\"link\":\"/post/2019/04/teaching-oo-with-gba/\",\"title\":\"Teaching Object-Oriented design using the GBA\"},{\"content\":\"My research on soft skills in software engineering has brought me to many shady places so far. These places are dark, murky, and carry the rotten smell of mold. Welcome to the wonderful world of \\u0026ldqu\",\"link\":\"/post/2019/02/competences-and-certificates/\",\"title\":\"IT Competences and Certificates\"},{\"content\":\"A huge amount of ideas and a quite a few months later, my original proposal, called \\u0026ldquo;The disparity between industrial requirements and classic education of modern software engineering.\\u0026quot;, ch\",\"link\":\"/post/2019/01/phd-iteration-2/\",\"title\":\"A Ph.D. Thesis: Iteration 2\"},{\"content\":\"Eens blazen en hem \\u0026ldquo;er uit en weer in steken\\u0026rdquo; - aan wat doet deze vreemde uitspraak denken? Zedige kinderen die opgroeiden in de jaren \\u0026lsquo;90 denken hopelijk onmiddellijk aan een consol\",\"link\":\"/post/2018/12/over-analoog-en-digitaal/\",\"title\":\"Over analoog en digitaal\"},{\"content\":\"To continue our unit testing tradition, each time I land on a new language or piece of technology, I carefully assess whether it\\u0026rsquo;s possible to write tests first. Unsurprisingly, even in Assembly\",\"link\":\"/post/2018/12/unit-testing-picoblaze-assembly/\",\"title\":\"Unit Testing PicoBlaze Assembly files\"},{\"content\":\"It never occurred to me that an article like this might be very informative for those interested in knowing how things work in the software engineering industry. Google\\u0026rsquo;s related results to \\u0026ldq\",\"link\":\"/post/2018/10/a-decade-in-the-industry/\",\"title\":\"A Decade in the Software Engineering industry\"},{\"content\":\"At the start of my doctoral study, things are a bit woozy. The use of that word \\u0026ldquo;bit\\u0026rdquo; may be the inverse of exaggeration: shaping an abstract idea into a malleable and well-defined project\",\"link\":\"/post/2018/10/lean-doctorate/\",\"title\":\"The Startup of a Lean Doctorate\"},{\"content\":\"I\\u0026rsquo;ve grown so accustomed to some of Neal Ford\\u0026rsquo;s The Productive Programmer \\u0026ldquo;power tools\\u0026rdquo; that each time I install a new OS or get a new laptop, I start with my list of cant-live\",\"link\":\"/post/2018/08/productivity-tools-multiplatform/\",\"title\":\"Productivity Tools on all platforms\"},{\"content\":\"Zoals 2017 in boeken kan worden uitgedrukt, zo kan mijn leven in zijn geheel tot nu toe worden uitgedrukt in de boeken die het sterk beïnvloed heeft. Tijdens het lezen van Montaigne\\u0026rsquo;s Essays kwa\",\"link\":\"/post/2018/08/boeken-die-mij-gevormd-hebben/\",\"title\":\"Boeken die mij gevormd hebben tot wie ik ben\"},{\"content\":\"As old as the language C may be, it took other languages a long time to catch up with something as mundane as a pointer. Pointers are the bread and butter of any C program and are widely regarded as a\",\"link\":\"/post/2018/08/domain-driven-design-in-c/\",\"title\":\"Domain Driven Design in C\"},{\"content\":\"Het resultaat van een onderzoek dat ik las in Frank Furedi\\u0026rsquo;s \\u0026ldquo;Waar zijn de intellectuelen?\\u0026rdquo; boezemt mij veel angst in: minder dan de helft van de samenleving wil tegenwoordig nog lit\",\"link\":\"/post/2018/07/over-intellect/\",\"title\":\"Over de inflatie van intellect\"},{\"content\":\"In Venteuil, een klein dorpje in de Champagne streek te Frankrijk dat vijfhonderd hele inwoners telt, ligt wijnmaker Autréau-Lasnot. Er zijn honderden grote en kleine champagneboeren gevestigd in de s\",\"link\":\"/post/2018/07/over-tijdsbesef/\",\"title\":\"Over tijdsbesef\"},{\"content\":\"Also worth reading: Reverse engineering a curriculum.\\nI happened to come across a very interesting study path for \\u0026ldquo;game programmers\\u0026rdquo; published at https://github.com/miloyip/game-programmer\",\"link\":\"/post/2018/06/informatics-education-modules/\",\"title\":\"Computer Science learning pathways\"},{\"content\":\"Also worth reading: Teaching by philosophy.\\nWhat if, instead of starting with the beginning, you\\u0026rsquo;d start with imagining where you\\u0026rsquo;d land if you\\u0026rsquo;d successfully finish a big project? T\",\"link\":\"/post/2018/06/reverse-engineering-a-curriculum/\",\"title\":\"Reverse engineering a curriculum\"},{\"content\":\"Addendum: 7 highly successful software engineering cultures is de moeite om in detail na te lezen, waarbij bedrijven zoals GitLab hun \\u0026ldquo;Team Handboek\\u0026rdquo; open stellen. Het gaat véél verder dan\",\"link\":\"/post/2018/06/over-bedrijfsethiek/\",\"title\":\"Over het introduceren van bedrijfsethiek\"},{\"content\":\"The following Ph.D. proposal has been tailored to act as a clarification for colleagues and professors, hence it\\u0026rsquo;s written in Dutch. The English abstract will follow later. The thesis subject:\\n \",\"link\":\"/post/2018/06/phd-proposal/\",\"title\":\"A Ph.D. Thesis Proposal\"},{\"content\":\"Also worth reading: reverse engineering a curriculum.\\nAwareness, that\\u0026rsquo;s the keyword I\\u0026rsquo;m looking for here.\\nStudents are required to slog through a lot of classes during their university yea\",\"link\":\"/post/2018/05/teaching-philosophy-first/\",\"title\":\"Teaching by philosophy\"},{\"content\":\"Filosofie kan gezien worden als een poging om dingen rondom de mensheid te definiëren. Ik noem het een poging, en geen manier, omdat we al duizenden jaren kritiek aan het geven zijn op elkaars definit\",\"link\":\"/post/2018/05/over-entropie/\",\"title\":\"Over entropie\"},{\"content\":\"Writing software isn\\u0026rsquo;t much different than describing a world. The world, where we live in, is a world, not the only one. With software, we could, theoretically speaking, describe our own world.\",\"link\":\"/post/2018/04/thinking-in-terms-of-objects/\",\"title\":\"Thinking in terms of objects\"},{\"content\":\"Coming across pseudocode isn\\u0026rsquo;t something that might happen every day except if you\\u0026rsquo;re used to browsing through the more theoretical and academic oriented \\u0026ldquo;computer science\\u0026rdquo; han\",\"link\":\"/post/2018/04/pseudocode/\",\"title\":\"Death to pseudocode?\"},{\"content\":\"When was the last time you were able to focus well on a difficult task in an office landscape? For long periods of time? Did you manage to finish the task in time? Knowledge workers are increasingly p\",\"link\":\"/post/serendipitous-creativity/\",\"title\":\"Concentrating on serendipitous creativity\"},{\"content\":\"We like to talk about the architecture of our software because we like complexity. Software developers are the bears, and complex patterns seem to be the honey. The more I pair with people the more I \",\"link\":\"/post/2018/02/hiding-complexity/\",\"title\":\"Hiding Code Complexity\"},{\"content\":\"\\u0026ldquo;Let\\u0026rsquo;s try to keep silent for a minute and enjoy the complete absence of traffic noise!\\u0026rdquo; I yelled to my friends. We were standing on a sandy hill in the middle of national park \\u0026ldqu\",\"link\":\"/post/take-your-time/\",\"title\":\"Take your time.\"},{\"content\":\"Goodreads presented me with a neat overview on my read books in 2017 you can also take a look at. The dull page statistics are of no interest to me, but the kind of books I\\u0026rsquo;ve read do tell a sto\",\"link\":\"/post/2018/01/2017-in-books/\",\"title\":\"2017 in books\"},{\"content\":\"People have an irresistible urge to create. But we often mistake productivity with creativity with really creating. Homo creativus. But is this always a good thing? The best inventions in the world br\",\"link\":\"/post/2017/12/inventing-for-the-worse/\",\"title\":\"Inventing - for the worse?\"},{\"content\":\"My dog, Miel (yes, like the French word for honey. It\\u0026rsquo;s a Golden Retriever, get the link?), loves to walk. He also likes playing a lot, but as soon as I put on my shoes or get near the garden ga\",\"link\":\"/post/2017/08/i-am-jealous-of-my-dog/\",\"title\":\"I'm jealous of my dog\"},{\"content\":\"My recent addiction to fountain pens has reached new heights. I happened to talk about pens with a dear colleague and she asked if I also had pens with a flexible nib. Posing such a question usually r\",\"link\":\"/post/2017/07/fountain-pens-first-look/\",\"title\":\"A quick look at 6 fountain pens\"},{\"content\":\"If you\\u0026rsquo;re wondering why you should journal in the first place, then maybe it\\u0026rsquo;s a good idea to start reading \\u0026lsquo;healing creative scars\\u0026rsquo; and \\u0026lsquo;a samurai learning mindset\\u0026rsquo\",\"link\":\"/post/2017/07/journaling-in-practice/\",\"title\":\"Journaling in practice\"},{\"content\":\"Remembering David Lebovitz' pine nut syndrome, I started to take a closer look at packages of food we buy at the local supermarket. It\\u0026rsquo;s so easy to get completely focused on buying local vegetab\",\"link\":\"/post/2017/07/nuts-about-local-nuts/\",\"title\":\"Nuts about local nuts\"},{\"content\":\"Want to skip to the practical part?\\nAre you aware of your problems? Once upon a time in a land not very far away (in fact, it\\u0026rsquo;s the very same we live in), a small boy and his Gameboy grew up. He\",\"link\":\"/post/2017/06/healing-creative-scars/\",\"title\":\"Healing creative scars\"},{\"content\":\"After reading the famed books The Book of five rings By Miyamoto Musashi and the Life-giving sword By Yagyu Munenori, I started making connections between the teachings of the art of war and the teach\",\"link\":\"/post/2017/06/a-samurai-learning-mindset/\",\"title\":\"A samurai learning mindset\"},{\"content\":\"A lot of people seem to think I\\u0026rsquo;m the kind of chef who uses loads and loads of ingredients, combining and layering without thinking twice. We were having a discussion about what to cook for dinn\",\"link\":\"/post/2017/06/development-principles-in-cooking/\",\"title\":\"Development principles in cooking\"},{\"content\":\"The other day, I was having a discussion with a friend and colleague about reaching out to others. He had an idea on combining patterns learned from the enterprise software development world (clean co\",\"link\":\"/post/2017/05/handing-over-enough-when-inspiring/\",\"title\":\"Are you handing over enough when inspiring someone?\"},{\"content\":\"Jessica Ellis gave a lot of great tips on how to teach kids to program at Techorama 2017 in Antwerp. She has ben an active teacher in the tkplabs.org society and introduced something clever called \\u0026ld\",\"link\":\"/post/2017/05/teaching-kids-how-to-program/\",\"title\":\"How to teach kids to program\"},{\"content\":\"Inspired by Noah Bradley\\u0026rsquo;s Don\\u0026rsquo;t go to art school blog at Medium.com.\\nDrawing and art in general has always been something I didn\\u0026rsquo;t quite grasp or try to understand. I was a software\",\"link\":\"/post/2017/02/teaching-yourself-to-draw/\",\"title\":\"Teaching yourself to draw\"},{\"content\":\"Thanks to the Postmodern VB6 article I\\u0026rsquo;ve found on the internetz, I decided to give SimplyVBUnit a try. My job requires sporadic visual basic 6 code changes in the big legacy project we\\u0026rsquo;re\",\"link\":\"/post/2016/12/vb6-unit-testing/\",\"title\":\"Unit testing in Legacy Projects: VB6\"},{\"content\":\"We were looking for a few alternatives to our big ExtJS 4 application. Since it\\u0026rsquo;s not that easy to completely migrate from one front-end framework to the next, a possible solution would be to st\",\"link\":\"/post/2016/01/react-in-extjs/\",\"title\":\"Migrating from Extjs to React gradually\"},{\"content\":\"As the previous post indicated, we\\u0026rsquo;re trying to stabilize our scenario tests created with WebDriver. One of the things we did was trying to capture as much data as possible if something goes wro\",\"link\":\"/post/2015/01/webdriver-exception-handling/\",\"title\":\"Webdriver Exception Handling\"},{\"content\":\"WebDriver \\u0026amp; js-heavy frameworks Writing scenario tests for javascript-heavy UI webpages can be really difficult. It gets complicated pretty quickly if you\\u0026rsquo;re using a lot of async calls or a \",\"link\":\"/post/2014/12/unit-testing-extjs-ui/\",\"title\":\"Unit Testing Extjs UI with Siesta\"},{\"content\":\"Memory management is something to keep in mind when deploying and running applications on top of the JVM. Parameters like Xmx and Xms are things to juggle with when it comes to finding the perfect bal\",\"link\":\"/post/2014/10/memory-management-vs-java/\",\"title\":\".NET Memory management VS JVM Memory management\"},{\"content\":\"Sometimes, life is just a little bit more difficult than you imagined the day before. Sometimes, you have to work on a legacy codebase with custom frameworks rooted so deeply you\\u0026rsquo;re having lot\\u0026r\",\"link\":\"/post/2014/09/faking-domain-logic/\",\"title\":\"Faking domain logic\"},{\"content\":\"The problem: Webdriver elements returned by driver.FindElement() are too generic. There\\u0026rsquo;re the Text, SendKeys() and Click() methods/properties (depending your on C#/Java implementation). The sol\",\"link\":\"/post/2014/09/custom-webdriver-page-factories/\",\"title\":\"Custom Webdriver Page Factories\"},{\"content\":\"Remember this?\\n ./configure make make install That\\u0026rsquo;s not so bad, as long as you have the right compiler and linker flags configured, depending on the target OS. The real problem, however, is tr\",\"link\":\"/post/2014/03/scons-building/\",\"title\":\"Bye autotools hello Scons\"},{\"content\":\"So\\u0026hellip; What\\u0026rsquo;s up with all that duplication in your unit tests? Let\\u0026rsquo;s take a look at a very recognizable pattern when for instance using RhinoMock in C#:\\n [TestInitialize] public void S\",\"link\":\"/post/2014/03/metaprogramming-convention-dry/\",\"title\":\"Metaprogramming instead of duplication\"},{\"content\":\"This post is inspired by Venkat Subramaniam\\u0026rsquo;s Devoxx 2013 talk Thinking Functional Style. See downloads at agiledeveloper.com which has a rather cool Groovy example.\\nClassic builders For years, \",\"link\":\"/post/2013/11/builders-dsl/\",\"title\":\"Enhancing the builder pattern with closures\"},{\"content\":\"On previous projects I\\u0026rsquo;ve worked on, development PCs came with a local version of the database scheme. Each DB change also got rolled out to those computers, which enabled us developers to fool \",\"link\":\"/post/2013/11/integration-testing-sqlite/\",\"title\":\"Integration Testing with SQLite\"},{\"content\":\"When switching over to a new editor and new language, I can sometimes get frustrated by missing features I got (very) attached to. This excludes the obvious difference in shortcut keys.\\nShortcuts and \",\"link\":\"/post/2013/10/vstudio-missing-features/\",\"title\":\"Visual Studio 2012 for Eclipse users\"},{\"content\":\"Originally posted on Medium.\\nAddendum Red Zuurdesem, my website about baking with sourdough, has been active since 2012, and still is. I hold a professional bread baker\\u0026rsquo;s degree since 2016 - thi\",\"link\":\"/post/2013/10/learning-to-become-a-baker/\",\"title\":\"Learning to become a baker\"},{\"content\":\"This article is based on the notes I\\u0026rsquo;ve collected on My Wiki.\\nTest Driven Development (or TDD), it\\u0026rsquo;s one of those buzz words which usuallly appear in the same sentence with \\u0026ldquo;scrum\\u0026rd\",\"link\":\"/post/2013/10/unit-testing-stored-procedures/\",\"title\":\"Unit Testing Stored Procedures\"},{\"content\":\"Dynamic Languages: Constructs vergelijken Deze pagina vergelijkt verschillende dynamische talen in een poging om een overzicht te maken tussen de alsmaar groeiende lijst. De meest gebruikte features v\",\"link\":\"/post/2013/10/dynamic-languages/\",\"title\":\"A look at dynamic languages\"},{\"content\":\"Scope C++ heeft block level scope, net als Java, alleen is het mogelijk om een variabele binnen een for loop dezelfde naam te geven als een die buiten die block gedefiniëerd is, terwijl dat in Java ni\",\"link\":\"/post/2013/10/cplusplus-basics/\",\"title\":\"C++ Basics\"},{\"content\":\"Binaries zoeken Kan met whereis, maar die zoekt blijkbaar niet in \\u0026ldquo;alle\\u0026rdquo; binary dirs - enkel degene die geconfigureerd zijn onder:\\nsysctl user.cs_path # output: user.cs_path = /usr/bin:/bi\",\"link\":\"/post/2013/10/unix-cmd/\",\"title\":\"Heavily used Unix Commands\"},{\"content\":\"Javascript Inleiding Primitives Soorten In javascript zijn er slechts 3 primitives:\\n string (geassocieerd object: String) boolean (geassocieerd object: Boolean) number (geassocieerd object: Number) P\",\"link\":\"/post/2013/10/introduction-to-js/\",\"title\":\"Introduction to JavaScript\"},{\"content\":\"Handy links:\\n special class methods like _ getattr _ and _ new _ dive into python - native datatypes Inside story on new style classes - ter info: Python3 heeft enkel \\u0026ldquo;newstyle\\u0026rdquo; classes! \",\"link\":\"/post/2013/10/python-basics/\",\"title\":\"Python Class structure basics\"},{\"content\":\"Ruby Classes Closures and lambda\\u0026rsquo;s Weer 4 verschillende mogelijkheden in Ruby, zie Proc and Lambda in Ruby\\nNative \\u0026ldquo;blocks\\u0026rdquo; aanmaken Is niet mogelijk. a = { puts \\u0026quot;hello\\u0026quot; } g\",\"link\":\"/post/2013/10/ruby-classes/\",\"title\":\"Ruby Class structures basics\"},{\"content\":\"Variable arguments Bron: http://www.cs.utexas.edu/ftp/garbage/cs345/schintro-v14/schintro_68.html\\n(define (stack . args) (display args)) (define (plus a b) (stack a b) (+ a b)) (plus 1 2) Print in een\",\"link\":\"/post/2013/10/scheme/\",\"title\":\"Scheme tips and tricks\"},{\"content\":\"Originally posted on Medium.\\nThe amateurs “So, you do eat a juicy peace of grilled salmon, right?” “No, I already told you, Im a vegetarian.” (sigh) Frowning. You can almost hear them thinking “that\",\"link\":\"/post/2013/09/vegetarians-do-not-eat-fish/\",\"title\":\"No, vegetarians do not eat fish!\"},{\"content\":\"Originally posted on Medium.\\nThere have been a lot of love letters to big cities here on Medium recently. I never really understood the love for those busy places, but that should not be a big surpris\",\"link\":\"/post/2013/08/on-finding-your-inner-zen-in-big-cities/\",\"title\":\"On finding your inner zen in big cities\"},{\"content\":\"Past new year, I stopped promising silly things to myself. “This year, Ill for sure go jogging several times a week!”or “This year, Ill really get into learning another language!”. We all know ho\",\"link\":\"/post/2013/08/can-i-haz-happy-thoughts/\",\"title\":\"Ending your day with happy thoughts\"},{\"content\":\" Not finding what you're looking for? Browse the archives. 2013 Nov 14 Enhancing the builder pattern with closures the trainwreck/builder/chaining pattern can be dangerous and here\\u0026#39;s why pro\",\"link\":\"/post/2013/\",\"title\":\"Archive by year: 2013\"},{\"content\":\" Not finding what you're looking for? Browse the archives. 2014 Dec 23 Unit Testing Extjs UI with Siesta An attempt to replace instable Webdriver tests with Siesta UI tests programming \\u0026nbsp; \\u0026n\",\"link\":\"/post/2014/\",\"title\":\"Archive by year: 2014\"},{\"content\":\" Not finding what you're looking for? Browse the archives. 2015 Jan 14 Webdriver Exception Handling What should you do when something goes wrong with your scenario tests programming \\u0026nbsp; \\u0026nbsp\",\"link\":\"/post/2015/\",\"title\":\"Archive by year: 2015\"},{\"content\":\" Not finding what you're looking for? Browse the archives. 2016 Dec 27 Unit testing in Legacy Projects: VB6 Even older 4GL languages have unit testing capabilities programming \\u0026nbsp; \\u0026nbsp; unit\",\"link\":\"/post/2016/\",\"title\":\"Archive by year: 2016\"},{\"content\":\" Not finding what you're looking for? Browse the archives. 2017 Dec 30 Inventing - for the worse? Is inventing always a good thing? learning \\u0026nbsp; \\u0026nbsp; craftsmanship Aug 17 I\\u0026#39;m jea\",\"link\":\"/post/2017/\",\"title\":\"Archive by year: 2017\"},{\"content\":\" Not finding what you're looking for? Browse the archives. 2018 Dec 22 Over analoog en digitaal Waarom een fysieke handeling niet vervangbaar is braindump hardware \\u0026nbsp; \\u0026nbsp; games 05 Uni\",\"link\":\"/post/2018/\",\"title\":\"Archive by year: 2018\"},{\"content\":\" Not finding what you're looking for? Browse the archives. 2019 Dec 02 Over Onmiddellijke Voldoening Het ik-MOET-het-nu-hebben gevoel zijn zin geven braindump \\u0026nbsp; Oct 08 Programming: a\",\"link\":\"/post/2019/\",\"title\":\"Archive by year: 2019\"},{\"content\":\" Not finding what you're looking for? Browse the archives. 2020 Dec 27 Programming on the Apple M1 Silicon Is early adoption a good idea as a software developer? hardware programming \\u0026nbsp; \\u0026nbs\",\"link\":\"/post/2020/\",\"title\":\"Archive by year: 2020\"},{\"content\":\" Not finding what you're looking for? Browse the archives. 2021 Mar 11 Always have a Diaster Recovery Plan One OVH data center was destroyed by fire last night braindump \\u0026nbsp; \\u0026nbsp; vps 09 \",\"link\":\"/post/2021/\",\"title\":\"Archive by year: 2021\"},{\"content\":\"Links:\\n Displaced Gamers YouTube video LCD Monitor compatibility DB (more) Open Source Scan Converter (OSSC) EDID VGA/DVI Emulators \",\"link\":\"/post/2020/10/dos-aspect-ratios/\",\"title\":\"Screen aspect ratios and DOS Games\"}]"
);
</script>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
<item>
<title>Subscribe to Brain Baking</title>
<link>https://brainbaking.com/subscribe/</link>
<comments>https://brainbaking.com/subscribe/#commento</comments>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<author>Wouter Groeneveld</author>
<guid isPermaLink="true">https://brainbaking.com/subscribe/</guid>
<description>
<![CDATA[
<p>If you&rsquo;re interested in receiving updates on all things Brain Baking, you can simply subscribe to one of the <em>RSS feeds</em> below. Freshly baked thoughts and ideas, served in your own favorite news reader, how about that? I like <a href="https://netnewswire.com/">NetNewsWire</a>, which comes with a catchy slogan:</p>
<blockquote>
<p>More news, less junk. Faster.</p>
</blockquote>
<p>It&rsquo;s also a nice way to unify the layout of your personal news.</p>
<h2 id="the-feeds">The feeds</h2>
<p>Do you want to subscribe to <strong>everything</strong> on this site? <em>(Blog, Notes)</em><br/>
Use <svg class='icon icon-text'><title>feed icon</title><use xlink:href='#news'></use></svg><a href="/index.xml">/index.xml</a> or just copy-paste <a href="brainbaking.com">brainbaking.com</a> in your reader to auto-discover the link.</p>
<ul>
<li>Are you only interested in <strong>blog articles</strong>? <br/>Use <svg class='icon icon-text'><title>feed icon</title><use xlink:href='#news'></use></svg><a href="/post/index.xml">/post/index.xml</a></li>
<li>Are you only interested in <strong>notes</strong> (the micro-blog)?<br/>Use <svg class='icon icon-text'><title>feed icon</title><use xlink:href='#news'></use></svg><a href="/notes/index.xml">/notes/index.xml</a></li>
</ul>
<p>If you really, <em>really</em> want, you can also subscribe to specific categories. <a href="/archives">See the archives</a> for an overview of the categories. Just add <code>/index.xml</code> to an url. For instance, to only subscribe to the <em>hardware</em> category, use <a href="/categories/hardware/index.xml">/categories/hardware/index.xml</a>.</p>
<p>
By <a href="/about">Wouter Groeneveld</a> on 1 January 0001.
</p>
]]>
</description>
</item>
</channel>
</rss>