Thomas Coopman - Infinite Treehttps://infinitetree.eu/index.xml
Recent content on Thomas Coopman - Infinite TreeHugo -- gohugo.ioen-usWed, 08 Feb 2017 20:44:40 +0100Exploring aggregate boundaries in event sourced systemshttps://infinitetree.eu/blog/2017/02/08/exploring-aggregate-boundaries-in-event-sourced-systems/
Wed, 08 Feb 2017 20:44:40 +0100https://infinitetree.eu/blog/2017/02/08/exploring-aggregate-boundaries-in-event-sourced-systems/
<p>In this post I&rsquo;m exploring some ways of modelling aggregate boundaries in an event sourced system. This is mostly to crystallise some thoughts that I had after some event storming sessions, but it might be interesting to someone else.</p>
<p>The domain I&rsquo;m using in this post is the domain that <a href="https://twitter.com/michelgrootjans">Michel Grootjans</a> and I have created for the workshop <em>Playing with projections</em> (We already gave it a few times, for example at <a href="https://dddeurope.com/2017/speakers/thomas-coopman/#handson">DDD Europe</a> and will also give a session at <a href="http://itakeunconf.com/">I T.A.K.E.</a>)</p>
<h2 id="the-domain-an-online-quiz-platform">The domain: An online quiz platform</h2>
<p>In the online quiz platform:</p>
<ul>
<li>a player can create a new quiz</li>
<li>they can add questions to the quiz</li>
<li>they can publish the quiz</li>
<li>once a quiz has been published, a game can be opened. A game is an instance of a quiz</li>
<li>Many games of a quiz can be opened (there is no limit)</li>
</ul>
<p>A game, once it is opened looks like this:</p>
<ul>
<li>players can join a game</li>
<li>after some time the game is started</li>
<li>once the game is started, every question that is part of the quiz will be asked</li>
<li>players get a limited time to answer the question, if they are too late, a timeout passes</li>
<li>once all players have answered, or the timeout has passed a new question is asked</li>
<li>once all questions have been asked, the game is finished</li>
<li>if no players joined the game, the game will be cancelled</li>
</ul>
<h2 id="how-can-we-model-the-domain">How can we model the domain?</h2>
<p>Now we will take a look at how we can model parts of the domain.</p>
<p>The first way to model could be by having one aggregate: the quiz. A quiz can handle its whole life cycle and so it&rsquo;s very easy to enforce all rules in this design. But we can see some problems with this design:</p>
<ul>
<li>Our quiz aggregate stream can grow to huge sizes. When lots of games are played, there will be lots of events.</li>
<li>An aggregate, because it should keep its invariants, is a synchronization point. So when there are many games played, this could be a performance issue.</li>
</ul>
<p>Furthermore, at the moment the life cycle of the quiz seems a bit incomplete. The defined business rules don&rsquo;t tell anything about ways of changing the quiz, archiving one, or preventing new games to be started. Suppose in a couple of weeks, business asks us to add these new features:</p>
<ul>
<li>A player can change a quiz (add new questions) after it&rsquo;s been published.</li>
<li>A player can archive a quiz. No games can be started for archived quizzes.</li>
</ul>
<p>Of course we will ask business:</p>
<blockquote>
<p>&ldquo;What happens to running games when a player changes something?&rdquo;</p>
<p>&ldquo;Running games must not be affected by changes&rdquo;</p>
</blockquote>
<p>This provides a bit of a challenge in the current design. If we model this as one aggregate, we will need to provide extra logic to handle changed questions.</p>
<p>Suppose we have a quiz with currently open games and change some questions of the quiz. We know that started games should not be affected. To solve this we would could save the old questions. But because multiple games can be started at different times, it&rsquo;s not enough to solve the previous set of questions. A better solution would be to copy the questions to the game when it is started.</p>
<p>At this point we can see a new design emerging. We can split our domain into 2 aggregates. A quiz and a game.
This can solve the problem of the changing questions and also solves our initial problem of performance and a huge aggregate. The quiz will still be long lived, but will almost always be very small. A game on the other hand will be short lived. The performance will be solved because each game is now independent.</p>
<p>The design with splitting the quiz and game aggregates introduces a new challenge though. A game can only be started for a quiz in the correct state. A game cannot be opened if the quiz isn&rsquo;t published yet or if it is archived. But the game doesn&rsquo;t have this information, the quiz has.</p>
<p>So the solution is simple: <em>the quiz creates a new aggregate; the game</em> (<a href="https://groups.google.com/forum/#!searchin/dddcqrs/aggregate$20instance|sort:relevance/dddcqrs/B6kxs7FK8_I/F_xcEdkOnHwJ">aggregates create other aggregate</a>).</p>
<p>In pseudo code this could look like:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span>quiz.open_game(game_id)
<span style="color: #008800; font-weight: bold">case</span> quiz_is_published
game = new <span style="color: #bb0066; font-weight: bold">Game</span>(game_id, quiz_id, copy(questions))
<span style="color: #888888"># game contains unsaved event game_was_opened</span>
return game
<span style="color: #008800; font-weight: bold">case</span> <span style="color: #003388">_</span>
return <span style="color: #bb0066; font-weight: bold">DomainError</span>(<span style="color: #dd2200; background-color: #fff0f0">&quot;A game can only be opened for published quizzes&quot;</span>)
</pre></div>
<h3 id="exploring-a-different-implementation">Exploring a different implementation</h3>
<p>Instead of the quiz aggregate that creates a new aggregate, we could also try something like this: The quiz handles the <code>open_game_request</code> command and returns an event <code>game_open_requested</code>. A process manager listens to this event and dispatches a <code>open_game</code> command. The <code>open_game</code> command is handled by a game. The <code>game_open_requested</code> means that it is allowed to open the game.</p>
<p>So <code>open_game</code> is now an internal command and should not be exposed to users. Users can only request to open a game.</p>
<p>This adds some complexity and is probably not always a good solution. But sometimes we might need a solution like this. Let&rsquo;s say that the we have some problems with copyrighted materials in our quizzes and that we are enforced to terminate all quizzes and corresponding games immediately (I know, this is probably far fetched, but it is to explore the solution further).</p>
<p>How could this look?</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span>quiz.terminate_due_to_copyright
<span style="color: #888888"># returns quiz aggregate with unsaved event (quiz_was_terminated)</span>
</pre></div>
<p>A process manager could listen to <code>quiz_was_terminated</code> and dispatch a <code>terminate_game</code> command to all open games for that quiz. But <em>how does the process manager know what games are open for the quiz</em>? Well if we modelled our solution to have the process manager open the games, then it can also keep the state of all the open games for the quiz. So in this final solution we have a process manager that listens to <code>game_open_requested</code>, <code>quiz_was_terminated</code>, <code>game_was_closed</code>.</p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>Although the problem and the domain seems simple, exploring the solution was fun. Furthermore, I only listed some probable solutions, more possible solutions can be found.</p>
<p>One thing I didn&rsquo;t touch yet, but might in an other post, is how frameworks or programming styles can force you into some solution. I had some trouble trying to implement the aggregate that creates an other aggregate in at least one framework and have seen some other frameworks where this solution is not obvious to implement.</p>
2017https://infinitetree.eu/blog/2017/01/03/2017/
Tue, 03 Jan 2017 19:18:13 +0100https://infinitetree.eu/blog/2017/01/03/2017/
<p>The year is over, a new year has come.</p>
<p>I know, New Year is an arbitrary point in time but it is a tradition to look back on the past year and have some resolutions for the year to come.</p>
<p>So at this arbitrary point in time, lets look back and forward</p>
<h2 id="2016">2016</h2>
<p>I&rsquo;m going to make this short, because I mostly want to look forward!</p>
<ul>
<li>Became an independent software consultant</li>
<li>Bought a house with my girlfriend</li>
<li>Read lots of books</li>
<li>Became a teamleader</li>
<li>Lots of other cool stuff</li>
</ul>
<h2 id="2017">2017</h2>
<p>Last month I read <a href="https://www.facebook.com/notes/mark-zuckerberg/building-jarvis/10154361492931634">Building Jarvis</a> from Mark Zuckerberg where he builds himself a Jarvis in 100 hours. I was, and still am, in awe. This looks like an awesome project and it was done in about 100 hours.</p>
<p>So I was thinking, last year, I had a goal of reading 30 books but I read way more <a href="https://www.goodreads.com/user/year_in_books/2016/5366494">46</a>. This year I&rsquo;m setting my goal lower because I kind of felt a pressure to read books. Even if it was without an underlying goal. Don&rsquo;t get me wrong, it&rsquo;s great to read this much books and I&rsquo;m going to try to keep reading a lot, but reading much isn&rsquo;t the goal. For me learning, recreation, relaxation are better goals.
And reading books is absolutely not the only way to learn. Moreover it&rsquo;s not the only way that I try to learn at the moment, but I believe my focus was a not alwasy correct, so that&rsquo;s why I&rsquo;m setting different goals this year.</p>
<h3 id="concrete-goals">Concrete goals:</h3>
<ul>
<li>Last year, I built lots of small things. This year, I want to build a concrete side project, put a time limit to it and finish it. 100 hours? 8 hours each month?. The side project should allow me to learn some of the stuff that I&rsquo;m interested in.</li>
<li>Read 20 books (reading still is fun and a great way to learn)</li>
<li>Read and understand 10 papers (1 each month)</li>
<li>Write 6 blog posts</li>
</ul>
<p>The books should be easy, the side project will probably be the hardest!</p>
<h3 id="learn-stuff-that-i-m-interested-in">Learn stuff that I&rsquo;m interested in</h3>
<p>So what will the project be? I don&rsquo;t know yet, but ideally, it should include some of the things that I&rsquo;m interested in at the moment:</p>
<p>(In no specific order)</p>
<ul>
<li>Machine learning and AI, natural language processing, neural networks,&hellip;.</li>
<li>Virtual reality</li>
<li>Event sourcing and DDD</li>
<li>Complex systems</li>
<li>Functional programming</li>
<li>Static typing (ML) languages</li>
<li>Frontend functional programming languages and UX</li>
<li>Product design, let&rsquo;s restate this: Building great products</li>
<li>Actor model - Erlang/Elixir</li>
<li>Mobile apps</li>
</ul>
<p>There are way more things that I&rsquo;m interested in, but this list is way too long already. So lets start with it!</p>
<h3 id="languages-i-m-watching">Languages I&rsquo;m watching:</h3>
<p>To complete, here are some of the languages that I&rsquo;m watching at the moment.</p>
<ul>
<li>Elixir</li>
<li>Elm</li>
<li>Purescript</li>
<li>Haskell</li>
<li>Typescript</li>
</ul>
<p>Watching means, at least try to write code in them or improve at these languages.</p>
<p>Have a great 2017!</p>
Programming Phoenix reviewhttps://infinitetree.eu/blog/2016/06/26/programming-phoenix-review/
Sun, 26 Jun 2016 10:49:59 +0200https://infinitetree.eu/blog/2016/06/26/programming-phoenix-review/<p>Elixir and Phoenix crossed my path multiple times last year. I read a really interesting tutorial on <a href="https://codewords.recurse.com/issues/five/building-a-web-framework-from-scratch-in-elixir">building a web framework from scratch</a>. Furthermore, Phoenix is really popular as an Elm backend, so I decided it was time to dive a bit deeper and learn myself some Phoenix.</p>
<p>It just happens that <a href="https://pragprog.com/book/phoenix/programming-phoenix">Program Phoenix</a> by
by Chris McCord, Bruce Tate, and José Valim was published recently, so this seemed like a good opportunity to learn more!</p>
<figure >
<a href="https://pragprog.com/book/phoenix/programming-phoenix">
<img src="https://infinitetree.eu/images/phoenix.jpg" />
</a>
<figcaption>
<h4>Programming Phoenix</h4>
</figcaption>
</figure>
<p>I enjoyed reading the book from cover to cover. It&rsquo;s been a long while since I&rsquo;ve read a book about a web framework, because I always wondered what the added value of a book was over documentation and tutorials. But as this book is written by the creator of framework and the language, I didn&rsquo;t bother looking any further.</p>
<p>When I started this book, I didn&rsquo;t really know Elixir and while reading the book I had to take some detours to explore the language a bit. The <a href="http://elixir-lang.org/getting-started/introduction.html">getting-started</a> guide in combination with this book were a great start into the language. Elixir is great in that is functional, runs on the BEAM (the Erlang VM) and is easy to get started with. On the other hand, I needed some time to get familiar and fluent with the syntax (especially if you compare it with something like Elm) and there a no static types (although <a href="http://erlang.org/doc/man/dialyzer.html">dialyzer</a> could be a help with that - I haven&rsquo;t explored that yet).</p>
<p>The first part of the book explains the basic parts of Phoenix as a MCV framework and is what you would expect in a book about web frameworks. The second part covers the fun part of Phoenix, channels and concurrency with Genserver and OTP (read about this if you haven&rsquo;t!).
The second part really invites me to explore Phoenix and Elixir more!</p>
<p>My biggest criticism with the book is about testing. While the testing chapters are decent and they go deep enough. I think that a test driven approach would have been better for some chapters (especially for the OTP chapters). You have to write quite a bit of code before you can see the results. Doing test first would probably help with the understanding. Although the interaction with the elixir REPL helps quite a bit!</p>
<p>The book covered all content that I wanted, except there is nothing about deploying the application. Some pointers and best practices into that direction would have been really nice!</p>
<p>Overall a very solid book and a good read. If you are interested in doing Phoenix programming, this is a very good starting point.</p>
Resumehttps://infinitetree.eu/resume/
Wed, 13 Apr 2016 13:20:35 +0200https://infinitetree.eu/resume/
<h3 id="independent-software-consultant">Independent Software Consultant</h3>
<p>Thomas Coopman has been fascinated with computers since he was a kid. Playing around at first, became programming later and after learning some programming for himself and a small detour starting studies for nursing, he went on and studied Master of Informatics at the KULeuven.</p>
<p>Thomas is a polyglot and loves to learn new languages. His latest language studies have taken him to Elixir and Elm, and he has a special affinity for functional programming languages.</p>
<p>Thomas is an independent software engineer and consultant focused on the full stack: frontend, backend and mostly people, practices and processes. Thomas is also currently active in the DDD Belgium and Software Craftsmanship Belgium community.</p>
<p>One of Thomas overal goals is to help to raise the software industry to a greater level, although he does not know yet how to do this. At the moment he is mostly trying to raise his own level by learning all the time from all his peers, and hopefully by learning and sharing he can gain some deeper insights in how to improve.</p>
<h4 id="work">Work</h4>
<p><strong><a href="https://infinitetree.eu/">Infinite Tree</a></strong> 2016-01 - Current</p>
<p>Independent software consultant.</p>
<p><strong><a href="www.protime.eu">Protime</a></strong>
2015-05 - Current</p>
<ul>
<li>Team leader</li>
<li>Senior software developer Ruby, Javascript and C#</li>
<li>Agile software development</li>
</ul>
<p><strong>Kenniscentrum Openbaar Domein (K-O-D)</strong> 2010-07 - 2015-04 Projectleader for IT projects</p>
<ul>
<li>Development and project leader for a GIS Viewer, mostly for sewers</li>
<li>Project lead and development of a platform for searching and creating public domain projects in synergy</li>
</ul>
<h4 id="interests">Interests</h4>
<ul>
<li>Co-organiser of <a href="https://www.meetup.com/dddbelgium/">DDD Belgium</a> and <a href="https://www.meetup.com/socratesbe/">Socrates Belgium</a></li>
<li>Speaking at conferences: <a href="https://dddeurope.com/2017/speakers/thomas-coopman/#handson">DDD Europe</a>, <a href="http://itakeunconf.com/sessions/playing-with-projections/">I T.A.K.E.</a></li>
<li><a href="https://www.goodreads.com/">Reading</a></li>
</ul>
<h4 id="education">Education</h4>
<p><strong>Master of Informatics (<a href="http://www.kuleuven.be/">KULeuven</a>)</strong></p>
<p>Masterthesis: A framework for dynamic extensible and context-driven domotics systems (<a href="https://link.springer.com/chapter/10.1007/978-3-642-13268-1_8">A User-Oriented and Context-Aware Service Orchestration Framework for Dynamic Home Automation Systems</a>)</p>
<h4 id="skills">Skills</h4>
<p>Methodologies:</p>
<ul>
<li>Domain Driven Design</li>
<li>Kanban and Agile software development</li>
<li>Continious improvement</li>
</ul>
<p>Frontend:</p>
<ul>
<li>Javascript</li>
<li>Elm</li>
<li>HTML</li>
<li>CSS</li>
<li>Reactjs + Redux</li>
</ul>
<p>Backend:</p>
<ul>
<li>C#</li>
<li>Elixir</li>
<li>Node</li>
<li>Ruby</li>
<li>Python</li>
<li>Java</li>
<li>Go</li>
</ul>
<p>GIS:</p>
<ul>
<li>ArcGIS Server + Desktop</li>
<li>Geoserver</li>
<li>Leaflet</li>
<li>Openlayers</li>
</ul>
Modelling money in Elmhttps://infinitetree.eu/blog/2016/04/12/modelling-money-in-elm/
Tue, 12 Apr 2016 22:28:31 +0200https://infinitetree.eu/blog/2016/04/12/modelling-money-in-elm/
<p>After reading the blog post of Mathias Verraes (@mathiasverraes) on (Type Safety and Money)[<a href="http://verraes.net/2016/02/type-safety-and-money/">http://verraes.net/2016/02/type-safety-and-money/</a>], and after doing a real short modelling attempt in Haskell at Socrates Belgium, I wanted to try to model Money in Elm.</p>
<p>I don&rsquo;t want to go to deep and too far so I&rsquo;ve set some basic constraints for myself:</p>
<ul>
<li>You cannot add money of different currencies (you need an explicit conversion) - <em>Add constraint</em></li>
<li>We also want a Price. A Price is a Money and a VAT amount.</li>
</ul>
<p>The goal is to explore different ways of modelling the money in Elm and to explore how a type safe language can support our constraints.</p>
<h2 id="possible-type-declarations-of-money-in-elm">Possible type declarations of Money in Elm</h2>
<p>Money is an amount (Float) and a currency</p>
<p>If you are doing serious calculations with money, you might want to check if you don&rsquo;t run into precision issues with Float. This is not the goal of the exercise, so we use Float.</p>
<p>There are some different options for modelling the money.</p>
<p>With a Tuple, a Currency and a Float:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">type</span> <span style="color: #008800; font-weight: bold">alias</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #0066bb; font-weight: bold">=</span> (<span style="color: #888888; font-weight: bold">Currency</span>, <span style="color: #888888; font-weight: bold">Float</span>)
<span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">Currency</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Euro</span> <span style="color: #0066bb; font-weight: bold">|</span> <span style="color: #888888; font-weight: bold">Dollar</span>
</pre></div>
<p>Or with union types</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Euro</span> <span style="color: #888888; font-weight: bold">Float</span> <span style="color: #0066bb; font-weight: bold">|</span> <span style="color: #888888; font-weight: bold">Dollar</span> <span style="color: #888888; font-weight: bold">Float</span>
</pre></div>
<p>Both these implementations fulfill the requirement of a <code>Money</code> type for the <code>Price</code>.</p>
<p>These implementations cannot enforce the <em>add constraint</em> at compile time. Although, you can enforce that you don&rsquo;t get wrong results:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #336699">add</span> <span style="color: #0066bb; font-weight: bold">:</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Maybe</span> <span style="color: #888888; font-weight: bold">Money</span>
</pre></div>
<p>or, there can be invalid money</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Euro</span> <span style="color: #888888; font-weight: bold">Float</span> <span style="color: #0066bb; font-weight: bold">|</span> <span style="color: #888888; font-weight: bold">Dollar</span> <span style="color: #888888; font-weight: bold">Float</span> <span style="color: #0066bb; font-weight: bold">|</span> <span style="color: #888888; font-weight: bold">Invalid</span>
<span style="color: #336699">add</span> <span style="color: #0066bb; font-weight: bold">:</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Money</span>
</pre></div>
<p>This last one would be harder to implement with a Tuple. But in most other ways I believe the Tuple and the union types are very similar. I like the union types better, so I won&rsquo;t explore the tuple any further.</p>
<p>When we have the choice between these 2 add type definitions, which one is best?
I prefer <code>add : Money -&gt; Money -&gt; Maybe Money</code> for 2 reasons: (1) Invalid is not an actual type of money and (2) returning Maybe makes it very explicit that this an operation that can fail.</p>
<p>Would it be possible to enforce the constraint of adding only the same currencies on compile time? Yes, like this:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">Euro</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Euro</span> <span style="color: #888888; font-weight: bold">Float</span>
<span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">Dollar</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Dollar</span> <span style="color: #888888; font-weight: bold">Float</span>
</pre></div>
<p>Now you have to implement 2 add functions for both types.</p>
<p>This does have some disadvantages, you have to implement add twice. If you want to have them in the same file, the names of the add methods can&rsquo;t be the same, and we need some type to represent money (for our price constraint).
This also means that it&rsquo;s best to implement <code>Euro</code> and <code>Dollar</code> both in their own module, so that you can create 2 add functions.</p>
<p>But lets see if this is doable.</p>
<p>First the problem of the reimplementation. This is something that is unavailable in Elm (I believe it&rsquo;s possible to avoid this with type classes in Haskell), but it&rsquo;s not that bad.
Suppose we needed to write many functions on money types, then we could write them like this:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #336699">update</span><span style="color: #0000DD; font-weight: bold">2</span> <span style="color: #0066bb; font-weight: bold">:</span> (<span style="color: #888888; font-weight: bold">Float</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Float</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Float</span>) <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span>
<span style="color: #336699">update</span><span style="color: #0000DD; font-weight: bold">2</span> <span style="color: #336699">f</span> <span style="color: #336699">e</span><span style="color: #0000DD; font-weight: bold">1</span> <span style="color: #336699">e</span><span style="color: #0000DD; font-weight: bold">2</span> <span style="color: #0066bb; font-weight: bold">=</span>
<span style="color: #008800; font-weight: bold">case</span> (<span style="color: #336699">e</span><span style="color: #0000DD; font-weight: bold">1</span>, <span style="color: #336699">e</span><span style="color: #0000DD; font-weight: bold">2</span>) <span style="color: #008800; font-weight: bold">of</span>
(<span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #336699">a</span>, <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #336699">a&#39;</span>) <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span> (<span style="color: #336699">f</span> <span style="color: #336699">a</span> <span style="color: #336699">a&#39;</span>)
<span style="color: #336699">add</span> <span style="color: #0066bb; font-weight: bold">:</span> <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span>
<span style="color: #336699">add</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #336699">update</span><span style="color: #0000DD; font-weight: bold">2</span> <span style="color: #0066bb; font-weight: bold">(+)</span>
</pre></div>
<p>Like this we can avoid writing complex functions twice</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #336699">complexOperation</span> <span style="color: #0066bb; font-weight: bold">:</span> <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span>
<span style="color: #336699">complexOperation</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #336699">update</span><span style="color: #0000DD; font-weight: bold">2</span> <span style="color: #336699">complexer</span>
<span style="color: #336699">complexer</span> <span style="color: #0066bb; font-weight: bold">:</span> <span style="color: #888888; font-weight: bold">Float</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Float</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Float</span>
</pre></div>
<p>The second constraint is that we need a <code>Price</code> with a <code>Money</code> type. With our first implementations this constraint was already fulfilled, but here we need to implement a <code>Money</code> type too.</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Euro</span> <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #0066bb; font-weight: bold">|</span> <span style="color: #888888; font-weight: bold">Dollar</span> <span style="color: #888888; font-weight: bold">USD</span>
<span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">VAT</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">VAT6</span> <span style="color: #0066bb; font-weight: bold">|</span> <span style="color: #888888; font-weight: bold">VAT12</span> <span style="color: #0066bb; font-weight: bold">|</span> <span style="color: #888888; font-weight: bold">VAT21</span>
<span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">Price</span> <span style="color: #0066bb; font-weight: bold">=</span> (<span style="color: #888888; font-weight: bold">Money</span>, <span style="color: #888888; font-weight: bold">VAT</span>)
</pre></div>
<p>(Here it makes more sense to use a tuple for <code>Price</code>, <code>Price</code> is a <code>Money</code> and a <code>VAT</code>, while <code>Money</code> is a amount of some currency)</p>
<p>We also need functions to transform a EUR or USD to Money, but these are trivial:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #888888; font-weight: bold">EURToMoney</span> <span style="color: #0066bb; font-weight: bold">:</span> <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Money</span>
<span style="color: #888888; font-weight: bold">EURToMoney</span> <span style="color: #336699">eur</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Euro</span> <span style="color: #336699">eur</span>
</pre></div>
<h2 id="extra-currency-conversions">Extra - Currency Conversions</h2>
<p>What if you want to convert a currency. Then you need exchange rates.
With Elm, these conversions can be typed checked too, although it&rsquo;s a bit verbose.</p>
<p>Let&rsquo;s say we want all the <code>Money</code> of our <code>Price</code>s to be converted to euro.</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">type</span> <span style="color: #008800; font-weight: bold">alias</span> <span style="color: #888888; font-weight: bold">EURToUSD</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Float</span>
<span style="color: #008800; font-weight: bold">type</span> <span style="color: #008800; font-weight: bold">alias</span> <span style="color: #888888; font-weight: bold">USDToEUR</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Float</span>
<span style="color: #008800; font-weight: bold">type</span> <span style="color: #008800; font-weight: bold">alias</span> <span style="color: #888888; font-weight: bold">Exchanges</span> <span style="color: #0066bb; font-weight: bold">=</span> (<span style="color: #888888; font-weight: bold">EURToUSD</span>, <span style="color: #888888; font-weight: bold">USDToEUR</span>)
<span style="color: #336699">moneyToEuro</span> <span style="color: #0066bb; font-weight: bold">:</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Exchanges</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span>
<span style="color: #336699">moneyToEuro</span> <span style="color: #336699">mon</span> <span style="color: #336699">con</span> <span style="color: #0066bb; font-weight: bold">=</span>
<span style="color: #008800; font-weight: bold">case</span> <span style="color: #336699">con</span> <span style="color: #008800; font-weight: bold">of</span>
(<span style="color: #336699">euroToUsd</span>, <span style="color: #336699">usdToEur</span>) <span style="color: #0066bb; font-weight: bold">-&gt;</span>
<span style="color: #008800; font-weight: bold">case</span> <span style="color: #336699">mon</span> <span style="color: #008800; font-weight: bold">of</span>
<span style="color: #888888; font-weight: bold">Dollar</span> <span style="color: #336699">usd</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">EUR</span> ((<span style="color: #888888; font-weight: bold">Usd</span><span style="color: #0066bb; font-weight: bold">.</span><span style="color: #336699">extract</span> <span style="color: #336699">usd</span>) <span style="color: #0066bb; font-weight: bold">*</span> <span style="color: #336699">usdToEur</span>)
<span style="color: #888888; font-weight: bold">Euro</span> <span style="color: #336699">eur</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #336699">eur</span>
</pre></div>
<p>Where extract is a function that extracts the amount of the USD.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Elm doesn&rsquo;t have type classes so some things are extra work and are a bit more verbose. But it is possible to enforce a lot at compile time. Furthermore everything is very readable.</p>
<p>Is it worth it of doing it like this? That totally depends on your use case. A lot of times you will want to use <code>type Money = EUR Float | USD Float</code> and use a <code>Maybe</code> type to enforce your constraints, but sometimes you will do the extra work to enforce some things at compile time.</p>
<h2 id="update-2016-04-18">Update 2016-04-18</h2>
<p><em>Zach May</em> left a nice comment (Thanks!) on the blog about an alternative solution:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">USD</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">USD</span>
<span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">EUR</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">EUR</span>
<span style="color: #008800; font-weight: bold">type</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #336699">a</span> <span style="color: #0066bb; font-weight: bold">=</span> <span style="color: #888888; font-weight: bold">Money</span> (<span style="color: #888888; font-weight: bold">Int</span>, <span style="color: #336699">a</span>)
<span style="color: #336699">add</span> <span style="color: #0066bb; font-weight: bold">:</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #336699">a</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #336699">a</span> <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Money</span> <span style="color: #336699">a</span>
<span style="color: #336699">add</span> <span style="color: #336699">m</span> <span style="color: #336699">m&#39;</span> <span style="color: #0066bb; font-weight: bold">=</span>
<span style="color: #008800; font-weight: bold">case</span> (<span style="color: #336699">m</span>, <span style="color: #336699">m&#39;</span>) <span style="color: #008800; font-weight: bold">of</span>
(<span style="color: #888888; font-weight: bold">Money</span> (<span style="color: #336699">i</span>, <span style="color: #336699">a</span>), <span style="color: #888888; font-weight: bold">Money</span> (<span style="color: #336699">i&#39;</span>, <span style="color: #336699">a&#39;</span>)) <span style="color: #0066bb; font-weight: bold">-&gt;</span> <span style="color: #888888; font-weight: bold">Money</span> (<span style="color: #336699">i</span> <span style="color: #0066bb; font-weight: bold">+</span> <span style="color: #336699">i&#39;</span>, <span style="color: #336699">a</span>)
</pre></div>
<p>This solution also enforces strict types when adding money with the advantage that you only need one implementation for add. A possible downside could be if you want your money types to have different number types (for example if you want to model bitcoins not with <code>Int</code>s but with <code>SomeBitcoinNumberType</code>). But like I said in my conclusion, you have to look at your constraints and chose a solution yourself.</p>
Welcomehttps://infinitetree.eu/blog/2016/04/12/welcome/
Tue, 12 Apr 2016 21:28:31 +0200https://infinitetree.eu/blog/2016/04/12/welcome/<p>Welcome to the my new site written in <a href="http://gohugo.io/">hugo</a>.
While busy, I&rsquo;ve set up https via letsencrypt. (see <a href="https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04">tutorial</a>. You can find the source code of the blog <a href="https://github.com/tcoopman/hugo-blog">here</a>.
This is a reboot of my site, and an attempt to blog some more.</p>
<p>So without further ado, let&rsquo;s start blogging :)</p>
Testing ES6 codehttps://infinitetree.eu/blog/2015/01/13/testing-es6-code/
Tue, 13 Jan 2015 00:00:00 +0000https://infinitetree.eu/blog/2015/01/13/testing-es6-code/
<p>Recently, I&rsquo;ve changed my webpack workflow, and switched to <a href="https://6to5.org/">6to5</a>, to be able to write more of my React code in ES6 than the current jsx transpiler supports (and because 6to5 just rocks!). You can find this workflow in my <a href="https://github.com/tcoopman/boilerplate-webpack-react">boilerplate-webpack-react</a> project. Switching was easy. I&rsquo;ve just replaced jsx-loader with 6to5-loader and everything worked correctly.</p>
<p>Writing code and developing is a breeze with this workflow, especially with <a href="https://github.com/gaearon/react-hot-loader">react-hot-loader</a>. I didn&rsquo;t look into writing test though yet, and it took me a little while to find out how to do it, so I explain it here.</p>
<h2 id="karma-webpack">Karma-webpack</h2>
<p>Luckely, there exist a <a href="http://karma-runner.github.io/">karma</a> plugin <a href="https://github.com/webpack/karma-webpack">webpack-karma</a> that allows you to run webpack on files loaded by karma. This means, the test can be written in ES6 (or any other language you prefer that can be transpiled by a webpack loader), and your own code also gets transpiled.</p>
<p>Let me show my setup.</p>
<h3 id="install-dependencies">Install dependencies</h3>
<p>First you need to install all dependencies:</p>
<p><code>npm install --save-dev karma karma-mocha karma-webpack karma-chrome-launcher should</code></p>
<p>I use <a href="http://mochajs.org/">mocha</a> as test framework and <a href="https://github.com/shouldjs/should.js">should</a> as assertion library, but this should work with anything that karma supports.</p>
<h3 id="karma-configuration-file">Karma configuration file</h3>
<p>Next we need to create the karma config file <em>karma.conf.js</em></p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #888888">// Karma configuration</span>
<span style="color: #008800; font-weight: bold">var</span> path = require(<span style="color: #dd2200; background-color: #fff0f0">&#39;path&#39;</span>);
module.exports = <span style="color: #008800; font-weight: bold">function</span>(config) {
config.set({
<span style="color: #888888">// ... normal karma configuration</span>
files: [
<span style="color: #888888">// all files ending in &quot;_test&quot;</span>
<span style="color: #dd2200; background-color: #fff0f0">&#39;test/*_test.jsx&#39;</span>,
<span style="color: #dd2200; background-color: #fff0f0">&#39;test/**/*_test.jsx&#39;</span>
<span style="color: #888888">// each file acts as entry point for the webpack configuration</span>
],
frameworks: [<span style="color: #dd2200; background-color: #fff0f0">&#39;mocha&#39;</span>],
browsers: [<span style="color: #dd2200; background-color: #fff0f0">&#39;Chrome&#39;</span>],
preprocessors: {
<span style="color: #888888">// add webpack as preprocessor</span>
<span style="color: #dd2200; background-color: #fff0f0">&#39;test/data/*.jsx&#39;</span>: [<span style="color: #dd2200; background-color: #fff0f0">&#39;webpack&#39;</span>],
<span style="color: #dd2200; background-color: #fff0f0">&#39;test/*_test.jsx&#39;</span>: [<span style="color: #dd2200; background-color: #fff0f0">&#39;webpack&#39;</span>],
<span style="color: #dd2200; background-color: #fff0f0">&#39;test/**/*_test.jsx&#39;</span>: [<span style="color: #dd2200; background-color: #fff0f0">&#39;webpack&#39;</span>]
},
webpack: {
<span style="color: #888888">// webpack configuration</span>
output: {
path: path.join(__dirname, <span style="color: #dd2200; background-color: #fff0f0">&#39;dist&#39;</span>),
publicPath: <span style="color: #dd2200; background-color: #fff0f0">&#39;/&#39;</span>,
filename: <span style="color: #dd2200; background-color: #fff0f0">&#39;app.js&#39;</span>,
chunkFilename: <span style="color: #dd2200; background-color: #fff0f0">&#39;[chunkhash].js&#39;</span>
},
resolve: {
extensions: [<span style="color: #dd2200; background-color: #fff0f0">&#39;&#39;</span>, <span style="color: #dd2200; background-color: #fff0f0">&#39;.js&#39;</span>, <span style="color: #dd2200; background-color: #fff0f0">&#39;.jsx&#39;</span>, <span style="color: #dd2200; background-color: #fff0f0">&#39;.styl&#39;</span>],
packageMains: [<span style="color: #dd2200; background-color: #fff0f0">&quot;webpack&quot;</span>, <span style="color: #dd2200; background-color: #fff0f0">&quot;browser&quot;</span>, <span style="color: #dd2200; background-color: #fff0f0">&quot;web&quot;</span>, <span style="color: #dd2200; background-color: #fff0f0">&quot;browserify&quot;</span>, <span style="color: #dd2200; background-color: #fff0f0">&quot;main&quot;</span>]
},
module: {
loaders: [
{test: <span style="color: #008800; background-color: #fff0ff">/\.jsx$/</span>, loaders: [<span style="color: #dd2200; background-color: #fff0f0">&#39;6to5-loader&#39;</span>] }
]
}
},
webpackMiddleware: {
<span style="color: #888888">// webpack-dev-middleware configuration</span>
<span style="color: #888888">// i. e.</span>
noInfo: <span style="color: #008800; font-weight: bold">true</span>
},
plugins: [
require(<span style="color: #dd2200; background-color: #fff0f0">&#39;karma-chrome-launcher&#39;</span>),
require(<span style="color: #dd2200; background-color: #fff0f0">&#39;karma-mocha&#39;</span>),
require(<span style="color: #dd2200; background-color: #fff0f0">&#39;karma-webpack&#39;</span>)
]
});
};
</pre></div>
<h3 id="first-test">First test</h3>
<p>We also add a simple _sanity<em>test</em> to make sure everything is setup correctly</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">import</span> should from <span style="color: #dd2200; background-color: #fff0f0">&#39;should&#39;</span>;
describe(<span style="color: #dd2200; background-color: #fff0f0">&#39;sanity test&#39;</span>, () =&gt; {
it(<span style="color: #dd2200; background-color: #fff0f0">&#39;true should be true&#39;</span>, () =&gt; {
<span style="color: #008800; font-weight: bold">true</span>.should.be.ok;
});
});
</pre></div>
<h3 id="first-run">First run</h3>
<p>Now, if we want to run our test, we run:</p>
<p><code>node node_modules/karma/bin/karma start karma.conf.js</code></p>
<p>This should start Chrome (if you don&rsquo;t have chrome, see the <a href="http://karma-runner.github.io/0.12/config/browsers.html">karma browser configuration</a>) and print this:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span>INFO [karma]: Karma v0.12.31 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome <span style="color: #0000DD; font-weight: bold">39</span>.0.2171 (Windows <span style="color: #0000DD; font-weight: bold">7</span>)]: Connected on socket xBMICOzH9lh3Eo9INXDA with id <span style="color: #0000DD; font-weight: bold">55389724</span>
Chrome <span style="color: #0000DD; font-weight: bold">39</span>.0.2171 (Windows <span style="color: #0000DD; font-weight: bold">7</span>): Executed <span style="color: #0000DD; font-weight: bold">1</span> of <span style="color: #0000DD; font-weight: bold">1</span> SUCCESS (<span style="color: #0000DD; font-weight: bold">0</span>.009 secs / <span style="color: #0000DD; font-weight: bold">0</span> secs)
</pre></div>
<p>Every time you change your code it will automatically rerun your tests.</p>
<p>To make it a bit easier to run the test, add the test command to npm:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #dd2200; background-color: #fff0f0">&quot;scripts&quot;</span><span style="color: #a61717; background-color: #e3d2d2">:</span> {
<span style="color: #bb0066; font-weight: bold">&quot;test&quot;</span>: <span style="color: #dd2200; background-color: #fff0f0">&quot;node node_modules/karma/bin/karma start karma.conf.js&quot;</span>
}
</pre></div>
<p>You could also add <code>--single-run</code> if you want to run the test only once and don&rsquo;t watch.</p>
<h2 id="testing-react-code">Testing React code</h2>
<p>The steps above give you a working testing environment, now we can test our code:</p>
<p>To test this we create a simple React component <em>Button.react.jsx</em>:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">import</span> React from <span style="color: #dd2200; background-color: #fff0f0">&#39;react&#39;</span>;
<span style="color: #008800; font-weight: bold">export</span> <span style="color: #008800; font-weight: bold">default</span> React.createClass({
displayName: <span style="color: #dd2200; background-color: #fff0f0">&#39;Button&#39;</span>,
render() {
<span style="color: #008800; font-weight: bold">return</span> &lt;div&gt;button&lt;<span style="color: #a61717; background-color: #e3d2d2">/div&gt;;</span>
}
});
</pre></div>
<p>And we test it in _Button.react<em>test.jsx</em>:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span><span style="color: #008800; font-weight: bold">import</span> React from <span style="color: #dd2200; background-color: #fff0f0">&#39;react/addons&#39;</span>;
<span style="color: #008800; font-weight: bold">import</span> should from <span style="color: #dd2200; background-color: #fff0f0">&#39;should&#39;</span>;
<span style="color: #008800; font-weight: bold">import</span> Button from <span style="color: #dd2200; background-color: #fff0f0">&#39;../app/jsx/components/Button.react&#39;</span>;
<span style="color: #008800; font-weight: bold">const</span> TestUtils = React.addons.TestUtils;
describe(<span style="color: #dd2200; background-color: #fff0f0">&#39;Button&#39;</span>, () =&gt; {
it(<span style="color: #dd2200; background-color: #fff0f0">&#39;renders button div&#39;</span>, () =&gt; {
<span style="color: #008800; font-weight: bold">const</span> button = TestUtils.renderIntoDocument(
&lt;Button /&gt;
);
TestUtils.isCompositeComponent(button).should.be.ok;
button.getDOMNode().textContent.should.be.eql(<span style="color: #dd2200; background-color: #fff0f0">&#39;button&#39;</span>);
});
});
</pre></div>
<p><strong>Easy!</strong></p>
<h3 id="remark">Remark</h3>
<p>While testing, I ran into a problem. This line in HelloWorld.react.jsx: <code>var exampleImage = require('../../images/example.jpg');</code> proved to be a problem. But the problem was quiet obvious to solve, I just needed to add a image loader to the karma webpack configuration:</p>
<div class="highlight" style="background: #ffffff"><pre style="line-height: 125%"><span></span>module: {
loaders: [
{test: <span style="color: #008800; background-color: #fff0ff">/\.jsx$/</span>, loaders: [<span style="color: #dd2200; background-color: #fff0f0">&#39;6to5-loader&#39;</span>] },
<span style="color: #888888">// Add the image loader</span>
{test: <span style="color: #008800; background-color: #fff0ff">/.*\.(gif|png|jpg)$/</span>, loaders: [<span style="color: #dd2200; background-color: #fff0f0">&#39;file?hash=sha512&amp;digest=hex&amp;size=16&amp;name=[hash].[ext]&#39;</span>, <span style="color: #dd2200; background-color: #fff0f0">&#39;image-webpack-loader?optimizationLevel=7&amp;interlaced=false&#39;</span>]}
]
}
</pre></div>
<p>After this, I could test the HelloWorld component too.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Once you have this up, you can test your code with the same setup you already have. Webpack rocks!</p>
<p>If you have any questions, please leave them as an issue at my boilerplate repository (<a href="https://github.com/tcoopman/boilerplate-webpack-react/issues">https://github.com/tcoopman/boilerplate-webpack-react/issues</a>)</p>
<h2 id="commits">Commits</h2>
<p>All steps and code above can be found in the commits between tag 0.0.9 and 0.0.10: <a href="https://github.com/tcoopman/boilerplate-webpack-react/commits/master">https://github.com/tcoopman/boilerplate-webpack-react/commits/master</a></p>
About the site, about mehttps://infinitetree.eu/blog/2014/10/04/about-the-site-about-me/
Sat, 04 Oct 2014 00:00:00 +0000https://infinitetree.eu/blog/2014/10/04/about-the-site-about-me/<p>My name is Thomas Coopman and I&rsquo;m a 29 year old developer. Recently I&rsquo;ve
officially started freelancing/consulting in my spare time. That&rsquo;s the main
reason for creating this site and blog.</p>
<p>On this site you can find some more information <a href="https://infinitetree.eu/about">about me</a>. At the
<a href="https://infinitetree.eu/portfolio">portfolio</a> page you can see some things I&rsquo;ve created. That page is
empty at the moment but it will be coming soon.</p>
<p>I&rsquo;m a developer, mostly a web-developer (backend and frontend). In my main job,
I&rsquo;m a project manager and developer. The main things I do is implementing
GIS systems and viewers, so I&rsquo;ve got a lot of experience with GIS (mainly with
ArcGIS, but I also know Geoserver and leaflet).</p>
<p>If you need someone to help you with the implementation of a custom solution,
GIS or something else. You want to get a second opinion about something
technical. Or you need some help on a project&hellip;
contact me and we can have a chat!</p>
<p>Greetings</p>
<p>Thomas</p>
Creating this sitehttps://infinitetree.eu/blog/2014/09/29/creating-this-site/
Mon, 29 Sep 2014 00:00:00 +0000https://infinitetree.eu/blog/2014/09/29/creating-this-site/
<p><em>This is not valid anymore. The site is build with hugo</em></p>
<p>This blogpost will be a about the why, but mostly about how I&rsquo;ve created
this site.</p>
<p>I&rsquo;ve created this site mostly for these reasons:</p>
<ul>
<li>Make myself visible on the web.</li>
<li>Practice my design and web-development skills.</li>
<li>Practice my writing (blog).</li>
<li>Record things I&rsquo;ve learned for myself. Maybe someone else will find
something useful here.</li>
</ul>
<h1 id="content">Content</h1>
<p>The contents of this site contain information about me, to make me more
visible on the web. The site includes a blog with primarly technical content. In
the first place javascript and web-development although this can change
depending on my interests at that moment and what I&rsquo;m working about.</p>
<p>Secondly, I&rsquo;ll try to blog about some of my hobbies (hiking for example),
but that will be very occasional.</p>
<h1 id="framework">Framework</h1>
<p>I&rsquo;ve created this site in <a href="http://facebook.github.io/react/">Reactjs</a>, my
current favorite javascript framework that I like for the same reasons everyone
else likes it. There are lots of blogs
about react so I&rsquo;ll try to keep the redundancy low and only talk about the new
things.</p>
<p>I&rsquo;m using <a href="https://github.com/rackt/react-router">react-router</a> for the routing.
At the moment of writing there are some shortcomings
(mostly no server-side rendering<sup>1</sup>), but these guys are working
on that and we can expect it shortly. As soon as server side rendering is
supported, I&rsquo;ll add it so this site can be easily searched with
Google, and then it should also be mostly useful without javascript.</p>
<p>For the css I&rsquo;m using the <a href="http://learnboost.github.io/stylus/">stylus</a> preprocessor.
I&rsquo;ve tried Less and Sass in the past but I like stylus, and this site is a
good way of exploring it. I try to keep the site low on css and don&rsquo;t
use a framework like bootstrap or foundation.</p>
<h1 id="blog">Blog</h1>
<p>The blog is written with my own implementation of a React markdown component
that I&rsquo;ve <a href="https://github.com/tcoopman/markdown-react">published</a><sup>2</sup>. In short, it uses an existing markdown parser,
but instead of rendering a html string, it renders React components. The cool
thing about this is that you can have full control over the React components, so
you can do all kind of cool things with. For example add a custom subscript
to every image or parse different html than what you normally want (like I do in
this blog. Here I render &lt;h2&gt; elements instead of &lt;h1&gt;). Of course you can do
all these things if you know something about parsing, but this component makes this
super easy if you know React, just substitute the main component for your own and
you&rsquo;re started. I&rsquo;m planning on writing a short blog post about this component too.</p>
<p>Stay tuned!</p>
<h1 id="hosting-and-deploying">Hosting and deploying</h1>
<p>I build this site with gulp and webpack. My boilerplate package
can be found at <a href="https://github.com/tcoopman/boilerplate-webpack-react">boilerplate-webpack-react</a>.
This site uses a very similar build, with some adaptations for the blog.</p>
<p>This website is hosted on <a href="https://www.digitalocean.com/">DigitalOcean</a> with Nginx.
At the moment it&rsquo;s just a static app, but as soon as react-router supports server
rendering I&rsquo;m going to implement it. I need to set up automatic deployment, probably with git.
I don&rsquo;t build my site on the server. I push the build to the server.
When server side rendering is implemented, the way I deploy my code will change
and I also have a blog about that in the pipeline.</p>
<h1 id="conclusion">Conclusion</h1>
<p>A custom implementation of a blog, custom css and hosted on a vps. And that for
a static site. It&rsquo;s a bit more work, and you could say it&rsquo;s not a best practice
to do things this way, but it&rsquo;s a good way to experiment and try new things and
that&rsquo;s exactly what I want to do with this site.</p>
<hr />
<p><sup>1</sup> This has been fixed in a recent version.</p>
<p><sup>2</sup> I&rsquo;ve switched to <a href="https://github.com/jonschlinkert/remarkable">remarkable</a></p>
Contacthttps://infinitetree.eu/contact/
Fri, 11 Jul 2014 10:54:24 +0200https://infinitetree.eu/contact/
<p><strong>Email</strong><br />
<a href="mailto:thomas.coopman@infitetree.eu">thomas.coopman@infinitetree.eu</a><br />
<strong>Phone</strong><br />
+32 491 08 06 16<br />
<strong>Website</strong><br />
<a href="http://infinitetree.eu">infinitetree.eu</a><br />
<strong>Location</strong><br />
Aartselaar - Belgium</p>
<h3 id="profiles">Profiles</h3>
<p><strong>Github</strong><br />
<a href="https://github.com/tcoopman">tcoopman</a><br />
<strong>Bitbucket</strong><br />
<a href="https://bitbucket.org/tcoopman/">tcoopman</a><br />
<strong>Twitter</strong><br />
<a href="https://twitter.com/tcoopman">tcoopman</a><br />
<strong>Google+</strong><br />
<a href="https://plus.google.com/u/0/109624499308077610663">thomascoopman</a></p>
https://infinitetree.eu/home/
Mon, 01 Jan 0001 00:00:00 +0000https://infinitetree.eu/home/<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Infinite Tree</title>
<meta name="description" content="Infinite Tree Website">
<meta name="author" content="Thomas Coopman">
<link href="https://fonts.googleapis.com/css?family=Montserrat|Neuton" rel="stylesheet">
<link rel="stylesheet" href="https://infinitetree.eu/css/index.css">
</head>
<body>
<main>
<div>
<img src="https://infinitetree.eu/images/logo.png" />
</div>
<div class="header">
<h2><a href="https://thomascoopman.eu">BLOG</a></h2>
</div>
</main>
</body>
</html>