· 10 years ago · Sep 14, 2016, 10:43 AM
1<?xml version="1.0" encoding="UTF-8"?>
2 <rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">
3 <channel>
4 <title>De Voorhoede</title>
5 <link>https://www.voorhoede.nl/</link>
6 <description>We are De Voorhoede, front-end developers. We build front-end solutions which you can use for years to come.</description>
7 <language>en</language>
8 <lastBuildDate>Wed, 14 Sep 2016 09:57:01 GMT</lastBuildDate>
9 <atom:link href="https://www.voorhoede.nl/feed.xml" rel="self" type="application/rss+xml" />
10 <atom:link rel="hub" href="http://pubsubhubbub.appspot.com" />
11 <image>
12 <link>https://www.voorhoede.nl/</link>
13 <title>De Voorhoede</title>
14 <url>https://www.voorhoede.nl/assets/images/logo.png</url>
15 <description>De Voorhoede logo</description>
16 </image>
17 <item>
18 <title>5 tips for effective daily standups</title>
19 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/5-tips-for-effective-daily-standups</guid>
20 <pubDate>Mon, 01 Aug 2016 00:00:00 GMT</pubDate>
21 <link>https://www.voorhoede.nl/en/blog/5-tips-for-effective-daily-standups</link>
22 <dc:creator><![CDATA[Reinout]]></dc:creator>
23 <category><![CDATA[daily]]></category>
24<category><![CDATA[standup]]></category>
25<category><![CDATA[kanban]]></category>
26<category><![CDATA[agile]]></category>
27<category><![CDATA[tips]]></category>
28<category><![CDATA[scrum]]></category>
29 <description><![CDATA[Daily standup meetings can sometimes feel long, repetitive or even like a waste of time. Here are some tips to get more out of your standup meeting]]></description>
30 <content:encoded><![CDATA[<h1 id="5-tips-for-effective-daily-standups">5 tips for effective daily standups</h1>
31<p>Ever felt that daily standups meetings can be long, repetitive or even feel like a waste of time? They shouldn’t be. A standup plays <a href="http://martinfowler.com/articles/itsNotJustStandingUp.html#TheParticularSetOfProblemsThatOccurWhenPeopleAttemptToWorkTogether">a vital role</a> in Scrum or Kanban. Learn how to get more out of your standup meetings with a few practical tips:</p>
32<h2 id="1-prepare">1. Prepare</h2>
33<p>Update the status of your stories (or tasks) on the storyboard before the meeting. Write down the things you’ve done yesterday on a post-it. Bad memory? In Jira you can use the quick filters 'Recently updated' in combination with 'Only my issues'. Or generate a list of git commits with <a href="https://github.com/kamranahmedse/git-standup">git standup</a>. Keep in mind that your team is your audience, not the Scrum Master. </p>
34<p><img src="https://www.voorhoede.nl/assets/images/git-standup.gif" title="Example of git-standup in iTerm2" alt="git standup in iTerm2" /></p>
35<p>Not physically together in the same room? Setup a <a href="http://behindcompanies.com/2014/01/set-up-a-permanent-google-hangout-for-easy-collaboration/">permanent Google Hangout</a> and use an <a href="http://www.mxlmics.com/microphones/web-conferencing/AC-404/">omnidirectional microphone</a>. Using a permanent hangout team members can test their connection beforehand. Try muting your microphone when not speaking to avoid background noise.</p>
36<h2 id="2-routine">2. Routine</h2>
37<p>Is someone on holidays? Missed the train? Working from home?</p>
38<p>Always start the standup on time with the people who are present at that moment. It’s better to have the whole team there, but it should not be a reason to delay or cancel. Not many updates? Keep the meeting shorter.</p>
39<p>There are plenty of reasons to start the meeting later, but this delays work for the rest of the team. And it frustrates people. Even worse, it may result in losing trust in doing standups at all.</p>
40<h2 id="3-visualize">3. Visualize</h2>
41<p>Everyone gathers around the storyboard during the standup. The storyboard should be visible to anyone, always. To make sure only one person is speaking at a time use a prop, such as a <a href="https://en.wikipedia.org/wiki/Stress_ball">stress ball</a>. Pass the ball on to the next person when you’re done. Rather than talking about story numbers or titles, point to them on the board.</p>
42<p>Personalize the stories you work on with <a href="http://www.faceyourmanga.com/">avatars</a>. If a story is not finished, mark it with a dot. A story that is open for (e.g.) 3 days will have 3 dots. This helps the team to track progress or identify impediments.</p>
43<p>If you prefer a digital storyboard (e.g. Jira) enable the view without swimming lanes, so that all stories appear on top. This gives a good overview of what the team is working on.</p>
44<p><img src="https://www.voorhoede.nl/assets/images/storyboard.png" title="Storyboard in Atlassian Jira with swimming lanes disabled" alt="Jira storyboard" /></p>
45<h2 id="4-energize">4. Energize</h2>
46<p>A standup is not just a status meeting. It helps the team to understand that they are on the right track and to identify as a team. Every now and then invite a stakeholder to the standup as well. Stakeholders are the connection between the team and the user. They embody why the team is doing the work and for whom. </p>
47<p>Although a standup is not the place for discussions, often important and useful ideas come up.
48It is sometimes the only moment of the day when the full team is available and listening. Rather than to kill any input during the standup, encourage people to bring up new ideas or things that need attention. Finding solutions for things that are brought up should be done after the standup though.</p>
49<h2 id="5-evaluate">5. Evaluate</h2>
50<p>The format for standups is simple: each person tells what he did yesterday, what he will do today and if there are any impediments. People should be standing (and not sitting or leaning) during the meeting and it should not be longer than 15 minutes. For the rest, Scrum is not very prescriptive about standups. There are no magic ingredients.</p>
51<p>That said, a good standup is different for every team. Regularly evaluate with the team if they are happy about it. Make sure there is routine, but also keep it fun. Switch the facilitator role, play a sound when the startup starts, try out different conferencing tools or do the <a href="https://twitter.com/signar/status/728161170906075136">standup while planking</a>.</p>
52<p><img src="https://www.voorhoede.nl/assets/images/planking-during-standup.jpg" title="Planking during the standup" alt="Planking during the standup" /></p>
53]]></content:encoded>
54 </item>
55<item>
56 <title>Why our website is faster than yours</title>
57 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/why-our-website-is-faster-than-yours</guid>
58 <pubDate>Tue, 26 Jul 2016 00:00:00 GMT</pubDate>
59 <link>https://www.voorhoede.nl/en/blog/why-our-website-is-faster-than-yours</link>
60 <dc:creator><![CDATA[Declan]]></dc:creator>
61 <category><![CDATA[performance]]></category>
62<category><![CDATA[critical rendering path]]></category>
63<category><![CDATA[static site]]></category>
64<category><![CDATA[design for performance]]></category>
65 <description><![CDATA[Our secrets revealed to getting a blazing fast website.]]></description>
66 <content:encoded><![CDATA[<h1 id="why-our-website-is-faster-than-yours">Why our website is faster than yours</h1>
67<p>We recently updated our site. Yes, it has a complete design overhaul, but as real software developers we focused a lot on the technical bits and pieces as well. Our goal was to take control, focus on performance, be flexible for the future and make it fun to write content for the site. Here’s how we made our website faster than yours (Yup, sorry!)</p>
68<h2 id="design-for-performance">Design for performance</h2>
69<p>In our projects we have daily discussions with designers and product owners about balancing aesthetics and performance. For our own site, this was easy. Simply said: we believe that a good user experience starts with delivering content as fast as possible. That means <strong>performance > aesthetics</strong>. </p>
70<p>Good content, layout, images, and interactivity are essential for engaging your audience, but each of these elements have impact on page load time and the end-user experience. In every step we looked at how we could get a nice user experience and design while having minimum impact on performance. </p>
71<h2 id="content-first">Content first</h2>
72<p>We want to serve the core content — meaning copy with the essential HTML and CSS — to our visitors as fast as possible. Every page should support the primary purpose of the content: get the message across. Enhancements, meaning JavaScript, complete CSS, web fonts, images and analytics are inferior to the core content.</p>
73<h2 id="take-control">Take control</h2>
74<p>After defining the standards we set for our ideal site, we concluded that we needed full control over every aspect of the site. We chose to build our own static site generator, including asset pipeline, and host it ourselves.</p>
75<h3 id="static-site-generator">Static site generator</h3>
76<p>We’ve written our own static site generator in Node.js. It takes Markdown files with short JSON page meta descriptions to generate the complete site structure with all of its assets. It can also be accompanied by a HTML file for including page-specific JavaScript.</p>
77<p>See below a simplified meta description and markdown file for this blog post, used to generate the actual HTML.</p>
78<p>The JSON meta description:</p>
79<pre><code class="lang-javascript">{
80 "keywords": ["performance", "critical rendering path", "static site", "..."],
81 "publishDate": "2016-07-13",
82 "authors": ["Declan"]
83}
84</code></pre>
85<p>And the markdown file:</p>
86<pre><code># Why our website is faster than yours
87We've recently updated our site. Yes, it has a complete...
88
89## Design for performance
90In our projects we have daily discussions...
91</code></pre><h2 id="image-delivery">Image delivery</h2>
92<p>The <a href="http://httparchive.org/interesting.php">average webpage is a whopping 2406kb of which 1535kb are images</a>. With images taking up such a big part of the average website, it is also one of the best targets for performance wins.</p>
93<p><img src="https://www.voorhoede.nl/assets/images/average-bytes-per-page-chart.jpg" title="Average bytes per page by content type for July 2016 from httparchive.org" alt="Average bytes per page by content type chart" /></p>
94<h3 id="webp">WebP</h3>
95<p>WebP is a modern image format that provides superior lossless and lossy compression for images on the web. WebP images can be substantially smaller than images of other formats: sometimes they are up to 25% smaller than their JPEG counterpart. WebP is overlooked a lot and not often used. At the time of writing, WebP support is limited to <a href="http://caniuse.com/#feat=webp">Chrome, Opera and Android</a> (still over 50% of our users), but we can degrade gracefully to JPG/PNG.</p>
96<h3 id="-picture-element"><code><picture></code> element</h3>
97<p>Using the picture element we can degrade gracefully from WebP to a more widely supported format like JPEG:</p>
98<pre><code class="lang-html"><picture>
99 <source type="image/webp" srcset="image-l.webp" media="(min-width: 640px)">
100 <source type="image/webp" srcset="image-m.webp" media="(min-width: 320px)">
101 <source type="image/webp" srcset="image-s.webp">
102 <source srcset="image-l.jpg" media="(min-width: 640px)">
103 <source srcset="image-m.jpg" media="(min-width: 320px)">
104 <source srcset="image-s.jpg">
105 <img alt="Description of the image" src="image-l.jpg">
106</picture>
107</code></pre>
108<p>We use <a href="https://github.com/scottjehl/picturefill">picturefill by Scott Jehl</a> to polyfill browsers not supporting the <code><picture></code> element and to get consistent behaviour across all browsers.</p>
109<p>We use the <code><img></code> as a fallback for browsers not supporting the <code><picture></code> element and/or JavaScript. Using the image’s largest instance makes sure it still looks good in the fallback scenario.</p>
110<h3 id="generate">Generate</h3>
111<p>While the image delivery approach was in place, we still had to figure out how to painlessly implement it. I love the picture element for what it can do, but I hate writing the snippet above. Especially if I have to include it while writing content. We don't want to bother with generating 6 instances of every image, optimising the images and writing <code><picture></code> elements in our markdown. So we:</p>
112<ul>
113<li><strong>generate</strong> multiple instances of the original images in our build process, both in the input format (JPG, PNG) as in WebP. We use <a href="https://github.com/mahnunchik/gulp-responsive">gulp responsive</a> to do so.</li>
114<li><strong>minify</strong> the generated images</li>
115<li><strong>write</strong> <code></code> in our markdown files.</li>
116<li>use custom written Markdown renderers during the build process to <strong>compile</strong> conventional markdown image declarations to full blown <code><picture></code> elements.</li>
117</ul>
118<h2 id="svg-animations">SVG animations</h2>
119<p>We chose a distinct graphic style for our site, in which SVG illustrations play a major role. We did this for several reasons. </p>
120<ul>
121<li>Firstly, SVG's (vector images) tend to be smaller than bitmap images;</li>
122<li>Secondly SVG's are responsive by nature and scale perfectly while always staying super crisp. So no need for image generation and <code><picture></code> elements; </li>
123<li>Last but not least we can animate and alter them by CSS! A perfect example of designing for performance. <a href="https://www.voorhoede.nl/en/portfolio/">All our portfolio pages</a> have a custom made animated SVG that is reused on the overview page. It serves as a recurring style for all our portfolio items making the design consistent, while having very little impact on performance.</li>
124</ul>
125<p>Check out this animation and how we can alter it with CSS.</p>
126<div style="text-align: center;">
127 <svg version="1.1" id="svg-animation-example" class="svg-line-drawing rtl-magazine-animation" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="720" height="310" viewBox="0 0 720 310" xml:space="preserve" aria-hidden="true" >
128 <defs>
129 <clipPath id="mask-page">
130 <path class="stroke-alt stroke-width linecap" d="m240,275 l240,0 0,-217 -240,0z" />
131 </clipPath>
132 </defs>
133 <!-- content page -->
134 <g clip-path="url(#mask-page)">
135 <g class="ani-move-page is-animated">
136 <!-- section one -->
137 <path class="stroke stroke-width linecap" d="m0,275 m254,-203 l212,0 0,112 -212,0z" fill="none" />
138 <path class="stroke-alt stroke-width linecap" d="m0,275 m272,-172 a13 13 180 0 1 26,0 a13 13 180 0 1 -26,0" fill="none" />
139 <path class="stroke stroke-width linecap" d="m0,275 m254,-203 m22,112 l34,-44 a9 9 180 0 1 13,-1 l15,16 38,-48 a5 5 180 0 1 8.4,0 l60,77" fill="none" />
140 <path class="stroke stroke-width linecap" d="m0,275 m254,-67 l212,0 m-212,10 l54,0 m25,0 l54,0 m25,0 l54,0 m-212,10 l54,0 m25,0 l54,0 m25,0 l54,0" fill="none" />
141 <!-- button section one -->
142 <path class="stroke stroke-width linecap" d="m350,250 a10 10 180 0 1 20,0 a10 10 180 0 1 -20,0 m6.8,-1.7 l3.2,3.2 3.2,-3.2" fill="none" />
143 <path class="stroke stroke-width linecap" d="m318,290 l0,430" fill="none" />
144 <path class="stroke stroke-width linecap" d="m333,306 l54,0 m-54,10 l54,0 m-54,10 l133,0 m-133,10 l133,0" fill="none" />
145 <path class="stroke stroke-width linecap" d="m333,356 l133,0 0,78 -133,0 0,-78 m0,90 l54,0 m-54,10 l54,0 m-54,20 133,0 0,78 -133,0 0,-78 m0,90 l54,0 m-54,10 l54,0 m-54,20 133,0 0,78 -133,0 0,-78 m0,90 l54,0 m-54,10 l54,0 m-54,20" fill="none" />
146 <!-- section two -->
147 <path class="stroke stroke-width linecap" d="m0,680 m0,275 m254,-203 l212,0 0,112 -212,0z" fill="none" />
148 <path class="stroke-alt stroke-width linecap" d="m0,680 m0,275 m272,-172 a13 13 180 0 1 26,0 a13 13 180 0 1 -26,0" fill="none" />
149 <path class="stroke stroke-width linecap" d="m0,680 m0,275 m254,-203 m22,112 l34,-44 a9 9 180 0 1 13,-1 l15,16 38,-48 a5 5 180 0 1 8.4,0 l60,77" fill="none" />
150 <path class="stroke stroke-width linecap" d="m0,680 m0,275 m254,-67 l212,0 m-212,10 l54,0 m25,0 l54,0 m25,0 l54,0 m-212,10 l54,0 m25,0 l54,0 m25,0 l54,0" fill="none" />
151 <!-- button section two -->
152 <path class="stroke stroke-width linecap" d="m0,680 m350,250 a10 10 180 0 1 20,0 a10 10 180 0 1 -20,0 m6.8,-1.7 l3.2,3.2 3.2,-3.2" fill="none" />
153 </g>
154 <g class="ani-move-menu is-animated">
155 <g>
156 <path class="stroke stroke-width linecap" d="m254,306 l54,0 m-54,10 l54,0 m-54,10 l54,0 m-54,10 l54,0" fill="none" />
157 </g>
158 </g>
159 </g>
160 <!-- fade button -->
161 <g class="ani-fade-button is-animated" opacity="0" >
162 <path class="stroke-background stroke-overlay linecap" d="m350,250 a10 10 180 0 1 20,0 a10 10 180 0 1 -20,0 m6.8,-1.7 l3.2,3.2 3.2,-3.2" fill="none" />
163 <path class="stroke-alt stroke-width linecap" d="m350,250 a10 10 180 0 1 20,0 a10 10 180 0 1 -20,0 m6.8,-1.7 l3.2,3.2 3.2,-3.2" fill="none" />
164 </g>
165 <!-- baseline -->
166 <path class="stroke stroke-width linecap" d="m0,275 l240,0 0,-230 a5 5 90 0 1 5,-5 l230,0 a5 5 90 0 1 5,5 l0,230 240,0" fill="none" />
167 <path class="stroke stroke-width linecap" d="m0,275 m240,-217 l240,0" fill="none" />
168 <path class="stroke stroke-width linecap" d="m0,275 m240,-226 m10,0 a4 4 180 0 1 8,0 a4 4 180 0 1 -8,0 m14,0 a4 4 180 0 1 8,0 a4 4 180 0 1 -8,0 m14,0 a4 4 180 0 1 8,0 a4 4 180 0 1 -8,0" fill="none" />
169 <defs>
170 <style>
171
172 .svg-line-drawing {
173 width: 100%;
174 }
175
176 .svg-line-drawing .stroke-background {
177 stroke: #eddd3e;
178 }
179
180 .svg-line-drawing .stroke {
181 stroke: #12353C;
182 }
183
184 .svg-line-drawing .stroke-alt {
185 stroke: #ffffff;
186 }
187
188 .svg-line-drawing .stroke-width {
189 stroke-width: 2;
190 }
191
192 .svg-line-drawing .stroke-overlay {
193 stroke-width: 3;
194 }
195
196 .svg-line-drawing .linecap {
197 stroke-linecap: round;
198 stroke-linejoin: round;
199 }
200
201 .rtl-magazine-animation .ani-fade-button,
202 .rtl-magazine-animation .ani-move-page,
203 .rtl-magazine-animation .ani-move-menu {
204 -webkit-animation-duration: 5500ms;
205 animation-duration: 5500ms;
206 -webkit-animation-timing-function: ease;
207 animation-timing-function: ease;
208 -webkit-animation-delay: 100ms;
209 animation-delay: 100ms;
210 -webkit-animation-iteration-count: infinite;
211 animation-iteration-count: infinite;
212 }
213
214 .rtl-magazine-animation .ani-fade-button {
215 -webkit-animation-name: fade-button;
216 animation-name: fade-button;
217 }
218
219 .rtl-magazine-animation .ani-move-page {
220 -webkit-animation-name: move-page;
221 animation-name: move-page;
222 }
223
224 .rtl-magazine-animation .ani-move-menu {
225 -webkit-animation-name: move-menu;
226 animation-name: move-menu;
227 }
228
229 @-webkit-keyframes fade-button {
230 0%, 12%, 100% { opacity: 0; }
231 9%, 11% { opacity: 1; }
232 }
233
234 @keyframes fade-button {
235 0%, 12%, 100% { opacity: 0; }
236 9%, 11% { opacity: 1; }
237 }
238
239 @-webkit-keyframes move-page {
240 0%, 14%, 100% { -webkit-transform: translateY(0px); -webkit-animation-timing-function: ease-in; }
241 28% { -webkit-transform: translateY(-220px); -webkit-animation-timing-function: linear; }
242 80%, 99.9999% { -webkit-transform: translateY(-680px); -webkit-animation-timing-function: linear; }
243 }
244
245 @keyframes move-page {
246 0%, 14%, 100% { transform: translateY(0px); animation-timing-function: ease-in; }
247 28% { transform: translateY(-220px); animation-timing-function: linear; }
248 80%, 99.9999% { transform: translateY(-680px); animation-timing-function: linear; }
249 }
250
251 @-webkit-keyframes move-menu {
252 0%, 14%, 100% { -webkit-transform: translateY(0px); -webkit-animation-timing-function: ease-in; }
253 28%, 68.6957% { -webkit-transform: translateY(-220px); -webkit-animation-timing-function: linear; }
254 80% { -webkit-transform: translateY(-320px); -webkit-animation-timing-function: linear; }
255 99.9999% { -webkit-transform: translateY(-680px); -webkit-animation-timing-function: linear; }
256 }
257
258 @keyframes move-menu {
259 0%, 14%, 100% { transform: translateY(0px); animation-timing-function: ease-in; }
260 28%, 68.6957% { transform: translateY(-220px); animation-timing-function: linear; }
261 80% { transform: translateY(-320px); animation-timing-function: linear; }
262 99.9999% { transform: translateY(-680px); animation-timing-function: linear; }
263 }
264
265 </style>
266 </defs>
267 </svg>
268
269 <noscript><p style="text-align:left;">Sorry, JavaScript needs to be enabled to change the svg styling with this button.</p></noscript>
270 <button type="button" id="change-svg-style-button" class="btn btn-primary" disabled onclick="changeSvgStyle()">Change style</button>
271</div>
272
273<h2 id="custom-web-fonts">Custom web fonts</h2>
274<p>Before diving in, here’s a short primer on browser behaviour regarding custom web fonts. When the browser comes across a <code>@font-face</code> definition in CSS that points to a font not available on the user’s computer, it will try to download this font file. While the download happens, most browsers don’t display the text using this font. At all. This phenomenon is called the “Flash of Invisible Text†or FOIT. If you know what to look for, you will find it almost everywhere on the web. And if you ask me, it is bad for the end-user experience. It delays the user in reaching their core goal: reading the content.</p>
275<p>We can however force the browser to change its behaviour into a “Flash of Unstyled Content†or FOUT. We tell the browser to use an ubiquitous font at first, like Arial or Georgia. Once the custom web font is downloaded it will replace the standard font and re-render all text. If the custom font fails to load, the content is still perfectly readable. While some might consider this a fallback, we see custom fonts as an enhancement. Even without it, the site looks fine and works 100%. Just toggle our custom fonts by checking/unchecking the checkbox and see for yourself:</p>
276<p><noscript><p>Sorry, JavaScript needs to be enabled to toggle the fonts-loaded class with this checkbox.</p></noscript></p>
277<div class="checkbox" style="text-align:center;">
278 <input type="checkbox" id="toggle-fonts-loaded-checkbox" disabled onchange="toggleFontsLoadedClass()"-input>
279 <label class="label-text" for="toggle-fonts-loaded-checkbox">Toggle fonts-loaded class</label>
280</div>
281
282<p>Using custom web fonts can benefit the user experience, as long as you optimise and serve them responsibly. </p>
283<h3 id="font-subsetting">Font subsetting</h3>
284<p>Subsetting is by far the quickest win in improving webfont performance. I would recommend it to every web developer using custom fonts. You can go all out with subsetting if you have complete control over the content and know which characters will be displayed. But even just subsetting your font to "Western languages" will have a huge impact on file size. For example, our Noto Regular <code>WOFF</code> font, which is 246KB by default, drops to 31KB when subsetted to Western languages. We used the <a href="https://www.fontsquirrel.com/tools/webfont-generator">Font squirrel webfont generator</a> which is really easy to use. </p>
285<h3 id="font-face-observer">Font face observer</h3>
286<p><a href="https://github.com/bramstein/fontfaceobserver">Font face observer by Bram Stein</a> is an awesome helper script for checking whether fonts are loaded. It is agnostic as to how you load your fonts, be it via a webfont service or hosting them yourself. After the font face observer script notifies us that all custom web fonts are loaded, we add a <code>fonts-loaded</code> class to the <code><html></code> element. We style our pages accordingly:</p>
287<pre><code class="lang-css">html {
288 font-family: Georgia, serif;
289}
290
291html.fonts-loaded {
292 font-family: Noto, Georgia, serif;
293}
294</code></pre>
295<p><em>Note: For brevity, I did not include the <code>@font-face</code> declaration for Noto in the CSS above.</em></p>
296<p>We also set a cookie to remember that all fonts are loaded, and therefore live in the browser’s cache. We use this cookie for repeating views, which I will explain a bit later.</p>
297<p>In the near future we probably do not need Bram Stein’s JavaScript to get this behaviour. The CSS Working Group has proposed a new <code>@font-face</code> descriptor (called <code>font-display</code>), where the property value controls how a downloadable font renders before it is fully loaded. The css statement <code>font-display: swap</code> would give us the same behaviour as the approach above. <a href="https://developers.google.com/web/updates/2016/02/font-display">Read more on the <code>font-display</code> property</a>.</p>
298<h2 id="lazy-load-js-and-css">Lazy load JS and CSS</h2>
299<p>Generally speaking we have an approach of loading in assets as soon as possible. We eliminate render blocking requests and optimise for the first view, leveraging the browser cache for repeated views.</p>
300<h3 id="lazy-load-js">Lazy load JS</h3>
301<p>By design, we do not have a lot of JavaScript in our site. For what we do have, and what we intend to use in the future, we developed a JavaScript workflow.</p>
302<p>JavaScript in the <code><head></code> blocks rendering, and we don't want that. JavaScript should only enhance the user experience; it is not critical for our visitors. The easy way to fix the render blocking JavaScript is to place the script in the tail of your webpage. The downside is that it will only start downloading the script after the complete HTML is downloaded. </p>
303<p>An alternative could be to add the script to the head and defer the script execution by adding the <code>defer</code> attribute to the <code><script></code> tag. This makes the script non-blocking as the browser downloads it almost immediately, without executing the code until the page is loaded.</p>
304<p>There is just one thing left, we don't use libraries like jQuery and thus our JavaScript depends on vanilla JavaScript features. We only want to load JavaScript in browsers supporting these features. The end result looks like this:</p>
305<pre><code class="lang-html"><script>
306if ('querySelector' in document && 'addEventListener' in window) {
307 document.write('<script src="index.js" defer><\/script>');
308}
309</script>
310</code></pre>
311<p>We place this little inline script in the head of our page detecting whether the vanilla JavaScript <code>document.querySelector</code> and <code>window.addEventListener</code> features are supported. If so, we load the script by writing the <code>script</code> tag directly to the page, and use the <code>defer</code> attribute to make it non-blocking.</p>
312<h3 id="lazy-load-css">Lazy load CSS</h3>
313<p>For the first view the biggest render blocking resource for our site is CSS. Browsers delay page rendering until the full CSS file referenced in the <code><head></code> is downloaded and parsed. This behaviour is deliberate, otherwise the browser would need to recalculate layouts and repaint all the time during rendering. </p>
314<p>To prevent CSS from render blocking, we need to asynchronously load the CSS file. We use the awesome <a href="https://github.com/filamentgroup/loadCSS">loadCSS function by the Filament Group</a>. It will give you a callback when the CSS file is loaded, where we set a cookie stating that the CSS is loaded. We use this cookie for repeating views, which I will explain a bit later.</p>
315<p>There is one ‘problem’ with loading in CSS asynchronously, in that while the HTML is being rendered really fast it will look like plain HTML with no CSS applied, until the full CSS is downloaded and parsed. This is where critical CSS comes in.</p>
316<h3 id="critical-css">Critical CSS</h3>
317<p>Critical CSS can be described as <em>the minimum amount of blocking CSS to make a page appear recognisable for the user</em>. We focus on ‘above the fold’ content. Obviously the location of the fold differs greatly between devices, so we make a best guess.</p>
318<p>Manually determining this critical CSS is a time consuming process, especially during future style changes. There are several nifty scripts for generating critical CSS in your build process. We used the magnificent <a href="https://github.com/addyosmani/critical">critical by Addy Osmani</a>. </p>
319<p>See below our homepage rendered with critical CSS and rendered with the full CSS. Notice the fold where below the fold the page is still sort of unstyled.</p>
320<p><img src="https://www.voorhoede.nl/assets/images/voorhoede-fold.jpg" title="On the left the homepage rendered with only critical CSS, on the right the homepage rendered with the full CSS. The red line representing the fold." alt="Fold illustration" /></p>
321<h2 id="the-server">The server</h2>
322<p>We host de Voorhoede site ourselves, because we wanted to have control over the server environment. We also wanted to experiment how we could boost performance by changing server configuration. At this time we have an Apache web server and we serve our site over HTTPS.</p>
323<h3 id="configuration">Configuration</h3>
324<p>To boost performance and security we did a little research on how to configure the server. </p>
325<p>We use <a href="https://github.com/h5bp/server-configs-apache">H5BP boilerplate apache configuration</a>, which is a great start for improving performance and security for your Apache web server. They have configurations for other server environments as well.</p>
326<p>We turned on GZIP for most of our HTML, CSS and JavaScript. We set caching headers neatly for all our resources. Read about that below in <a href="#file-level-caching">the file level caching section</a>.</p>
327<h3 id="https">HTTPS</h3>
328<p>Serving your site over HTTPS can have a performance impact for your site. The performance penalty is mainly from setting up the SSL handshake, introducing a lot of latency. But — as always — we can do something about that!</p>
329<p><strong>HTTP Strict Transport Security</strong> is a HTTP header that lets the server tell the browser that it should only be communicated with using HTTPS. This way it prevents HTTP requests from being redirected to HTTPS. All attempts to access the site using HTTP should automatically be converted. That saves us a roundtrip!</p>
330<p><strong>TLS false start</strong> allows the client to start sending encrypted data immediately after the first TLS roundtrip. This optimization reduces handshake overhead for new TLS connections to one roundtrip. Once the client knows the encryption key it can begin transmitting application data. The rest of the handshake is spent confirming that nobody has tampered with the handshake records, and can be done in parallel.</p>
331<p><strong>TLS session resumption</strong> saves us another roudtrip by making sure that if the browser and the server have communicated over TLS in the past, the browser can remember the session identifier and the next time it sets up a connection, that identifier can be reused, saving a round trip.</p>
332<p>I sound like a dev ops engineer, but I’m not. I just read some things and watched some videos. I loved <a href="https://www.youtube.com/watch?v=YMfW1bfyGSY">Mythbusting HTTPS: Squashing security’s urban legends by Emily Stark</a> from Google I/O 2016.</p>
333<h3 id="use-of-cookies">Use of cookies</h3>
334<p>We don't have a server side language, just a static Apache web server. But an Apache web server can still do server side includes (SSI) and read out cookies. By making smart use of cookies and serving HTML that is partially rewritten by Apache, we can boost front-end performance. Take this example below (our actual code is a little more complex, but boils down to the same ideas):</p>
335<pre><code class="lang-html"><!-- #if expr="($HTTP_COOKIE!=/css-loaded/) || ($HTTP_COOKIE=/.*css-loaded=([^;]+);?.*/ && ${1} != '0d82f.css' )"-->
336
337<noscript><link rel="stylesheet" href="0d82f.css"></noscript>
338<script>
339(function() {
340 function loadCSS(url) {...}
341 function onloadCSS(stylesheet, callback) {...}
342 function setCookie(name, value, expInDays) {...}
343
344 var stylesheet = loadCSS('0d82f.css');
345 onloadCSS(stylesheet, function() {
346 setCookie('css-loaded', '0d82f', 100);
347 });
348}());
349</script>
350
351<style>/* Critical CSS here */</style>
352
353<!-- #else -->
354<link rel="stylesheet" href="0d82f.css">
355<!-- #endif -->
356</code></pre>
357<p>The Apache server side logic are the comment looking lines starting with <code><!-- #</code>. Let's look at this step by step:</p>
358<ul>
359<li><code>$HTTP_COOKIE!=/css-loaded/</code> checks if no CSS cache cookie exists yet.</li>
360<li><code>$HTTP_COOKIE=/.*css-loaded=([^;]+);?.*/ && ${1} != '0d82f.css'</code> checks if the cached CSS version is not the current version.</li>
361<li>If <code><!-- #if expr="..." --></code> evaluates to <code>true</code> we assume this is the visitor’s first view.</li>
362<li>For the first view we add a <code><noscript></code> tag with a render blocking <code><link rel="stylesheet"></code>. We do this, because we will load in the full CSS asynchronously with JavaScript. If JavaScript would be disabled, this would not be possible. This means that as a fallback, we load CSS ‘by the numbers’, ie. in a blocking manner.</li>
363<li>We add an inline script with functions for lazy loading the CSS, an <code>onloadCSS</code> callback and set cookies.</li>
364<li>In the same script we load in the full CSS asynchronously.</li>
365<li>In the <code>onloadCSS</code> callback we set a cookie with the version hash as cookie value.</li>
366<li>After the script we add an inline stylesheet with the critical CSS. This will be render blocking, but it will be very small and prevent the page from being displayed as plain unstyled HTML.</li>
367<li>The <code><!-- #else --></code> statement (meaning the <code>css-loaded</code> cookie <strong>is</strong> present) represents the visitor’s repeating views. Because we can assume to some degree that the CSS file is loaded previously we can leverage browser cache and serve the stylesheet in a blocking manner. It will be served from the cache and load almost instantly.</li>
368</ul>
369<p>The same approach is used for loading in fonts asynchronously for the first view, assuming we can serve them from browser cache for repeating views.</p>
370<p><img src="https://www.voorhoede.nl/assets/images/voorhoede-cookies.jpg" title="See here our cookies used to differentiate between first and repeated views." alt="Cookie overview screenshot" /></p>
371<h2 id="file-level-caching">File level caching</h2>
372<p>Since we depend heavily on browser caching for repeating views, we need to make sure we cache properly. Ideally we want to cache assets (css, js, fonts, images) forever, only invalidating the cache when a file actually changes. Cache is invalidated if the request URL is unique. We <code>git tag</code> our site when we release a new version, so the easiest way would be to add a query parameter to request URLs with the code base version, like <code>https://www.voorhoede.nl/assets/css/main.css?v=1.0.4</code>. But.</p>
373<p>The disadvantage of this approach is that when we would write a new blog post (which is part of our code base, not externally stored in a CMS), cache for all of our assets would be invalidated, while no changes have been made to those assets.</p>
374<p>While trying to level up our approach, we stumbled upon <a href="https://github.com/sindresorhus/gulp-rev">gulp-rev</a> and <a href="https://github.com/jamesknelson/gulp-rev-replace">gulp-rev-replace</a>. These scripts helped us to add revisioning per file by appending a content hash to our filenames. This means the request URL only changes when the actual file has changed. Now we have per-file cache invalidation. This makes my heart go boom boom!</p>
375<h2 id="result">Result</h2>
376<p>If you’ve come this far (awesome!) you probably want to know the result. Testing how performant your site is can be done with tooling like <a href="https://developers.google.com/speed/pagespeed/insights/">PageSpeed Insights</a> for very practical tips and <a href="http://www.webpagetest.org/">WebPagetest</a> for extensive network analysis. I think the best way to test your site rendering performance is by watching your page evolve while throttling your connection insanely. That means: throttle in a probably unrealistic manner. In Google Chrome you can throttle your connection (via the inspector > Network tab) and see how requests are slowly being loaded in while your page builds up.</p>
377<p>So see here how our homepage loads on a throttled 50KB/s GPRS connection.</p>
378<p><img src="https://www.voorhoede.nl/assets/images/voorhoede-network-analysis.jpg" title="An overview of how the page evolves for the first visit" alt="Network analysis for de Voorhoede site for the first page view" /></p>
379<p>Notice how we get the first render at 2.27s on a 50KB/s GPRS network, represented by the first image from the filmstrip and the corresponding yellow line on the waterfall view. The yellow line is drawn right after the HTML has been downloaded. The HTML contains the critical CSS, making sure the page looks usable. All other blocking recources are being lazily loaded, so we can interact with the page while the rest is being downloaded. This is exactly what we wanted!</p>
380<p>Another thing to notice is that custom fonts are never loaded on connections this slow. The font face observer automatically takes care of this, but if we wouldn't load in fonts asynchronously you would be staring at FOIT for a while in most browsers.</p>
381<p>The full CSS file is only loaded in after 8 seconds. Conversely, if we’d loaded the full CSS in a blocking manner instead of having critical CSS inline, we would have been staring at a white page for 8 seconds.</p>
382<p>If you’re curious how these times compare to other websites with less of a focus on performance, go for it. Load times will go through the roof! </p>
383<p>Testing our site against the tools mentioned earlier shows some nice results as well. PageSpeed insights gives us a 100/100 score for mobile performance, how awesome is that!</p>
384<p><img src="https://www.voorhoede.nl/assets/images/pagespeed-insights-voorhoede.jpg" title="Woohoo! 100/100 on speed" alt="PageSpeed insights results for voorhoede.nl" /></p>
385<p>When we look at WebPagetest we get the following result:</p>
386<p><img src="https://www.voorhoede.nl/assets/images/webpagetest-voorhoede.jpg" title="WebPagetest results for voorhoede.nl" alt="WebPagetest results for voorhoede.nl" /></p>
387<p>We can see that our server performs well and that the SpeedIndex for the first view is 693. This means our page is usable after 693ms on a cable connection. Looking good! </p>
388<h2 id="roadmap">Roadmap</h2>
389<p>We are not done yet and are constantly iterating on our approach. We will focus in the near future on:</p>
390<ul>
391<li><p><strong>HTTP/2</strong>: It's here and we are currently experimenting with it. A lot of things described in this article are best practices based on the limitations of HTTP/1.1. In short: HTTP/1.1 dates from 1999 when table layouts and inline styles were super awesome. HTTP/1.1 was never designed for 2.6MB webpages with 200 requests. To alleviate our poor old protocol’s pains we concatenate JS and CSS, inline critical CSS, use data URI's for small images, et cetera. Everything to save requests. Since HTTP/2 can run multiple requests in parallel over the same TCP connection, all this concatenation and reducing of requests might even prove to be an antipattern. We will move to HTTP/2 when we are done with running experiments.</p>
392</li>
393<li><p><strong>Service Workers</strong>: This is a modern browser JavaScript API that is run in the background. It enables a lot of features that were not available for websites before, like offline support, push notifications, background sync and more. We are playing around with Service Workers, but we still need to implement it in our own site. I guarantee you, we will! </p>
394</li>
395<li><p><strong>CDN</strong>: So, we wanted control and hosted the site ourselves. Yes, yes, and now we want to move to a CDN to get rid of network latency caused by the physical distance between client and server. Although our clients are mostly based in the Netherlands, we want to reach the worldwide front-end community in a way that reflects what we do best: quality, performance, and moving the web forward.</p>
396</li>
397</ul>
398<p>Thanks for reading! Do you have comments or questions? Let us know <a href="https://twitter.com/devoorhoede">via Twitter</a>. And if you enjoy building fast websites, <a href="https://www.voorhoede.nl/en/team/">why not join us</a>?</p>
399]]></content:encoded>
400 </item>
401<item>
402 <title>Progressive Enhancement for JavaScript App Developers</title>
403 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/progressive-enhancement-for-javascript-app-developers</guid>
404 <pubDate>Tue, 14 Jun 2016 00:00:00 GMT</pubDate>
405 <link>https://www.voorhoede.nl/en/blog/progressive-enhancement-for-javascript-app-developers</link>
406 <dc:creator><![CDATA[Jasper]]></dc:creator>
407 <category><![CDATA[progessive enhancement]]></category>
408<category><![CDATA[JavaScript]]></category>
409<category><![CDATA[frameworks]]></category>
410<category><![CDATA[best practices]]></category>
411<category><![CDATA[render strategies]]></category>
412<category><![CDATA[Progressive Web Apps]]></category>
413 <description><![CDATA[Build JS apps responsibly - cover your basics, render strategically and enhance into true apps.]]></description>
414 <content:encoded><![CDATA[<h1 id="progressive-enhancement-for-javascript-app-developers">Progressive Enhancement for JavaScript App Developers</h1>
415<p>You use a JavaScript framework to build your apps? Smart. It's probably helping you and your team to build amazing things without having to worry about all the cross-browser inconsistencies. Popular JavaScript frameworks have extensive documentation, demos, tooling and a community to help you out. <a href="https://aerotwist.com/blog/the-cost-of-frameworks/">JavaScript frameworks do come at a cost</a>. But I'll assume you're already past that consideration. </p>
416<p>So let's instead discuss techniques and best practices to get the most out of your JavaScript app. How can you get the best experience across browsers and devices? Some good old basics help create widely useable apps. And while JavaScript apps run in the browser, you can already prep server-side. Finally, we can go even further and enhance our JavaScript apps into native-like apps using Progressive Web App technology.</p>
417<h2 id="the-basics-still-apply">The basics still apply</h2>
418<p>JavaScript enables us to create rich interactive web apps. But we still need to cover our basics to ensure it works everywhere.</p>
419<h3 id="accessible-content">Accessible content</h3>
420<p>Content should always be meaningful. So regardless of your JavaScript framework, you should use the appropriate markup: headings, paragraphs, captions and so on. And <a href="https://www.smashingmagazine.com/2013/01/the-importance-of-sections/">consider HTML5 section elements</a> to make your content more descriptive.</p>
421<p>Users should also be able to easily reach your content. The URL is one of the most powerful features of the web. Use it to make content easily accessible. Your JavaScript app may not have traditional pages, but you can still use the <a href="http://html5doctor.com/history-api/">history API</a> to link to specific states of the app.</p>
422<h3 id="interactive-elements">Interactive elements</h3>
423<p>Sure, you're building a highly interactive app. HTML has you covered. Instead of letting your users find and click on <code><span></code>s and <code><div></code>s, use the HTML elements made for interaction: anchors, buttons and form elements. These elements have all interactive states - focus, hover, disabled and more - <a href="https://www.smashingmagazine.com/2016/05/developing-dependency-awareness/#not-all-buttons-are-created-equal">built-in</a>. </p>
424<p>Can users only interact with an element using JavaScript, then use a <code><button></code>. Should your user be able to navigate somewhere? Use an anchor with the appropriate URL as <code>href</code>. Not <code><a href="#"></code>, not <code><a href="javascript:void(0)"></code>, but <code><a href="path/to/content"></code>. Then, you can animate the navigation, get the content asynchronously or create another rich experience. But cover the basics first.</p>
425<h3 id="useful-forms">Useful forms</h3>
426<p>Using form elements for user input? There's a few things to keep in mind. <a href="https://www.christianheilmann.com/2015/12/04/a-quick-reminder-on-how-and-why-to-use-labels-in-forms-to-make-them-more-accessible/">Each input should have an associated label</a>: <code><label for="username">username</label> <input id="username"></code>. You can enhance the experience with icons, floating labels and other patterns. But always keep the label accessible. Don't use the <code>placeholder</code> attribute instead of the label. Placeholders don't have the same meaning, are only initially visible and are not supported in every browser.</p>
427<p>Also ensure you wrap all your form elements in a <code><form></code>. This helps browsers and other technologies understand the inputs belong together. Mobile devices adapt their head-up keyboards accordingly. Also consider setting the form's <code>action</code> attribute and handling submissions server-side for support regardless of JavaScript. User input is valuable and we should do our best to accept it.</p>
428<p>Is your single page application framework capable of complex form validation and constraints? Great! But have you considered first trying to use <a href="http://www.html5rocks.com/en/tutorials/forms/html5forms/">native browser form features</a>? Using the correct input type (like <code>email</code> or <code>url</code>) lets the browser validate input for you. In addition combining attributes like <code>required</code>, <code>min</code>, <code>max</code> and <code>pattern</code> let you set advanced constraints on your input elements. Meaning you get all that for free. </p>
429<p>With the basics in place you can use your JavaScript framework to further enhance the experience of your app.</p>
430<h2 id="render-strategically">Render strategically</h2>
431<p>Not all HTML is created equally. Surely your JavaScript framework has a smart way to generate HTML. Maybe it's using Virtual DOM to optimise updates. Such techniques are great to do instant updates in your app. But there are two problems which they don't always solve for you. Initially the page will be blank until the framework renders the initial HTML. And only after all JavaScript is executed is all the app's functionality available.</p>
432<p>A way to get an initial view on the page sooner, is pre-rendering HTML on the server. This is generally a good start as it prevents users staring at white screens. This solves our first issue.</p>
433<p>Yet this can also lead to a state where the app looks ready, but the user can't interact with it yet. For instance, the initial HTML may contain buttons which don't do anything yet when you click them. This happens because the JavaScript required for the interaction isn't executed yet. You may solve part of this by using anchors and forms. As these basics already work before JavaScript is done. Other parts may be more difficult to get working initially. Sometimes you won't find a basic approach. In that case you could consider initially hiding those functionalities and revealing them only after JavaScript has enabled them. You could also keep the initial page small and asynchronously load extra features.</p>
434<p>Paul Lewis (<a href="https://twitter.com/aerotwist">@aerotwist</a>) illustrates these <a href="https://twitter.com/aerotwist/status/729712502943174657">different rendering techniques in a tweet</a>:</p>
435<p><img src="https://www.voorhoede.nl/assets/images/js-render-techniques.jpg" title="JS-based render initially takes long to render (wasted time). Server-side rendering gets an initial view sooner but still takes time before JS behaviour kicks in (Uncanny Valley). Progressive rendering delivers functional view early and enhances incrementally." alt="JS-based render initially takes long to render (wasted time). Server-side rendering gets an initial view sooner but still takes time before JS behaviour kicks in (Uncanny Valley). Progressive rendering delivers functional view early and enhances incrementally." /></p>
436<p>The best rendering strategy depends on your app. Can you easily integrate your own rendering strategy? There's a trend of server-side pre-rendering and routing extensions for popular JavaScript frameworks. These are commonly referred to as <a href="https://medium.com/@ghengeveld/isomorphism-vs-universal-javascript-4b47fb481beb#.fwirp2e6w">Universal or Isomorphic JavaScript</a> techniques. Truly progressive rendering where functionality is incrementally added is still in its infancy. HTTP/2, Web Components and native support for JavaScript modules will stimulate a progressive approach.</p>
437<h2 id="enhance-to-progressive-web-app">Enhance to Progressive Web App</h2>
438<p>The latest browser technology lets us take our JavaScript apps one step further. It lets us enhance our JavaScript app living it the browser, into an installable native-like app. You can free your app from the browser tab. Make it instantly available. And resilient to flaky internet connections. JavaScript apps successfully applying these features are called <a href="https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul/">Progressive Web Apps</a>.</p>
439<p>The core technology behind Progressive Web Apps is the ServiceWorker API. The ServiceWorker can run in the background of the browser, even when your page is closed. It can intercept network requests and responses, and use the Cache API. You can use this to get your app to function even with flaky or no network connection. The ServiceWorker can also receive Server Push Events and trigger native notifications. <a href="https://jakearchibald.github.io/isserviceworkerready/">Browser support for ServiceWorkers</a> is quickly improving but not ready in all browsers yet. You should therefore use ServiceWorkers as an enhancement to your JavaScript app.</p>
440<p>There's one last step to make your JavaScript app installable: add a manifest. A manifest file contains your app name, icon(s), theme colors and display mode to start the app in. You can define if your app should start in browser, standalone or fullscreen and in a specific orientation. Though you should <a href="https://adactio.com/journal/10708">consider setting display to browser as otherwise your app loses the power of the URL</a>. If a user visits your app frequently, he or she will be prompted to install your app. In addition users can manually install your app to their home screen. During Google I/O 2016 Addy Osmani presented <a href="https://www.youtube.com/watch?v=srdKq0DckXQ">Progressive Web Apps across popular JavaScript frameworks</a>. His article will help you <a href="https://addyosmani.com/blog/getting-started-with-progressive-web-apps/">get started with Progressive Web Apps</a>. </p>
441<p>That's it. Cover your basics. Make sure you start with a functional page using a fitting rendering strategy. Then enhance your JavaScript app into a fast, resilient and installable app.</p>
442]]></content:encoded>
443 </item>
444<item>
445 <title>Design Checklist</title>
446 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/design-checklist</guid>
447 <pubDate>Fri, 03 Jun 2016 00:00:00 GMT</pubDate>
448 <link>https://www.voorhoede.nl/en/blog/design-checklist</link>
449 <dc:creator><![CDATA[Sanne]]></dc:creator>
450 <category><![CDATA[design checklist]]></category>
451<category><![CDATA[designers]]></category>
452<category><![CDATA[developers]]></category>
453<category><![CDATA[checklist]]></category>
454<category><![CDATA[design]]></category>
455<category><![CDATA[front-end]]></category>
456<category><![CDATA[development]]></category>
457 <description><![CDATA[A checklist to ensure a smooth hand-over between design and development]]></description>
458 <content:encoded><![CDATA[<h1 id="design-checklist">Design Checklist</h1>
459<p>This design checklist is meant as a basis for exchanging assets between the designer and developer. Especially in a non-agile
460setting, this list can help with a smooth hand-over between design and front-end development. The list contains the
461most important points that might otherwise be overlooked or deemed unimportant.
462It is in no way meant as a complete list and might be updated when browsers, devices or specifications, etc. change.</p>
463<div data-design-checklist>
464 <p class="enhanced-content" data-persistent-checkboxes>
465 The checkboxes won't uncheck when you refresh or close the tab. This makes
466 the list easy to use over a longer period of time.
467 </p>
468
469 <button class="btn clear-button enhanced-content" data-clear-handle>clear checklist</button>
470
471 <ul class="checklist" data-checklist>
472 <li data-checkbox-group>
473 <div class="checkbox" data-checkbox>
474 <input type="checkbox" id="links" data-collective-input>
475 <label class="label-text" for="links">Links</label>
476 </div>
477 <ul class="nested-list">
478 <li>
479 <div class="checkbox" data-checkbox>
480 <input type="checkbox" id="default" data-individual-input>
481 <label class="label-text" for="default">
482 ..have a default state
483 </label>
484 </div>
485 </li>
486 <li data-expandible>
487 <div class="checkbox" data-checkbox>
488 <input type="checkbox" id="hover" data-individual-input>
489 <label class="label-text" for="hover">
490 ..have a hover state
491 </label>
492 </div>
493 <button type="button" data-expandible-handle class="expandible-handle">
494 <span class="expandible-handle-text">expandible</span>
495 </button>
496 <p class="expandible-content" data-expandible-content>
497 The hover state is activated when the link is targeted
498 by the mouse cursor.
499 </p>
500 </li>
501 <li data-expandible>
502 <div class="checkbox" data-checkbox>
503 <input type="checkbox" id="focus" data-individual-input>
504 <label class="label-text" for="focus">
505 ..have a focus state
506 </label>
507 </div>
508 <button type="button" data-expandible-handle class="expandible-handle">
509 <span class="expandible-handle-text">expandible</span>
510 </button>
511 <p class="expandible-content" data-expandible-content>
512 The focus state is activated when the link is targeted by
513 the keyboard. Most browsers have a default focus state,
514 usually a blue outline.
515 The default styling can be replaced with custom styling that
516 matches the design. In general, the focus and hover state
517 have the same styling.
518 </p>
519 </li>
520 <li data-expandible>
521 <div class="checkbox" data-checkbox>
522 <input type="checkbox" id="active" data-individual-input>
523 <label class="label-text" for="active">
524 ..have an active state
525 </label>
526 </div>
527 <button type="button" data-expandible-handle class="expandible-handle">
528 <span class="expandible-handle-text">expandible</span>
529 </button>
530 <p class="expandible-content" data-expandible-content>
531 The active state gives the user feedback that the activation
532 has been detected by the browser. In other words, it lets
533 the user know that the link was indeed clicked.
534 </p>
535 </li>
536 <li data-expandible>
537 <div class="checkbox" data-checkbox>
538 <input type="checkbox" id="visited" data-individual-input>
539 <label class="label-text" for="visited">
540 ..have a visited state
541 </label>
542 </div>
543 <button type="button" data-expandible-handle class="expandible-handle">
544 <span class="expandible-handle-text">expandible</span>
545 </button>
546 <p class="expandible-content" data-expandible-content>
547 A link is given a visited state if the user has already
548 been on the page it's leading to. It's telling users the
549 difference between the pages they have visited before and
550 the ones they have not.
551 </p>
552 </li>
553 <li data-expandible>
554 <div class="checkbox" data-checkbox>
555 <input type="checkbox" id="external" data-individual-input>
556 <label class="label-text" for="external">
557 Links to external pages are visually distinct
558 </label>
559 </div>
560 <button type="button" data-expandible-handle class="expandible-handle">
561 <span class="expandible-handle-text">expandible</span>
562 </button>
563 <p class="expandible-content" data-expandible-content>
564 Links can have a target attribute which we can use to
565 specify what should happen when the link is clicked. One of
566 the possible values is blank, which tells the browser to
567 open the link in a new window or tab (based on the user's
568 preference).
569 Opening a link in a new window or tab is a change in the
570 default behaviour. To make sure the user knows what to
571 expect there should be a clear visual distinction between
572 internal and external links.
573 </p>
574 </li>
575 <li data-expandible>
576 <div class="checkbox" data-checkbox>
577 <input type="checkbox" id="download" data-individual-input>
578 <label class="label-text" for="download">
579 Download links are visually distinct
580 </label>
581 </div>
582 <button type="button" data-expandible-handle class="expandible-handle">
583 <span class="expandible-handle-text">expandible</span>
584 </button>
585 <div class="expandible-content" data-expandible-content>
586 <p>
587 If a link is used for downloading a resource, we can add
588 the download attribute to it. This way, when the user clicks
589 the link the resource will be downloaded directly
590 (instead of navigating to it).
591 </p>
592 <p>
593 It can be pretty annoying when a download starts without
594 expecting it. Therefore, the behaviour should be clear to
595 the user before the link is clicked, by making download links
596 visually distinct. It is also recommended to add some
597 download details, like the type and size of the download.
598 </p>
599 </div>
600 </li>
601 </ul>
602 </li>
603 <li data-checkbox-group data-expandible>
604 <div class="checkbox" data-checkbox>
605 <input type="checkbox" id="fonts" data-collective-input>
606 <label class="label-text" for="fonts">Fonts</label>
607 </div>
608 <button type="button" data-expandible-handle class="expandible-handle">
609 <span class="expandible-handle-text">expandible</span>
610 </button>
611 <div class="expandible-content" data-expandible-content>
612 <p>
613 When you choose a font for your design, you have two options:
614 </p>
615 <ul>
616 <li>
617 System fonts: the fonts already installed on our computer
618 <ul>
619 <li>
620 <span class="pro"></span>They are always available and you get them for free
621 </li>
622 <li>
623 <span class="con"></span>The number of system fonts installed on computers is
624 limited
625 </li>
626 </ul>
627 </li>
628 <li>
629 Custom fonts
630 <ul>
631 <li>
632 <span class="pro"></span>the font will match the visual design and branding
633 </li>
634 <li>
635 <span class="con"></span>font files can be very large and add extra requests to
636 your site. Both are hurtful for performance.
637 </li>
638 </ul>
639 </li>
640 </ul>
641 <p>
642 When you decide to use a custom font, be sure to include the correct
643 format, a fallback system font and (if possible) a subsetted font.
644 </p>
645 </div>
646 <ul class="nested-list">
647 <li data-expandible>
648 <div class="checkbox" data-checkbox>
649 <input type="checkbox" id="woff" data-individual-input>
650 <label class="label-text" for="woff">
651 ..are in WOFF format
652 </label>
653 </div>
654 <button type="button" data-expandible-handle class="expandible-handle">
655 <span class="expandible-handle-text">expandible</span>
656 </button>
657 <div class="expandible-content" data-expandible-content>
658 <p>
659 We used to include four file formats of our web font in
660 order to get optimal browser support. Nowadays, the WOFF
661 format will be sufficient in most cases, because it covers
662 nearly all browsers (the only browsers not supporting WOFF
663 are IE8, Opera Mini, and older versions of Android and iOS).
664 Including only the WOFF format of the custom font has a
665 couple of benefits:
666 </p>
667 <ul>
668 <li>
669 It saves HTTP requests, improving the performance of the
670 site
671 </li>
672 <li>
673 The WOFF format loads faster than other formats, because
674 it uses a compressed version of the structure used by
675 OpenType and TrueType fonts
676 </li>
677 </ul>
678 <p>
679 With the <a href="http://www.fontsquirrel.com/tools/webfont-generator">Font Squirrel Webfont Generator</a>,
680 you can add a font and it will generate the needed formats
681 for you.
682 </p>
683 </div>
684 </li>
685 <li data-expandible>
686 <div class="checkbox" data-checkbox>
687 <input type="checkbox" id="subset" data-individual-input>
688 <label class="label-text" for="subset">
689 ..are subsetted
690 </label>
691 </div>
692 <button type="button" data-expandible-handle class="expandible-handle">
693 <span class="expandible-handle-text">expandible</span>
694 </button>
695 <p class="expandible-content" data-expandible-content>
696 When you know in advance which letters you'll need, for
697 example when the font is used in a logo, you can only
698 include those characters. Subsetting reduces the web font
699 file size, which will increase the site's performance. This
700 can be done with the <a href="http://www.fontsquirrel.com/tools/webfont-generator">Font Squirrel Webfont Generator</a>.
701 </p>
702 </li>
703 <li data-expandible>
704 <div class="checkbox" data-checkbox>
705 <input type="checkbox" id="fallback" data-individual-input>
706 <label class="label-text" for="fallback">
707 ..have a system fallback font
708 </label>
709 </div>
710 <button type="button" data-expandible-handle class="expandible-handle">
711 <span class="expandible-handle-text">expandible</span>
712 </button>
713 <p class="expandible-content" data-expandible-content>
714 Always include a fallback system font that matches the
715 custom font as close as possible. Browsers can select
716 the fallback system font when it doesn't not support the WOFF format
717 or the custom font can not be downloaded.
718 </p>
719 </li>
720 </ul>
721 </li>
722 <li class="top-list-item" data-expandible>
723 <div class="checkbox" data-checkbox>
724 <input type="checkbox" id="icons" data-collective-input>
725 <label class="label-text" for="icons">Icons</label>
726 </div>
727 <button type="button" data-expandible-handle class="expandible-handle">
728 <span class="expandible-handle-text">expandible</span>
729 </button>
730 <div class="expandible-content" data-expandible-content>
731 <p>
732 At De Voorhoede, we prefer to use SVG icons because:
733 </p>
734 <ul>
735 <li>
736 <span class="pro"></span>
737 they're vector graphics and thus are crisp on displays of all
738 resolutions
739 </li>
740 <li>
741 <span class="pro"></span>
742 they are semantic
743 </li>
744 <li>
745 <span class="pro"></span>
746 they are fast and non-blocking
747 </li>
748 <li>
749 <span class="pro"></span>
750 they support multiple colours and gradients, as opposed to icon
751 fonts (which are monochrome)
752 </li>
753 </ul>
754 <p>
755 To provide an appropriate fallback solution, you can make use of
756 several tools, like <a href="http://grunticon.com">Grunticon</a> and
757 <a href="http://iconizr.com/">Iconizr</a>.
758 </p>
759 <p>
760 These tools take your SVG icons and processes them to a bunch of
761 files, including SVG data URI's (for better performance), PNG data
762 URI's (for browsers that don't <a href="http://caniuse.com/#feat=svg">support</a> SVG)
763 and some fallback CSS files (for older browsers and for browsers
764 with JavaScript disabled).
765 </p>
766 </div>
767 </li>
768 <li data-checkbox-group>
769 <div class="checkbox" data-checkbox>
770 <input type="checkbox" id="forms" data-collective-input>
771 <label class="label-text" for="forms">Forms</label>
772 </div>
773 <ul class="nested-list">
774 <li data-expandible>
775 <div class="checkbox" data-checkbox>
776 <input type="checkbox" id="input-focus" data-individual-input>
777 <label class="label-text" for="input-focus">
778 The focus state of input fields is defined
779 </label>
780 </div>
781 <button type="button" data-expandible-handle class="expandible-handle">
782 <span class="expandible-handle-text">expandible</span>
783 </button>
784 <div class="expandible-content" data-expandible-content>
785 <p>
786 According to the <abbr title="Web Content Accessibility Guidelines">WCAG</abbr>,
787 'any keyboard operable user interface has a mode of operation
788 where the keyboard focus indicator is visible'. Just as links,
789 browsers have a default state for focused form elements.
790 </p>
791 <p>
792 The default browser styling for focused form element isn't
793 always consistent with the visual design. For aesthetic
794 reasons, it can be tempting to remove the focus indicator.
795 However, this will make the form inaccessible to some users
796 (e.g. those who rely on their keyboard). Fortunately, we can
797 replace the default browser styling with custom styling that
798 matches the visual design.
799 </p>
800 </div>
801 </li>
802 <li data-expandible>
803 <div class="checkbox" data-checkbox>
804 <input type="checkbox" id="disabled" data-individual-input>
805 <label class="label-text" for="disabled">
806 The disabled state of input fields is defined
807 </label>
808 </div>
809 <button type="button" data-expandible-handle class="expandible-handle">
810 <span class="expandible-handle-text">expandible</span>
811 </button>
812 <div class="expandible-content" class="expandible-content" data-expandible-content>
813 <p>
814 This state indicates that the user can not interact with the form element, e.g., a
815 checkbox can not be selected or a button is not clickable.
816 </p>
817 <p>
818 Since the default color of disabled
819 form fields is grey in most browsers, you should be careful with making regular form fields
820 grey. There should be sufficient contrast between regular and disabled form fields to make sure the user can easily see the difference.
821 </p>
822 </div>
823 </li>
824 <li data-expandible>
825 <div class="checkbox" data-checkbox>
826 <input type="checkbox" id="placeholder" data-individual-input>
827 <label class="label-text" for="placeholder">
828 Placeholder design is included
829 </label>
830 </div>
831 <button type="button" data-expandible-handle class="expandible-handle">
832 <span class="expandible-handle-text">expandible</span>
833 </button>
834 <div class="expandible-content" class="expandible-content" data-expandible-content>
835 <p>
836 A placeholder is an additional hint for users to help them
837 with form completion (it's <i>additional</i> - it is
838 <a href="http://www.456bereastreet.com/archive/201204/the_html5_placeholder_attribute_is_not_a_substitute_for_the_label_element/">not a substitute</a>
839 for a form label). A hint could be an example value or a
840 brief description of the expected format.
841 </p>
842 <p>
843 In most browsers, if <a href="http://caniuse.com/#feat=input-placeholder">supported</a>,
844 the default color of placeholder text is light grey. You can
845 alter this default color to suit the visual design (be sure
846 to apply a style that has sufficient contrast with the
847 background color!).
848 </p>
849 </div>
850 </li>
851 <li data-expandible>
852 <div class="checkbox" data-checkbox>
853 <input type="checkbox" id="required" data-individual-input>
854 <label class="label-text" for="required">
855 Indicators of required/optional fields are included
856 </label>
857 </div>
858 <button type="button" data-expandible-handle class="expandible-handle">
859 <span class="expandible-handle-text">expandible</span>
860 </button>
861 <div class="expandible-content" class="expandible-content" data-expandible-content>
862 <p>
863 Most browsers supply additional information if the user tries
864 to submit the form without filling in the required value.
865 However, it is useful to include an indicator of required/optional
866 fields in the visual design to make sure that:
867 </p>
868 <ul class="bullet-list">
869 <li>
870 users know which fields are required or optional <i>before</i>
871 they try to submit the form
872 </li>
873 <li>
874 they match the overall look and feel. The default browser
875 tooltips can't be styled. However, we can add custom tooltips,
876 <a href="http://heydonworks.com/practical_aria_examples/#input-tooltip">using only CSS</a>.
877 </li>
878 </ul>
879 </div>
880 </li>
881 <li data-expandible>
882 <div class="checkbox" data-checkbox>
883 <input type="checkbox" id="valid" data-individual-input>
884 <label class="label-text" for="valid">
885 Indicators of valid/invalid fields are included
886 </label>
887 </div>
888 <button type="button" data-expandible-handle class="expandible-handle">
889 <span class="expandible-handle-text">expandible</span>
890 </button>
891 <p class="expandible-content" data-expandible-content>
892 With the <code>:valid</code> and <code>:invalid</code>
893 CSS pseudo-classes we can give users feedback about whether
894 or not the entered input is valid, while they are interacting
895 with the form. For example, we can make email fields red
896 or green, based on whether or not the contents match a valid
897 email address pattern.
898 </p>
899 </li>
900 <li data-expandible>
901 <div class="checkbox" data-checkbox>
902 <input type="checkbox" id="error" data-individual-input>
903 <label class="label-text" for="error">
904 Error messages are included
905 </label>
906 </div>
907 <button type="button" data-expandible-handle class="expandible-handle">
908 <span class="expandible-handle-text">expandible</span>
909 </button>
910 <p class="expandible-content" data-expandible-content>
911 The use of required/optional indicators and placeholders
912 help the user to complete the form successfully. However,
913 something always can go wrong. Be sure to include error
914 messages in the visual design in case this happens.
915 </p>
916 </li>
917 </ul>
918 </li>
919 <li data-checkbox-group data-expandible>
920 <div class="checkbox" data-checkbox>
921 <input type="checkbox" id="images" data-collective-input>
922 <label class="label-text" for="images">Images</label>
923 </div>
924 <button type="button" data-expandible-handle class="expandible-handle">
925 <span class="expandible-handle-text">expandible</span>
926 </button>
927 <p class="expandible-content" data-expandible-content>
928 Images are often the main source of <a href="http://httparchive.org/interesting.php#bytesperpage">page weight</a>.
929 An overweight website results in a poor user experience and high
930 bandwidth costs. There are a couple of ways to take control over
931 image size and quality in order to deliver fast loading site.
932 </p>
933 <ul class="nested-list">
934 <li data-expandible>
935 <div class="checkbox" data-checkbox>
936 <input type="checkbox" id="type" data-individual-input>
937 <label class="label-text" for="type">
938 ..are in the right format
939 </label>
940 </div>
941 <button type="button" data-expandible-handle class="expandible-handle">
942 <span class="expandible-handle-text">expandible</span>
943 </button>
944 <div class="expandible-content" data-expandible-content>
945 <p>
946 There are two types of images to consider:
947 </p>
948 <ul class="bullet-list">
949 <li>
950 <p>
951 vector images: use lines, points, and polygons to
952 represent an image. They are suited for images that
953 consist of simple geometric shapes, like logos,
954 icons etc.
955 </p>
956 <p>
957 Although SVGs are already pretty small, there are
958 still things we can do to optimize them. SVGs contain
959 a lot of metadata, like XML namespaces and layer
960 information. Tools like <a href="http://petercollingridge.appspot.com/svg-editor">SVG
961 Editor</a> remove unnecessary attributes,
962 whitespace etc., resulting in reduced file sizes.
963 </p>
964 </li>
965 <li>
966 <p>
967 raster images: represent an image by encoding the
968 individual values of each pixel within a rectangular
969 grid. They are suitable for photographs and other
970 images.
971 </p>
972 <p>
973 Because JPG compresses the data to be much smaller,
974 it is the preferred images type for photographic
975 images. If the image has transparency, PNG is
976 favorited.
977 </p>
978 <p>
979 For SVG's and PNG's, make sure that the exported
980 assets have the right fill colours and transparency
981 where necessary (not the background color of the
982 document in which they were made).
983 </p>
984 </li>
985 </ul>
986 </div>
987 </li>
988 <li data-expandible>
989 <div class="checkbox" data-checkbox>
990 <input type="checkbox" id="compressed" data-individual-input>
991 <label class="label-text" for="compressed">
992 ..are compressed
993 </label>
994 </div>
995 <button type="button" data-expandible-handle class="expandible-handle">
996 <span class="expandible-handle-text">expandible</span>
997 </button>
998 <p class="expandible-content" data-expandible-content>
999 You can reduce image file sizes with minimal image quality
1000 loss by using compression tools like <a href="https://tinyjpg.com/">TinyJPG</a>.
1001 </p>
1002 </li>
1003 <li data-expandible>
1004 <div class="checkbox" data-checkbox>
1005 <input type="checkbox" id="progressive" data-individual-input>
1006 <label class="label-text" for="progressive">
1007 ..are progressive
1008 </label>
1009 </div>
1010 <button type="button" data-expandible-handle class="expandible-handle">
1011 <span class="expandible-handle-text">expandible</span>
1012 </button>
1013 <div class="expandible-content" data-expandible-content>
1014 <p>
1015 There are two kinds of JPGs: baseline and progressive. A
1016 baseline JPG is a full-resolution top-to-bottom scan of the
1017 image, and a progressive JPG is a series of scans of increasing
1018 quality. The progressive method has a positive effect on
1019 the perceived performance.
1020 </p>
1021 <figure class="content-figure">
1022 <img itemprop="image" src="/assets/images/baseline-jpg.gif" alt="an example of a baseline jpg" title="baseline jpg"/>
1023 <figcaption>An example of a baseline JPG</figcaption>
1024 </figure>
1025 <figure class="content-figure">
1026 <img itemprop="image" src="/assets/images/progressive-jpg.gif" alt="an example of a progressive jpg" title="progressive jpg"/>
1027 <figcaption>An example of a progressive JPG</figcaption>
1028 </figure>
1029 <p>
1030 Using the progressive method in your image is easy: Simply
1031 save your JPEG images with the 'progressive' option.
1032 </p>
1033 </div>
1034 </li>
1035 <li data-expandible>
1036 <div class="checkbox" data-checkbox>
1037 <input type="checkbox" id="high-resolution" data-individual-input>
1038 <label class="label-text" for="high-resolution">
1039 ..are high resolution proof
1040 </label>
1041 </div>
1042 <button type="button" data-expandible-handle class="expandible-handle">
1043 <span class="expandible-handle-text">expandible</span>
1044 </button>
1045 <p class="expandible-content" data-expandible-content>
1046 To cater for high-resolution displays, you need two images:
1047 a normal resolution and a high-resolution image (@2x).
1048 The @2x images can have a high compression rate. High
1049 compression doesn't affect the final image that much: since
1050 that image is more than twice the resolution of the display
1051 size, it also looks sharp on retina screens. High compression
1052 will decrease the file size of the images.
1053 </p>
1054 </li>
1055 <li data-expandible>
1056 <div class="checkbox" data-checkbox>
1057 <input type="checkbox" id="really" data-individual-input>
1058 <label class="label-text" for="really">
1059 Is it really an image?
1060 </label>
1061 </div>
1062 <button type="button" data-expandible-handle class="expandible-handle">
1063 <span class="expandible-handle-text">expandible</span>
1064 </button>
1065 <p class="expandible-content" data-expandible-content>
1066 Often, static charts - like pie or bar charts - are represented
1067 by images. However, those images have some accessibility issues,
1068 since they provide very little information about the data to
1069 color blind people and users of screen readers. An ALT text
1070 generally doesn't do justice to the complexity of a chart.
1071 Luckily, in most cases, instead of using an image, we can
1072 construct graphs as HTML. So before deciding to create an
1073 image, think about whether or not the data can be visualized
1074 using HTML.
1075 </p>
1076 </li>
1077 </ul>
1078 </li>
1079 <li class="top-list-item" data-expandible>
1080 <div class="checkbox" data-checkbox>
1081 <input type="checkbox" id="video" data-collective-input>
1082 <label class="label-text" for="video">Video</label>
1083 </div>
1084 <button type="button" data-expandible-handle class="expandible-handle">
1085 <span class="expandible-handle-text">expandible</span>
1086 </button>
1087 <div class="expandible-content" data-expandible-content>
1088 <p>
1089 The best solution to have videos working, including fallbacks for older browsers, is the
1090 use of embeds. Youtube, Vimeo, etc. provide easy embedding of their videos. The control
1091 over these videos is a little limited but is enough in most cases.
1092 </p>
1093 <p>
1094 If videos can't be hosted on an external service which provides an embed link, the videos
1095 should be delivered in three different formats to make sure they will be visible on all common
1096 modern browsers/devices. The different formats are:
1097 </p>
1098 <ul>
1099 <li>WebM</li>
1100 <li>Ogg Vorbis</li>
1101 <li>MP4 (H.264)</li>
1102 </ul>
1103 <p>
1104 <a href="http://www.mirovideoconverter.com/">Miro Converter</a> is a free application which can
1105 convert MP4 files to other formats on Mac.
1106 </p>
1107 <p>
1108 Older browsers which don't support these formats can fallback to Flash movies. This fallback
1109 provides limited control and usually doesn't give the best quality.
1110 </p>
1111 </div>
1112 </li>
1113 </ul>
1114
1115 <div class="encore">
1116 <h2>One more thing..</h2>
1117 <p>
1118 If you have checked all the boxes in this list, you're good to go and you can hand you're assets
1119 over to development. However, there's one more thing you might want to pay attention to:
1120 naming your assets. Using naming conventions ensures consistency and makes sure that files are easy to find.
1121 Some things to keep in mind when naming your assets:
1122 </p>
1123 <ul class="encore-list">
1124 <li>
1125 <div class="checkbox" data-checkbox>
1126 <input type="checkbox" id="english" data-individual-checkbox>
1127 <label class="label-text" for="english">
1128 Always use English names
1129 </label>
1130 </div>
1131 </li>
1132 <li>
1133 <div class="checkbox" data-checkbox>
1134 <input type="checkbox" id="slugify" data-individual-checkbox>
1135 <label class="label-text" for="slugify">
1136 Always use lowercase and hyphenated file names, like a slug. You can use <a href="https://codeofaninja.com/tools/online-slugify">Online Slugify</a> for this.
1137 </label>
1138 </div>
1139 </li>
1140 <li>
1141 <div class="checkbox" data-checkbox>
1142 <input type="checkbox" id="descriptive" data-individual-checkbox>
1143 <label class="label-text" for="descriptive">
1144 Choose descriptive names for your Photoshop, Fireworks or Sketch files (or whatever application you are using) and for the layers within that file. Never use version numbers in production assets.
1145 </label>
1146 </div>
1147 </li>
1148 </ul>
1149 </div>
1150</div>
1151]]></content:encoded>
1152 </item>
1153<item>
1154 <title>How to keep your projects fresh, and clients happy</title>
1155 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/how-to-keep-your-projects-fresh-and-clients-happy</guid>
1156 <pubDate>Thu, 28 Apr 2016 00:00:00 GMT</pubDate>
1157 <link>https://www.voorhoede.nl/en/blog/how-to-keep-your-projects-fresh-and-clients-happy</link>
1158 <dc:creator><![CDATA[Joao]]></dc:creator>
1159 <category><![CDATA[collaboration, developers, agile, client]]></category>
1160 <description><![CDATA[Get high team morale, quality code, and fresh thinking by rotating developers frequently]]></description>
1161 <content:encoded><![CDATA[<h1 id="how-to-keep-your-projects-fresh-and-clients-happy">How to keep your projects fresh, and clients happy</h1>
1162<p>We like to keep our projects fresh. When one of our developers has worked with a client for six months straight, we rotate them out and replace them with a colleague. But how to deal with consistency of quality, knowledge transfer and such? </p>
1163<p><img src="https://www.voorhoede.nl/assets/images/tim-krul-sub.jpg" title="Jasper Cillessen, playing for the Dutch national team against Costa Rica in the 2014 World Cup, is substituted by Tim Krul who went on to stop 2 penalties. Photo credit: Henk Jan Dijks/ANP" alt="Substitution of two football keepers during 2014 World Cup match" /></p>
1164<h2 id="developer-rotation-boosts-energy-motivation-and-fresh-thinking">Developer rotation boosts energy, motivation and fresh thinking</h2>
1165<p>We have at least three good reasons for developer rotation.</p>
1166<ul>
1167<li><strong>Rotation boosts energy.</strong> Solving new puzzles and learning new concepts is what makes a developer’s juices flow. New energy keeps any longish project vivid.</li>
1168<li><strong>Rotation boosts morale and motivation.</strong> ‘Educating’ new members in the team is a great way to solidify, share and gain knowledge. As much for the leaving members as the new ones on the team. </li>
1169<li><strong>Rotation guarantees fresh thinking.</strong> New team members add new ways of approaching old challenges. New perspectives are the source of better solutions.</li>
1170</ul>
1171<p>Now, let’s look at how.</p>
1172<h2 id="embed-knowledge-with-good-communication-and-code-conventions">Embed knowledge with good communication and code conventions</h2>
1173<p>Before the new developer rotates in, there’s a couple of things you should do to pave the way:</p>
1174<ul>
1175<li><strong>Make developer rotation a known policy.</strong> By making developer rotation a standard part of the way you do your projects, it becomes easier to communicate it upfront. Meaning: in the proposal. That way rotation will never come as a surprise to developers and clients.</li>
1176<li><strong>Plan precisely.</strong> Start planning the rotation well in time. Usually we start planning two months in advance. That way we have time to match the right developer with the job at hand. Plan at least two weeks for a proper handover from developer to developer.</li>
1177<li><strong>Document your code well.</strong> Documentation is the key to working collaboratively. At De Voorhoede, we tend to document basic implementation details, APIs, and quirks that deserve special notice. We put a README next to each component that explains its purpose and how to implement it. For code that's hard to comprehend, we include JSDoc-type comments. We don’t overdo it; most code should be self-explanatory. Don’t be careless about documentation or it will come back to bite you!</li>
1178<li><strong>Put a README in the root.</strong> This file should be the common source of knowledge for everything in and around the code base with regards to writing, testing, running and reviewing code.</li>
1179</ul>
1180<p>Now that the code base is in pristine condition and everybody knows the supersub is coming, they can be eased into the project:</p>
1181<ul>
1182<li><strong>Do a social introduction.</strong> Show the new colleague around the work floor. Explain who’s who in and around the project. Remember in particular to explain everyone’s goals and agenda’s.</li>
1183<li><strong>Current state of affairs.</strong> Every project has some rough edges, either in the technological stack, due to flawed processes, or coming from management decisions. These things are usually undocumented, but important for the new developer to know about. If the developer who is rotating out is still dealing with these situations, they should pass on critical information and point out who to contact, so that the new developer can deal with any escalations promptly.</li>
1184<li><strong>Go over technical project details.</strong> Walk through the build process together. Point out what technologies are used and explain the choices that were made. Show how tests should be run, how to file bugs, create fix patches and how to deploy your code. </li>
1185<li><strong>Demo the current working version.</strong> Explain the project objectives while demonstrating the current working version of the project. Objectives and choices get the proper context in that way. </li>
1186</ul>
1187<p>Almost done! All that’s left is cleaning out the desk and shake up the pillows:</p>
1188<ul>
1189<li><strong>Leave a clean sheet.</strong> It is common courtesy that every developer finishes their tasks before leaving. A proper handover period certainly helps. In some cases, if a task is too big to be completed, build an MVP and document a set of improvement issues for the new developer. </li>
1190<li><strong>Be around until everything works.</strong> Your new colleague should set up the project themselves, which is a good test case for the README’s completeness. Apart from that, help with troubleshooting e-mail accounts, JIRA access, entrance passes. </li>
1191<li><strong>Run!</strong></li>
1192</ul>
1193<p>In conclusion: fresh developers means fresh code, motivated developers and happy clients. If you found this interesting or you’d like to work with us, just <a href="/en/contact">drop a line</a>. We’re always interested in new people and new challenges!</p>
1194]]></content:encoded>
1195 </item>
1196<item>
1197 <title>Performance matters at Fronteers spring conference</title>
1198 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/performance-matters-at-fronteers-spring-conference</guid>
1199 <pubDate>Fri, 15 Apr 2016 00:00:00 GMT</pubDate>
1200 <link>https://www.voorhoede.nl/en/blog/performance-matters-at-fronteers-spring-conference</link>
1201 <dc:creator><![CDATA[Tjerk]]></dc:creator>
1202 <category><![CDATA[performance]]></category>
1203<category><![CDATA[accessibility]]></category>
1204<category><![CDATA[progressive enhancement]]></category>
1205<category><![CDATA[conference]]></category>
1206 <description><![CDATA[A short resume of a full day of interesting talks about web performance]]></description>
1207 <content:encoded><![CDATA[<h1 id="performance-matters-at-fronteers-spring-conference">Performance matters at Fronteers spring conference</h1>
1208<p><img src="https://www.voorhoede.nl/assets/images/fronteers-spring-conf_voorhoede.jpg" title="null" alt="Voorhoede @ Fronteers conf" /></p>
1209<p>Fronteers, the Dutch association of front-end developers, organised the first <a href="https://fronteers.nl/congres/2016-spring">Fronteers Spring Conference</a> at the beautiful Eye Film Museum in Amsterdam. Fronteers conferences have the reputation of being one of the best about front-end development, so we could not skip this edition. </p>
1210<p>The main topic was web performance. This was divided into 3 smaller topics: <b>visual</b>, <b>accessible</b> and <b>technical performance</b>. Every topic had 3 speakers with 20-minute talks each, and an interactive panel discussion afterwards. </p>
1211<p>Some interesting things we heard that day:</p>
1212<h2 id="visual-performance">Visual performance</h2>
1213<p><b><a href="https://twitter.com/tobiasahlin">Tobias Ahlin</a></b> talked about the performance of CSS animations. His advice: you should only animate using CSS <code>transform</code> , <code>opacity</code> and <code>filter</code> . These properties are hardware accelerated which greatly improves performance. So if for instance you want to animate an element’s shadow, use pseudo elements that you animate using <code>opacity</code>, instead of animating <code>box-shadow</code> on the element itself. See example below: </p>
1214<p><img src="https://www.voorhoede.nl/assets/images/fronteers-spring-conf_animate-shadow.gif" title="Setting up the homepage with drag and drop" alt="Example of 2 types of shadow animations" /></p>
1215<p><img src="https://www.voorhoede.nl/assets/images/fronteers-spring-conf_shadow-paint.jpg" title="Difference in number of paints by the browser for animation box-shadow or animating a pseudo-element difference in number of paints by the browser for animation box-shadow or animating a pseudo-element" alt="difference in number of paints by the browser for animation box-shadow or animating a pseudo-element" /></p>
1216<p>As a rule of thumb: <b>animate objects, not properties</b>. </p>
1217<h2 id="accessible-performance">Accessible performance</h2>
1218<p>This block was mostly about progressive enhancement. With the use of native HTML inputs that can be enhanced with JavaScript you not only get a website that is super fast, your website is also more accessible. If you can’t use native HTML inputs, always put the right aria roles on your elements. That way, screenreaders can make sense of it. </p>
1219<p>A great example from <b><a href="https://twitter.com/estellevw">Estelle Weyl</a></b> was about how you can <b>tap into new markets with a fast website</b>. Youtube developers made a 100kb size clone (instead of the normal 1200kb) called Youtube Feather. The result was that they had a lot more traffic coming from regions with low bandwidth internet, such as the African continent and India.</p>
1220<h2 id="technical-performance">Technical Performance</h2>
1221<p>Websites can be a lot faster with HTTP/2, the next version of the HTTP protocol. <b><a href="https://twitter.com/tbaldaufhttps://twitter.com/tbaldauf">Tobias Baldauf</a></b> summarised the differences nicely in the following slide:</p>
1222<p><img src="https://www.voorhoede.nl/assets/images/fronteers-spring-conf_http1vs2.jpg" title="Difference between HTTP/1 and HTTP/2, photo by Jeroen Tjepkema" alt="Difference between HTTP/1 and HTTP/2" /></p>
1223<p>Tobias also held an impressive <a href="https://speakerdeck.com/tbaldauf/your-hero-images-need-you-save-the-day-with-http2-image-loading">talk</a> about a new way to <b>optimise the perceived loading speed of images with 6%</b>. He did that by adjusting the scan level configuration of progressive JPG’s. The technique is not ready for production yet, but keep an eye on his <a href="http://tobias.is/blog/">blog</a>.</p>
1224<p><b><a href="https://twitter.com/mathias">Mathias Bynens</a></b> blew our minds with his <a href="https://speakerdeck.com/mathiasbynens/front-end-performance-the-dark-side-at-fronteers-spring-conference-2016">talk</a> on the drawbacks of using the browser’s performance measuring tools for end-users. He showed a <b>timing attack technique</b>, in which you can time how fast a page loads for an user by using the <code>img</code> or <code>video</code> element’s <code>src</code> attribute. Once you have this benchmark, you can tell if users have admin rights for certain sites, for instance. But you can also extract all kinds of demographic information by (mis)using Facebook. Very impressive and at the same time very scary because there is no real solution for this problem yet.</p>
1225<p><img src="https://www.voorhoede.nl/assets/images/fronteers-spring-conf_mathias.jpg" title="Mathias talking, photo by Peter Peerdeman" alt="Mathias talking @ Fronteers spring conf" /></p>
1226<h2 id="performance-in-the-real-world">Performance in the real world</h2>
1227<p>The closing <a href="http://de.slideshare.net/kskoeld/fronteers-spring-conference-amsterdam-2016-keynote">talk</a> was from <a href="https://twitter.com/kskoeld">Kristian Skold</a>. Even if we want to bring all these performance improvements into practice, a client might not give you budget to build these things. How do you <b>convince clients of web performance benefits</b> to their business? Well, tell them what it does for their <b>bounce rate, conversion rate, order value and session length</b>. Use their current data and plot it against data that predicts the increase in these statistics when their website loads a second faster. Start with small improvements and compare after a month. Once they see the effects and start feeling it in their pocket, they’re bound to give you the go-ahead on more drastic performance enhancements. </p>
1228<h2 id="conclusion">Conclusion</h2>
1229<p>We really enjoyed this new edition of Fronteers Conference. The short talks ensured that they where focused and gave you a lot of information about different subjects in a short time. We already look forward to attending <a href="https://fronteers.nl/congres">the next conference</a> in theater Pathé Tuschinski this fall!</p>
1230]]></content:encoded>
1231 </item>
1232<item>
1233 <title>Riot.js: the good, the bad and the style guide</title>
1234 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/riotjs-the-good-the-bad-and-the-style-guide</guid>
1235 <pubDate>Tue, 12 Apr 2016 00:00:00 GMT</pubDate>
1236 <link>https://www.voorhoede.nl/en/blog/riotjs-the-good-the-bad-and-the-style-guide</link>
1237 <dc:creator><![CDATA[Anne]]></dc:creator>
1238<dc:creator><![CDATA[Jasper]]></dc:creator>
1239 <category><![CDATA[Riot]]></category>
1240<category><![CDATA[Riot.js]]></category>
1241<category><![CDATA[best practices]]></category>
1242<category><![CDATA[issues]]></category>
1243<category><![CDATA[guidelines]]></category>
1244<category><![CDATA[experience]]></category>
1245<category><![CDATA[opinion]]></category>
1246 <description><![CDATA[Our experience with the Riot JavaScript framework, and our response: a style guide.]]></description>
1247 <content:encoded><![CDATA[<h1 id="riot-js-the-good-the-bad-and-the-style-guide">Riot.js: the good, the bad and the style guide</h1>
1248<p>Lately, we’ve been doing a lot of projects with Riot.js, a “<a href="http://riotjs.com/">React-like user interface micro-library</a>â€. We discovered that it aligns nicely with our approach for smaller projects, but has some drawbacks when apps become more complex. To keep our Riot projects maintainable, we published a <a href="https://github.com/voorhoede/riotjs-style-guide">style guide</a> that we intend to maintain and improve. </p>
1249<p>So what about Riot's pros and cons?</p>
1250<h2 id="the-good">The good</h2>
1251<ul>
1252<li><strong>Easy to learn</strong>: since Riot is a small framework (only 9kb) there’s not much to learn about it. Furthermore, it’s mostly vanilla JavaScript and HTML — no new syntax like <a href="https://facebook.github.io/react/docs/jsx-in-depth.html">React’s JSX</a> that you need to learn.</li>
1253<li><strong>High performance</strong>: Riot has a fast runtime compiler, that’s also available as part of your JS build step. Apart from that, Riot makes use of a simplified virtual DOM which makes HTML updates and changes very fast.</li>
1254<li><strong>Love for modules</strong>: we like component based development. Riot is built around UI modules, called tags, that provide modularity out of the box. Appended with some of our own practices, it’s a breeze to exchange Riot tags between projects. </li>
1255</ul>
1256<h2 id="the-bad">The bad</h2>
1257<ul>
1258<li><strong>State management is hard</strong>: there is no (opinionated) way to manage state within a component or between components. There is no step between a state update and re-render, and when updating a tag, all its children will be updated also. This increases the need for plumbing every time you add complexity to a Riot app. Alternatively, you could implement another library like Redux to keep state, which has its own implications and challenges.</li>
1259</ul>
1260<pre><code class="lang-html"><my-tag>
1261 <div class={ active: isActive } onclick={ toggle }>
1262 { title }
1263 </div>
1264
1265 this.isActive = false;
1266 toggle(e) {
1267 this.isActive = !this.isActive;
1268 }
1269</my-tag>
1270</code></pre>
1271<ul>
1272<li><strong>Magic syntax</strong>: the Riot team made peculiar choices with regards to keeping to standards. There is some ES6-like syntax used in code examples that is not found anywhere else. Also, Riot interprets your tag contents as JavaScript instead of HTML by default. In the example above, HTML attributes have no quotes. The <code>toggle</code> function definition would throw an error in any linter and there’s no <code><script></code> tag around the JavaScript. Quirks you can easily work around, but a possible stumbling block for novice developers. And bad for reusability of your code.</li>
1273<li><strong>Maybe not strict enough</strong>: An app built in Riot is just a big object, living in the global scope, that you can easily traverse and manipulate. Even its internals are accessible. When running into problems it becomes tempting to build hacks and workarounds using these ‘features’. Unexpected side effects because of this are all too common in Riot.</li>
1274</ul>
1275<h2 id="the-style-guide">The style guide</h2>
1276<p>The best way to work around these pitfalls is to put guidelines in place. It will allow you and your team to build stable and robust apps, even if the underlying architecture is as loose as Riot’s. We wrote a style guide just for this reason.</p>
1277<p><a href="https://github.com/voorhoede/riotjs-style-guide">Check our Riot style guide on GitHub!</a></p>
1278]]></content:encoded>
1279 </item>
1280<item>
1281 <title>Our takeaways from Enhance Conf 2016</title>
1282 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/enhanceconf</guid>
1283 <pubDate>Mon, 21 Mar 2016 00:00:00 GMT</pubDate>
1284 <link>https://www.voorhoede.nl/en/blog/enhanceconf</link>
1285 <dc:creator><![CDATA[Sanne]]></dc:creator>
1286<dc:creator><![CDATA[João]]></dc:creator>
1287 <category><![CDATA[enhanceconf]]></category>
1288<category><![CDATA[conference]]></category>
1289<category><![CDATA[progressive enhancement]]></category>
1290 <description><![CDATA[Overview of the takeaways from the talks of Enhance Conf 2016]]></description>
1291 <content:encoded><![CDATA[<h1 id="our-takeaways-from-enhance-conf-2016">Our takeaways from Enhance Conf 2016</h1>
1292<p>As front-end developers, we have a great focus on performance, accessibility and
1293getting the best experience for end users. A large part of this is progressive
1294enhancement. No wonder that when we heard about
1295<a href="http://enhanceconf.com/">EnhanceConf</a>, we immediately booked a flight to London.</p>
1296<p><img src="https://www.voorhoede.nl/assets/images/enhanceconf.jpg" title="Photo by Paul Downey" alt="EnhanceConf speakers on stage" /></p>
1297<p>EnhanceConf is a one day conference taking place in the RSA House in the center
1298of London. The day was divided in four blocks of talks. Each block of three 20
1299minutes talks - followed by a Q&A - provided a lot of inspiring information.</p>
1300<h2 id="the-takeaways">The takeaways</h2>
1301<p>The day was kicked off by <a href="http://natbuckley.co.uk/">Nat Buckley</a>, reminding us
1302of how complicated building for the web can be. The points Nat discussed
1303recurred in more detail throughout the day: when building for the web, we should...</p>
1304<h3 id="-think-about-the-various-ways-our-web-apps-can-be-used">...think about the various ways our web apps can be used</h3>
1305<p><a href="http://maban.co.uk/">Anna Debenham</a> gave us a detailed overview of the many
1306game consoles people are using to access the web. Anna's talk made clear that
1307smartphone, tablet and desktop are not the only devices we should account for.
1308The talks of
1309<a href="https://www.aaron-gustafson.com/">Aaron Gustafson</a> and
1310<a href="https://twitter.com/usa2day">Robin Christopherson</a> pointed out the importance
1311of voice. Paying attention to how our interface is read will <strong>improve
1312accessibility</strong>. It will also prepare us for the future, when users will become
1313more reliant on voice-based interactions with technologies like
1314Siri and Google Now.</p>
1315<h3 id="-consider-performance">...consider performance</h3>
1316<p><a href="http://www.forbeslindesay.co.uk/">Forbes Lindesay</a> and
1317<a href="https://oliverjash.me/">Oliver Joseph Ash</a> showed us some <strong>performance
1318strategies</strong> for improving user experience. Forbes talked about
1319how to do this by sharing code for rendering on the server and the client using
1320React. Oliver walked us through the process of how they created an offline
1321experience for the Guardian. We can <strong>show our users content even when they are
1322offline</strong> using Service Worker.</p>
1323<h3 id="-embrace-the-browser">...embrace the browser</h3>
1324<p><a href="https://twitter.com/stilkov">Stefan Tilkov</a> gave us a high-level view of
1325architectures for building for the web. Stefan encouraged us to embrace the
1326web’s architectural style and its constraints. This point of view was supported
1327by <a href="http://adamsilver.io/">Adam Silver</a>’s talk 'Embracing Simplicity'. Adam
1328talked about <strong>the great results we can get with just the core experience</strong>, without
1329jumping to the enhancement.</p>
1330<p>We had an inspiring day at EnhanceConf and are looking forward to put the ideas
1331and strategies into practice. Videos of the talks are available on
1332<a href="https://www.youtube.com/channel/UCJbdGfrWglK727eZPc4_t_A">YouTube</a>.</p>
1333]]></content:encoded>
1334 </item>
1335<item>
1336 <title>Resisting the fast food menu</title>
1337 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/resisting-the-fast-food-menu</guid>
1338 <pubDate>Tue, 02 Feb 2016 00:00:00 GMT</pubDate>
1339 <link>https://www.voorhoede.nl/en/blog/resisting-the-fast-food-menu</link>
1340 <dc:creator><![CDATA[Jasper]]></dc:creator>
1341 <category><![CDATA[menu]]></category>
1342<category><![CDATA[hamburger]]></category>
1343<category><![CDATA[navigation]]></category>
1344<category><![CDATA[progressive enhancement]]></category>
1345<category><![CDATA[usability]]></category>
1346<category><![CDATA[accessibility]]></category>
1347 <description><![CDATA[How we managed to keep our menu always directly usable, entirely visible and always accessible.]]></description>
1348 <content:encoded><![CDATA[<h1 id="resisting-the-fast-food-menu">Resisting the fast food menu</h1>
1349<p>Hamburger menus (☰) are addictive. They let you tuck away your fat menus and feel fashionable again. But like with all fast food, you feel kinda sick afterwards. Because the truth is, you didn't solve your problem, you just created new ones. Chances are your hamburger icon isn't loading or your users don't know what it actually means. If they do, the hamburger menu still requires an extra interaction, and they probably have to wait for that until the entire page is loaded and the required JavaScript is successfully downloaded and executed.</p>
1350<p>So, let's talk about a healthier approach.</p>
1351<h2 id="keep-your-menu-slim">Keep your menu slim</h2>
1352<p>Fat menus tucked away behind hamburger icons are a result of desktop sites squeezed into a mobile layout. So the first step is embracing mobile first. Do a short usability study with your users and check your site's analytics. What are the top items users navigate to or which do you find are most important to be discovered quickly? Try putting just those items in your menu and make the rest of the site accessible via other pages and search. Chances are your menu can be so slim, it can simply always be entirely visible.</p>
1353<h2 id="strive-for-visibility">Strive for visibility</h2>
1354<p>Is your menu still too large to be entirely visible by default on smaller screens? Then it's time to look into responsible ways to do so. Instead of hiding all menu items at once, consider incrementally hiding items the smaller the screen gets, starting with the once least used. As Luke Wroblewski puts it “<a href="http://www.lukew.com/ff/entry.asp?1945">[Visible and] obvious always wins</a>â€.</p>
1355<h2 id="keep-your-menu-accessible">Keep your menu accessible</h2>
1356<p>When you decide to hide your navigation, do it right. Don’t break default browser behaviour. Make it semantically correct, use ARIA roles, and think twice before adding JavaScript and little-supported CSS features.</p>
1357<p>Start with a plain accessible HTML menu. Do feature detection and only then enhance to something better. For example put the full menu on the page and move it to an off-canvas panel in capable browsers. Heydon Pickering explains how to use this technique with a <a href="http://heydonworks.com/practical_aria_examples/#hamburger">Progressive hamburger menu</a>.</p>
1358<p>You should also make the icon understandable to everyone by adding a text or title, like "menu" or "site navigation". The article <a href="http://exisweb.net/mobile-menu-abtest">Mobile Menu A/B Test</a> backs this up with data.</p>
1359<h2 id="eat-your-own-menu">Eat your own menu</h2>
1360<p>We believe we can do better.</p>
1361<p>The first design for our own site <a href="https://www.voorhoede.nl/">voorhoede.nl</a> always had its menu items tucked away behind a stylish hamburger icon and was conveniently missing our language selector. After some prototyping in the browser, we realised our logo creates plenty of space next to it for the full menu. By using two versions of our logo (one with just the shield, the other with also our company name) and conditionally placing the menu items and language selector on one or two lines we've created a menu which is always directly usable, entirely visible and always accessible:</p>
1362<p><img src="https://www.voorhoede.nl/assets/images/voorhoede-menu-320-vs-900px-screen.png" title="Voorhoede.nl menu on a 320px and a 900px wide screen." alt="Navigation menu on voorhoede.nl on small screen with shield logo on the left spanning two lines; portfolio, blog & contact on first line and language selector on second line. On large screens the logo with company name is on the left and all menu items and language selector are on one line on the right." /></p>
1363]]></content:encoded>
1364 </item>
1365<item>
1366 <title>Create a CMS in 15'ish Minutes</title>
1367 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/create-a-cms-in-15ish-minutes</guid>
1368 <pubDate>Sun, 19 Apr 2015 00:00:00 GMT</pubDate>
1369 <link>https://www.voorhoede.nl/en/blog/create-a-cms-in-15ish-minutes</link>
1370 <dc:creator><![CDATA[Celine]]></dc:creator>
1371 <category><![CDATA[cms]]></category>
1372<category><![CDATA[content management]]></category>
1373<category><![CDATA[webhook]]></category>
1374<category><![CDATA[wecity]]></category>
1375 <description><![CDATA[We use Webhook CMS to quickly customise the back-end and spend most of our effort on a blazingly fast and responsive front-end.]]></description>
1376 <content:encoded><![CDATA[<h1 id="create-a-cms-in-15-ish-minutes">Create a CMS in 15'ish Minutes</h1>
1377<p>At De Voorhoede we love all the stuff we can create in the browser. Most of the time we create websites and deliver them as a <a href="https://github.com/voorhoede/front-end-guide">Front-end guide</a>. But occasionally the client wants more than just the front-end. For those cases we like to use Webhook.</p>
1378<p><a href="http://www.webhook.com/">Webhook</a> is a CMS that builds static websites using a popular front-end development stack. It is easy to set up, comes with a database service, an image server, an online content editor and hosting. By using Webhook we can quickly customise the back-end and spend most of our effort on a blazingly fast and responsive front-end.</p>
1379<h2 id="case-introduction">Case introduction</h2>
1380<p><a href="http://www.wecity.guide/">WeCity</a> assists tourists on a city trip by means of a mobile app. We created the product information website and implemented Webhook so weCity can edit their own content.</p>
1381<h2 id="setup">Setup</h2>
1382<p>Adding Webhook to your project is as easy as running three commands in your terminal. After that you are all set to begin your journey.</p>
1383<pre><code> $ npm install -g wh
1384 $ wh init [projectname]
1385 $ wh serve
1386</code></pre><h2 id="content-first">Content first</h2>
1387<p>The weCity website has a homepage and a couple of blog posts. With Webhook you can create a different content type for each. The homepage is a single article, the blog posts we consider 'multiple content'. When creating multiple content you can set up a single content definition and use it for multiple 'child' articles.</p>
1388<h2 id="setting-up-the-content">Setting up the content</h2>
1389<p>The structure for the homepage content is as easy as drag-n-drop; add fields to your form, order them and set the properties. Webhook has a rich set of predefined field types.</p>
1390<p><img src="https://www.voorhoede.nl/assets/images/wecity_addfield.gif" title="Setting up the homepage with drag and drop" alt="Drag and drop animation" /></p>
1391<h2 id="creating-templates">Creating templates</h2>
1392<p>Webhook uses a template engine called <a href="http://paularmstrong.github.io/swig/">Swig</a> which uses a popular syntax (eg. <code>{{ item.property }}</code> ) also seen in Nunjucks, Django and Twig.</p>
1393<p>Webhook gives you a predefined template structure when creating new content types, but you have complete freedom over how to put it all together, using macros, includes and everything Swig has to offer. Webhook also puts all kinds of filter sauce on top of that. This way you can fully control your data and the markup at the same time.
1394<img src="https://www.voorhoede.nl/assets/images/wecity_code.jpg" title="A Section of the homepage HTML with the use of Swig and the Webhook variables" alt="Template code" /></p>
1395<h2 id="how-it-turns-out">How it turns out</h2>
1396<p>Next to all the benefits for developers, Webhook is very easy to use for our clients and copywriters. Editing and saving the form causes an instant reload of the browser.</p>
1397<p><img src="https://www.voorhoede.nl/assets/images/wecity_cms4.min.gif" title="After save the changed content appears right at the templates placeholder" alt="Drag and drop animation" /></p>
1398<h2 id="why-we-like-it">Why we like it</h2>
1399<ul>
1400<li>It's easy to setup</li>
1401<li>Ability to create a custom content editor</li>
1402<li>Total control of HTML templates, styling and asset management</li>
1403<li>Exchangeable content (via API, import or export)</li>
1404<li>We can continue to work as kick ass Front-end developers and create websites that are mobile first, small in size, fast and optimised for screen readers</li>
1405<li>Open source</li>
1406<li>Well documented</li>
1407<li>Affordable hosting and a fairly straightforward means to host on our own environments</li>
1408<li>If Webhook ever goes away, we still have a very workable development stack with templates that we can build with our own tools</li>
1409</ul>
1410<p>All in all, using Webhook is a painless way to get all the benefits of a CMS while keeping focused on the front-end. Do you want to know more about the way we work, our workflow or webhook in specific? Contact us!</p>
1411]]></content:encoded>
1412 </item>
1413<item>
1414 <title>9 ways to improve collaboration between developers and designers</title>
1415 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/9-ways-to-improve-collaboration-between-developers-and-designers</guid>
1416 <pubDate>Mon, 30 Mar 2015 00:00:00 GMT</pubDate>
1417 <link>https://www.voorhoede.nl/en/blog/9-ways-to-improve-collaboration-between-developers-and-designers</link>
1418 <dc:creator><![CDATA[Anne]]></dc:creator>
1419 <category><![CDATA[Collaboration]]></category>
1420<category><![CDATA[developers]]></category>
1421<category><![CDATA[designers]]></category>
1422<category><![CDATA[agile]]></category>
1423<category><![CDATA[scrum]]></category>
1424 <description><![CDATA[As front-end developers, we work closely together with designers every day. To get the best out of each other, we came up with these guidelines.]]></description>
1425 <content:encoded><![CDATA[<h1 id="9-ways-to-improve-collaboration-between-developers-and-designers">9 ways to improve collaboration between developers and designers</h1>
1426<p>Developers respect color theory, designers worry about render-blocking JavaScript. These are some of our daydreams. The reality is that we usually prioritise fixing our own problems before we try to understand someone else’s. As front-end development specialists, we work closely together with interaction and visual designers every day. To get the best out of each other, we came up with these guidelines.</p>
1427<p><img src="https://www.voorhoede.nl/assets/images/designers-developers-working-together.jpg" title="Photo taken during our “Developers ⤠designers†day with UNITiD. We talked about code and design, and put our ideas into practice by teaming up to build random prototypes." alt="Designers and developers working together" /></p>
1428<h2 id="wait-why-is-this-collaboration-so-difficult-in-the-first-place-">Wait — why is this collaboration so difficult in the first place?</h2>
1429<p>To many web developers, design is mostly important because it makes things recognisable and appealing. But the heart of the matter lies at its functionality. <strong>A design is useless if it doesn‘t improve how it works.</strong> Nobody will disagree on that.</p>
1430<p>The client however sees <strong>design as a means to tell a story</strong>. It’s the story of what her organisation does, how it does those things, and why that is important. And let’s be honest: storytelling shouldn’t be hindered by concerns of reusability, browser quirks or performance.</p>
1431<p>The designer now has to <strong>design something that is highly usable and tells the story at the same time</strong>. The trouble is that the client isn’t going to be sold by a technical concept. So before you know it, parallax carousels with soft-focus high definition photography show up all over the place. And that may not be in everybody’s best interest.</p>
1432<h2 id="ok-so-what-are-your-suggestions-">OK, so what are your suggestions?</h2>
1433<p>Here’s how we go from storytelling, through concept and visual designs, towards a modular, high-performance website:</p>
1434<h2 id="1-work-agile">1. Work agile</h2>
1435<p>The best way to tackle problems before they arise is to <strong>work agile</strong>. Since you’re in the same room working on the same things it will be so much easier to <strong>prototype, test and iterate together</strong>. If you can’t work agile, the following points are all the more important.</p>
1436<h2 id="2-get-front-end-involved-early">2. Get front-end involved early</h2>
1437<p>A front-end developer should be <strong>part of the project set-up as early as possible</strong>. Probably earlier. They need to be able to <strong>speak out about feasibility</strong>, chances for <strong>innovation</strong> and what the <strong>hard parts</strong> are. Don’t hesitate to invite them to introductory meetings: you may be surprised at how well they can sell their work.</p>
1438<h2 id="3-speak-the-same-language">3. Speak the same language</h2>
1439<p>All parties involved should <strong>form a shared vocabulary</strong>. We should use the words that the client uses for products and services. Developers might even <strong>use those words in the code base</strong>. Teaching clients our jargon is fun too.</p>
1440<h2 id="4-take-time-for-the-hand-over">4. Take time for the hand-over</h2>
1441<p>Especially in a non-agile setting, the hand-over of a design should happen via a <strong>human to human interface</strong>. This means that a designer and a developer should <strong>take as much time as needed to discuss and improve the design</strong>. Put the designs on a wall and figure out form element states, behaviour on touch interfaces, animations, use of graphic elements and so on. <strong>Discuss responsive behaviour</strong> and breakpoints for which there’s no design. Which leads us to:</p>
1442<h2 id="5-mobile-first">5. Mobile first</h2>
1443<p>The design should be <strong>mobile first</strong>. That’s the way things are. Two major advantages: 1) mobile first is the <strong>shortest route to an MVP</strong> and 2) the result will be <strong>designed for performance</strong>. Because as we all know:</p>
1444<h2 id="6-build-for-performance">6. Build for performance</h2>
1445<p><strong>Good UX starts with performance</strong>. A designer that cares about the user always chooses in favor of performance. Not entirely coincidental, this is usually easier for the developer to build and <strong>improves accessibility</strong> as well.</p>
1446<h2 id="7-make-a-style-guide">7. Make a style guide</h2>
1447<p><strong>Build a style guide together</strong>. Typography, colours, buttons, form elements, panels, all the core stuff that every website needs. This kind of <strong>design system accelerates building compositions and prototypes</strong>. And do it directly in the browser. Because in the end:</p>
1448<h2 id="8-embrace-the-browser">8. Embrace the browser</h2>
1449<p><strong>The browser is the canvas</strong>. The “definition of done†is a website that your uncle can visit from his vacation home. Not an unmerged branch on Github, nor a PNG file on Dropbox. That’s why designers need to <strong>learn about the browser</strong>. At the same time, developers shouldn’t use technical barriers as an excuse for lousy design implementations. Because <a href="https://www.chromeexperiments.com/">browsers can do pretty much anything these days</a>. Finally:</p>
1450<h2 id="9-respect-each-other-s-work">9. Respect each other’s work</h2>
1451<p>Most developers know their way around Photoshop, and most designers know how websites are built. That doesn’t mean you know the job. Play to your strengths, and <strong>know when to ask someone for advice or feedback</strong>. Stay curious. Let others help you make your stuff better, and then help others make theirs better as well.</p>
1452<h2 id="to-cap-it-off-">To cap it off:</h2>
1453<p>To make beautiful things, both visually and technically, it’s critical that developers and designers work well together. That’s why we try to adhere to these guidelines. Our love for designers is real — and we hope that the feeling is mutual.</p>
1454]]></content:encoded>
1455 </item>
1456<item>
1457 <title>Designing components with Angular</title>
1458 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/designing-components-with-angular</guid>
1459 <pubDate>Tue, 17 Feb 2015 00:00:00 GMT</pubDate>
1460 <link>https://www.voorhoede.nl/en/blog/designing-components-with-angular</link>
1461 <dc:creator><![CDATA[Maarten]]></dc:creator>
1462 <category><![CDATA[angular]]></category>
1463<category><![CDATA[AngularJS]]></category>
1464<category><![CDATA[components]]></category>
1465<category><![CDATA[modules]]></category>
1466<category><![CDATA[architecture]]></category>
1467<category><![CDATA[setup]]></category>
1468 <description><![CDATA[Our opinionated way of designing components and apps with AngularJS.]]></description>
1469 <content:encoded><![CDATA[<h1 id="designing-components-with-angular">Designing components with Angular</h1>
1470<p>At De Voorhoede, we did our first Angular project in 2013. What started as "getting it to frigging work", quickly evolved into a more opinionated way of designing components and apps. In this post, I'll cover patterns and tools that we use to design our components and be productive at it.</p>
1471<h2 id="problems-to-solve">Problems to solve</h2>
1472<p>In order to find out what sort of components and architecture we're going to need, we need to know what sort of "problems" we need to solve. I'm very problem-oriented and practical when making architectural decisions. I never just copy the architecture from another project.</p>
1473<p>Let's take a look at the requirements of one of our largest Angular projects.</p>
1474<p>5 different apps. Multiple organizations that designed their own backends. At some point they all became part of the same umbrella organization and now they want their apps to get a uniform branding and UX.</p>
1475<p>They are asking for a frontend that provides them with re-usable components. The first few backends will be redesigned while we work on the frontend components, so that we can design the functionality and corresponding JSON together. The JSON data structures will be the contracts between backend and frontend.</p>
1476<p>After the first few apps have been built, the component library will have reached a level of maturity. It will allow the backend teams to build new apps just by building a new backend for it; no additional frontend work required.</p>
1477<p>All backend teams will do their best to be as consistent as possible in the JSON structure that they deliver. However, some exceptions will happen. The components will need to be usable with slight JSON structure variations.</p>
1478<p>We work agile. As apps get built, changes will be made to components constantly. Features will be added, bugs will be fixed, UX enhancements will be done, etc. Sometimes, there will be breaking changes. Each app will need to be able to control if and how they want to deal with (breaking) changes.</p>
1479<p>Components will need to work together. When we receive a JSON response for a page, it will be passed to a router. The router will pass on most of the JSON structure to other components. Components will delegate further to other components internally, etc.</p>
1480<p>A page response might also contain data to instantiate a new child router. The app structure is not set in stone; it is constantly extended with new routes as responses are coming in.</p>
1481<p>We will be working in a Scrum team with backenders, frontenders and designers. Communication and documentation is essential for making quick progress and re-using (or building on top of) existing work.</p>
1482<h2 id="deliverables">Deliverables</h2>
1483<p>Based on the project requirements, we'll need to deliver:</p>
1484<ul>
1485<li><em>A component library.</em> All components will be maintained and tested in one place.</li>
1486<li><em>Package management.</em> Apps will be able to either conveniently install the entire component library at a specific version, or only specific components to keep the frontend more lightweight.</li>
1487<li><em>Component changelogs.</em> As components are constantly changing, we'll need to document added features and bug fixes. Especially the breaking changes, and grouped by component.</li>
1488<li><em>A component API reference with runnable examples.</em> This will become the home of the component library, for backenders and frontenders. People will look here to find out how a component works, or which component(s) they want to use for a particular scenario. It will also be the place where we develop and review components.</li>
1489<li><em>JSON contracts.</em> We'll need them in two formats: human readable and machine readable. The human readable format will be used in design sessions and documentation, and should be very easy to read and write. Where applicable, these should be linked with specific component documentation. The machine readable format will be used for runtime validation of incoming/outgoing JSON, on both server and client. It will help in tracing the source of any incorrect JSON during development and testing.</li>
1490<li><em>An example app with mocked backend.</em> The last station. It will be the proof that you can compose an extremely dynamic app with just JSON responses. Using one frontend, switch one backend mock with another, and get an entirely different app.</li>
1491</ul>
1492<h2 id="component-philosophy">Component philosophy</h2>
1493<h3 id="component-definition">Component definition</h3>
1494<p>In general, the meaning of the term "component" can vary based on the context. In our case, it means: an isolated responsibility within the architecture. It can be a visual widget (e.g. responsible for rendering a form field), an API (e.g. responsible for querying data from the server), or a composition of multiple components to combine their functionality (in this case its only responsibility is to pass instructions on to the other components).</p>
1495<p>Each component has just one responsibility. Some components will be really tiny. That's okay, as it will make them highly re-usable.</p>
1496<p>More complex components will delegate most of their functionality to other, smaller components. For example, a form field component might internally use our server query component, to implement server side validation of its model value. Other small components can be used to consistently render validation reponses across different form field components.</p>
1497<h3 id="philosophical-influences">Philosophical influences</h3>
1498<h4 id="web-components">Web Components</h4>
1499<p><a href="http://webcomponents.org/">Web Components</a> are an excellent starting point for forming your own philosophy in component design. I like how Web Components make HTML the center of the architecture. This makes component APIs very declarative, and more agnostic from JavaScript implementations and frameworks.</p>
1500<h4 id="polymer">Polymer</h4>
1501<p>The "everything is an element" philosophy, as explained in <a href="https://www.polymer-project.org/docs/start/everything.html">The Polymer World-View</a>:</p>
1502<blockquote>
1503<p> Consider the humble <code><select></code>. We take it for granted, but it's actually pretty impressive:</p>
1504<ul>
1505<li><em>Functional.</em> The browser already knows what to do with a <code><select></code> element. When it encounters <code><select></code> in markup it creates an interactive control for the user.</li>
1506<li><em>Reusable.</em> The <code><select></code> element is a reusable package of functionality that you don't have to implement yourself.</li>
1507<li><em>Interoperable</em>. Every JavaScript library knows how to interact with DOM elements.</li>
1508<li><em>Encapsulated.</em> It keeps its internals all tucked away, so including one won't break the rest of your page.</li>
1509<li><em>Configurable.</em> You can configure its behavior with HTML attributes, without using any script.</li>
1510<li><em>Programmable.</em> If you grab the element from the DOM it also has methods and properties for things that don't make sense in markup.</li>
1511<li><em>Event Generator.</em> It dispatches events to let you know when something interesting happens.</li>
1512<li><em>Composable.</em> Not only can you include a <code><select></code> inside of most other kinds of element, its behavior can also change depending on which things you put inside of it.</li>
1513</ul>
1514</blockquote>
1515<h4 id="bootstrap">Bootstrap</h4>
1516<p>Another interesting architecture that inspired me to write declarative HTML APIs, long before I discovered Web Components or Angular, is <a href="http://getbootstrap.com/javascript/#js-data-attrs">Bootstrap's Data API</a>.</p>
1517<p>This architecture can be summarized as follows:</p>
1518<pre><code class="lang-css">[data-{verb}={component}]
1519[data-target={selector}]
1520.{component}-{modifier}
1521</code></pre>
1522<p>An example, using their (<a href="http://getbootstrap.com/javascript/#alerts">http://getbootstrap.com/javascript/#alerts</a>) component: </p>
1523<pre><code class="lang-html"><!--
1524Using data-dismiss without target will traverse
1525up the DOM until an "alert" component instance
1526is found, and will invoke its "dismiss" method.
1527-->
1528<div class="alert alert-dismissable">
1529<button data-dismiss="alert"></button>
1530</div>
1531<!--
1532Using data-target to manually specify
1533the component instance.
1534-->
1535<div class="alert alert-dismissable" id="myAlert"></div>
1536<button data-dismiss="alert" data-target="#myAlert"></button>
1537</code></pre>
1538<h4 id="angular">Angular</h4>
1539<p>The declarative HTML approach started to really interest me when I saw an (<a href="https://angularjs.org/#add-some-control">example">https://angularjs.org/#add-some-control">example</a> todo app using Angular dir).</p>
1540<p>The interesting thing to me is that all the JavaScript parts are just APIs. None of them control the application flow directly. Each of them has one responsibility, and you need to tell it what to do and when.</p>
1541<p>Angular introduced three concepts to make it easy to wire components together into an app using HTML:</p>
1542<ul>
1543<li>Scopes</li>
1544<li>Bindings</li>
1545<li>DOM-level dependency injection</li>
1546</ul>
1547<p>Especially the dependency injection is powerful in composing apps using just HTML. The Angular injector goes further than injecting singleton or transient services into each other. You can declaratively inject component instances into each other, based on their position in the DOM.</p>
1548<p>For example, injecting <code><form-field-{type}></code> components into parent <code><form></code> components, and <code><form></code> components into parent <code><form></code> components. In this particular example you could leverage it to determine the validity of a form based on the validity of child component instances.</p>
1549<p>Injecting <code><tab-pane></code> components into a parent <code><tab-container</code>> to automatically keep an up-to-date list of tabs based on the current DOM.</p>
1550<p>Scopes, combined with powerful single-purpose directives such as <code>[ng-if]</code> and <code>[ng-repeat]</code>, will update the DOM and create/destroy component instances based on your model bindings. No JavaScript needed to wire everything together.</p>
1551<h4 id="aurelia">Aurelia</h4>
1552<p><a href="http://aurelia.io/docs.html">The Aurelia Framework</a> categorizes components into three common types:</p>
1553<ul>
1554<li><em>Custom Elements:</em> Add new tags to your HTML markup. Each Custom Element can have its own view template which can be rendered into the Light DOM or the Shadow DOM. Custom Elements can also have any number of properties which they surface as attributes in HTML for databinding support and which they can databind to inside their view template.</li>
1555<li><em>Attached Behaviors:</em> "Attach" new behavior or functionality to existing HTML elements by adding a custom attribute to your markup.</li>
1556<li><em>Template Controllers:</em> Convert DOM into an inert HTML template. The controller can then decide when and where (or how many times) to instantiate the template in the DOM. Examples of this are the if and repeat behaviors. Simply place one of these behavior on a DOM node and it becomes a template, controlled by the behavior.</li>
1557</ul>
1558<p>Angular 2.x has the same types, except they are calling them Components, Decorators and Templates.</p>
1559<h3 id="philosophy-summarized">Philosophy summarized</h3>
1560<ul>
1561<li>Use declarative HTML to compose apps out of components.</li>
1562<li>Leverage DOM hierarchy for component dependencies and life cycle management.</li>
1563<li>Build single-purpose components with explicit dependencies. Components can work together by letting them share bindings, and components can delegate to other components internally.</li>
1564</ul>
1565<h3 id="benefits">Benefits</h3>
1566<ul>
1567<li>We can compose apps very rapidly, while still having very maintainable code.</li>
1568<li>The impact of change is predictable because of a good separation of concerns.</li>
1569<li>Application flow in HTML is very readable. It's a good starting point when picking up a user story.</li>
1570<li>Easy memory management as component instances are automatically created and cleaned up, based on the scopes that they are part of.</li>
1571</ul>
1572<h2 id="project-architecture">Project architecture</h2>
1573<p>Based on the list of deliverables and our component philosophy, let's take a look at the actual component library architecture.</p>
1574<h3 id="tools">Tools</h3>
1575<ul>
1576<li><em>Application framework:</em> <a href="https://angularjs.org/">Angular</a></li>
1577<li><em>Package management:</em> <a href="http://bower.io/">Bower</a></li>
1578<li><em>Changelog generator:</em> <a href="http://git-scm.co">Git</a> + [Conventional Changelog](<a href="https://github.com/ajoslin/conventional-changelog">https://github.com/ajoslin/conventional-changelog</a></li>
1579<li><em>Documentation generator:</em> <a href="https://github.com/angular/dgeni">Dgeni</a></li>
1580<li><em>Data contracts:</em> <a href="http://www.typescriptlang.org/">TypeScript</a> (source language), generated into <a href="http://json-schema.org/">JSON Schemas</a> (using <a href="https://github.com/lbovet/typson">Typson</a>) for server and client side validation (using <a href="http://www.newtonsoft.com/json">Json.NET</a> on the server and <a href="http://geraintluff.github.io/tv4/">Tiny Validator</a> on the client)
1581In addition, we are using a couple of Continuous Integration tools (e.g. <a href="http://jenkins-ci.org/">Jenkins</a>), to automate most of the build processes and making their output available to clients.</li>
1582</ul>
1583<h4 id="angular">Angular</h4>
1584<p>Angular makes us extremely productive in building declarative, single purpose components.</p>
1585<p>Our Angular components will do all the heavy lifting, apps are composed using a bit of HTML.</p>
1586<p>Speaking of heavy lifting, Angular's focus on writing testable components is also a huge plus. I've experienced that writing testable Angular components actually helps in designing them well, too. Your tests will not take it easy on you if you have not separated your concerns well enough.</p>
1587<p>Having good test coverage in our components will cause apps to require very little unit testing in return. After all, the apps are just connecting all the different components and have almost no custom logic.</p>
1588<h4 id="bower">Bower</h4>
1589<p>We split components into separate packages as much as needed. Some packages will contain only one component (e.g. authentication), others will contain a collection of smaller components (e.g. form field components).</p>
1590<p>The goal is to clearly define dependencies between packages (as opposed to stuffing everything in a single package, with more implicit internal dependencies).</p>
1591<p>Also, we don't just specify the package name as dependency but also the version. Using <a href="http://semver.org">Semantic Versioning</a> and a changelog per component, we'll maintain a good amount of transparency in compatibility between components and apps.</p>
1592<h4 id="conventional-changelog">Conventional Changelog</h4>
1593<p>Conventional Changelog is a set of <a href="https://github.com/ajoslin/conventional-changelog/blob/master/CONVENTIONS.md">Git commit message conventions</a>, and a tool to generate a readable Markdown file based on your Git commits.</p>
1594<p>Nobody wants to maintain a changelog manually. Plus, a wise developer once told me that "later equals never". It's best to describe the changes while you are actually doing them, in your Git commit message.</p>
1595<p>The relevant Git commits will automatically appear in the changelog, grouped per component. (By default, only commits of the type "feature" and "bug fix" appear in the changelog. Other types are ignored.)</p>
1596<p>The convention in short:</p>
1597<pre><code>{type}({scope}): {subject}
1598{BLANK LINE}
1599{body}
1600</code></pre><p>A few simple examples:</p>
1601<pre><code>feat(authentication): add server request to #logout()
1602</code></pre><pre><code>fix(authentication): notify #logout() promise of failed attempt
1603Use case: `authentication.logout().then(onSuccess, onError)`
1604Before: onError never called
1605After: onError called if response status is 4xx
1606</code></pre><h4 id="dgeni-typescript-typson-amp-json-schema">Dgeni, TypeScript, Typson & JSON Schema</h4>
1607<p>Dgeni is an extremely powerful documentation generator framework. It's built by people from the Angular team, particularly suitable for Angular projects but I've used it successfully for non-Angular projects as well.</p>
1608<p>We use the following <a href="https://github.com/angular/dgeni-packages">Dgeni packages</a>:</p>
1609<ul>
1610<li><em>NgDoc:</em> Generates API references for anything that is part of JSDoc, with added support for directives, controllers, filters, services and providers.</li>
1611<li><em>Examples:</em> Generates runnable examples. We use this to provide each component with a demonstration of its features, along with code to get people started with using the component.</li>
1612</ul>
1613<p>In addition, we created a custom "Schemas" package to document JSON contracts, component parameters and their connections. The package contains:</p>
1614<ul>
1615<li>A file reader: Reads out TypeScript files and adds all the defined interfaces to the documentation index (using doc type "schema").</li>
1616<li>A processor: Parses the "schema" docs through the Typson JSON Schema generator.</li>
1617<li>A rendering filter: Connects documented <code>@param</code>s (from directives and functions) with a schema doc if there is one with a matching name.</li>
1618</ul>
1619<p>The Dgeni framework resembles Angular in a lot of ways. The <a href="https://github.com/angular/dgeni/blob/b91bfe5e2724a85d07dda22b6a15fa0537ea19e4/README.md#packages">package interface</a>, using Angular's injector on Node.js (of course), makes it very easy to create your own documentation generator based on your specific needs.</p>
1620<h3 id="anatomy-of-a-component">Anatomy of a component</h3>
1621<p>To make everything just a bit more visual, let's take a look at the contents of a component.</p>
1622<h4 id="file-structure-template">File structure template</h4>
1623<pre><code>PROJECTNAMESPACE-COMPONENTNAME/
1624 bower.json
1625 index.js
1626 COMPONENTNAME-{directive|filter|service}.js
1627 COMPONENTNAME-{directive|filter|service}_test_unit.js
1628 COMPONENTNAME-directive_test_e2e.js
1629 COMPOENNTNAME-directive.html
1630 COMPONENTNAME-INTERFACENAME.ts
1631 example/
1632 manifest.json
1633 index.html
1634 (+ any other files listed in manifest.json)
1635</code></pre><p>A component is essentially a Bower package (bower.json) containing a single Angular module (index.js). These are the entry points for other components that include it as their dependency.</p>
1636<p>Most other files are referenced only internally, or used by build processes (e.g. test runner and documentation generator).</p>
1637<p>For testing, we distinguish between Unit and End-to-End (E2E) tests:</p>
1638<ul>
1639<li>Components that publish APIs will need unit tests to verify that all information is processed and returned as expected.</li>
1640<li>Visual components will need E2E tests to verify that all information is rendered as expected.</li>
1641</ul>
1642<h4 id="file-structure-example-login-form">File structure example: login form</h4>
1643<p>Let's take a look at an extremely simplified version of a login form component. It's a visual component that accepts a specific JSON structure to build up the form fields and action buttons. Then, all the hard work (actually logging in, performing form validation, toggling a modal containing the form, etc) is delegated to other components.</p>
1644<pre><code>PROJECTNAMESPACE-login-form/
1645 bower.json
1646 index.js
1647 login-form-directive.js
1648 login-form-directive_test_e2e.js
1649 login-form-directive.html
1650 example/
1651 manifest.json
1652 index.html
1653 index.js
1654 login-form-response.json
1655 login-action-success-response.json
1656 login-action-error-response.json
1657</code></pre><h5 id="bower-json">bower.json</h5>
1658<pre><code class="lang-javascript">{
1659 "name": "PROJECTNAMESPACE-login-form",
1660 "version": "X.Y.Z",
1661 "dependencies": {
1662 "PROJECTNAMESPACE-authentication": "X.Y.Z",
1663 "PROJECTNAMESPACE-form": "X.Y.Z",
1664 "PROJECTNAMESPACE-modal": "X.Y.Z"
1665 }
1666}
1667</code></pre>
1668<h5 id="index-js">index.js</h5>
1669<pre><code class="lang-javascript">angular.module('PROJECTNAMESPACE.components.loginForm', [
1670 'PROJECTNAMESPACE.components.authentication',
1671 'PROJECTNAMESPACE.components.form',
1672 'PROJECTNAMESPACE.components.modal'
1673]);
1674</code></pre>
1675<h5 id="login-form-directive-js">login-form-directive.js</h5>
1676<pre><code class="lang-javascript">angular.module('PROJECTNAMESPACE.components.loginForm')
1677 .directive('PROJECTNAMESPACELoginForm', loginFormDirective);
1678/**
1679 - @ngdoc directive
1680 - @name PROJECTNAMESPACELoginForm
1681 - @module PROJECTNAMESPACE.components.loginForm
1682 - - @param fields {FieldType[]}
1683 - @param actions {FormAction[]}
1684 */
1685function loginFormDirective { ... }
1686</code></pre>
1687<p>The documented parameters match with some of the type definitions (next section), which are provided by components listed as a dependency for the login form component.</p>
1688<h5 id="used-type-definitions">Used type definitions</h5>
1689<h6 id="namespace-form-field-type-ts">NAMESPACE-form/field-type.ts</h6>
1690<pre><code class="lang-javascript">enum FieldType {
1691 TextField,
1692 NumberField,
1693 DateField,
1694 (etc)
1695}
1696</code></pre>
1697<h6 id="namespace-form-form-action-ts">NAMESPACE-form/form-action.ts</h6>
1698<pre><code class="lang-javascript">interface FormAction {
1699 label:string;
1700 name:ServerApi;
1701}
1702</code></pre>
1703<h6 id="namespace-server-api-server-api-ts">NAMESPACE-server-api/server-api.ts</h6>
1704<pre><code class="lang-javascript">enum ServerApi {
1705 Login,
1706 Logout,
1707 CreateAccount,
1708 ResetPassword,
1709 (etc)
1710}
1711</code></pre>
1712<h6 id="namespace-form-text-field-ts">NAMESPACE-form/text-field.ts</h6>
1713<pre><code class="lang-javascript">interface TextField extends Field {
1714 value:string;
1715 validations:TextFieldValidations;
1716}
1717</code></pre>
1718<h6 id="namespace-form-text-field-validations-ts">NAMESPACE-form/text-field-validations.ts</h6>
1719<pre><code class="lang-javascript">interface TextFieldValidations {
1720 required:boolean;
1721 minlength:number;
1722 maxlength:number;
1723 pattern:string;
1724}
1725</code></pre>
1726<h6 id="namespace-form-field-ts">NAMESPACE-form/field.ts</h6>
1727<pre><code class="lang-javascript">interface Field {
1728 label:string;
1729 name:string;
1730 help:string;
1731}
1732</code></pre>
1733<h5 id="tests">Tests</h5>
1734<p>In this example we have a login form directive, which is just a visual component, delegating most of the work to the APIs of other components.</p>
1735<p>The components containing the APIs would contain unit tests to verify that all information is processed and returned as expected.</p>
1736<p>The login form directive (and the smaller visual components, e.g. form field directives) would contain E2E tests to verify that all returned information from the APIs is rendered as expected.</p>
1737<h5 id="the-example-folder">The "example" folder</h5>
1738<h6 id="manifest-json">manifest.json</h6>
1739<pre><code class="lang-javascript">{
1740 "module": "PROJECTNAMESPACE.examples.loginForm",
1741 "files": ["index.html", "index.js"]
1742}
1743</code></pre>
1744<h6 id="index-html">index.html</h6>
1745<pre><code><div ng-controller="ExampleController as example">
1746 <PROJECTNAMESPACE-login-form
1747 fields="example.loginForm.fields"
1748 actions="example.loginForm.actions">
1749 </PROJECTNAMESPACE-login-form>
1750</div>
1751</code></pre><h6 id="index-js">index.js</h6>
1752<pre><code class="lang-javascript">angular.module('PROJECTNAMESPACE.examples.loginForm', [
1753 'PROJECTNAMESPACE.components.loginForm'
1754])
1755// Example-specific components
1756.controller('ExampleController, ['$http', ExampleController]);
1757function ExampleController($http) {
1758 var controller = this;
1759 $http({url: 'login-form-response.json'})
1760 .then(function(response) {
1761 controller.loginForm = response.data;
1762 }));
1763}
1764</code></pre>
1765<h3 id="anatomy-of-an-app">Anatomy of an app</h3>
1766<p>The app is essentially also just a component, called "app". Its responsibility is to bootstrap the application, delegating everything else to the other components.</p>
1767<p>Steps that could be part of the "app" component include specifying the server API(s), setting up the main router, performing the first request which can then be handled by all sorts of components which will take everything from there. The application starts to live its life once that is done.</p>
1768<h2 id="so-much-to-talk-about-">So much to talk about!</h2>
1769<p>With this blog post I wanted to give you an overview of the way we work with Angular. So many details have been left out, though. I'll be addressing some of these in separate posts.</p>
1770<p>Topics that I'm considering, include:</p>
1771<ul>
1772<li>Using the <a href="http://martinfowler.com/bliki/CQRS.html">CQRS</a> to abstract away the server implementation (e.g. HTTP, WebSocket) from data components.</li>
1773<li>Building your own documentation generator using Dgeni, using a couple of use cases from different projects that we did.</li>
1774<li>A walkthrough of a complex component design: designing the API, writing tests for it, implementing the component, building a runnable example, etc.</li>
1775<li><p>Leveraging the latest features of ngModel and ngModelOptions to build a data driven form component library.
1776I'm also speaking at meetups regularly about some of these topics. Currently, my favorite meetups are:</p>
1777</li>
1778<li><p><a href="http://www.meetup.com/Frontend-Developer-Meetup-Amsterdam/">Frontend Developer Meetup Amsterdam</a> (organized by The Frontend Lab)</p>
1779</li>
1780<li><a href="http://www.meetup.com/AngularJS-Amsterdam-Meetup/">AngularJS AMsterdam Meetup</a> (also organized by The Frontend Lab, will probably move towards a more general framework meetup instead of just Angular)</li>
1781<li><a href="http://www.meetup.com/Dutch-AngularJS-group/">Dutch AngularJS Group</a> (organized by, let's call it "Carmen Popoviciu & Friends" :-D)</li>
1782</ul>
1783]]></content:encoded>
1784 </item>
1785<item>
1786 <title>From favicon to app icon</title>
1787 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/from-favicon-to-app-icon</guid>
1788 <pubDate>Sun, 08 Feb 2015 00:00:00 GMT</pubDate>
1789 <link>https://www.voorhoede.nl/en/blog/from-favicon-to-app-icon</link>
1790 <dc:creator><![CDATA[Sanne]]></dc:creator>
1791<dc:creator><![CDATA[Jeroen]]></dc:creator>
1792 <category><![CDATA[favicon]]></category>
1793<category><![CDATA[icon]]></category>
1794<category><![CDATA[iOS]]></category>
1795<category><![CDATA[Android]]></category>
1796<category><![CDATA[Safari]]></category>
1797<category><![CDATA[Chrome]]></category>
1798<category><![CDATA[IE]]></category>
1799<category><![CDATA[Windows]]></category>
1800<category><![CDATA[browser]]></category>
1801<category><![CDATA[theme]]></category>
1802<category><![CDATA[color]]></category>
1803 <description><![CDATA[Using favicons and app icons to brand your web apps on every browser]]></description>
1804 <content:encoded><![CDATA[<h1 id="from-favicon-to-app-icon">From favicon to app icon</h1>
1805<p>With the growing number of mobile users, it is important to keep your branding strong on all sorts of devices. While many sites have a favicon, lots of sites are still missing app icons for smart phones and tablets.</p>
1806<h2 id="the-favicon">The Favicon</h2>
1807<p><img src="https://www.voorhoede.nl/assets/images/favicon-in-ie.jpg" title="A few examples of places where a favicon can be displayed on Windows Vista (IE9 and IE10)" alt="favicon in ie" /></p>
1808<p>When the favicon was first introduced in 1999, it was an <em>icon</em> shown in the <em>favorites</em> menu of Internet Explorer, hence the name favicon. Today, favicons have evolved beyond being a simple bookmark and are now showing on a variety of places.</p>
1809<h2 id="touch-icons">Touch icons</h2>
1810<p><img src="https://www.voorhoede.nl/assets/images/app-icon-on-android.jpg" title="The home screen of an Android device: the middle one has a touch icon defined, the right one hasn't" alt="android" /></p>
1811<p>Touch icons are the favicons of smart phones and tablets. By adding a touch icon, users that save the web page to the home screen of their device will see an app-like icon instead of an image of the page.</p>
1812<h3 id="windows-8-tile">Windows 8 Tile</h3>
1813<p><img src="https://www.voorhoede.nl/assets/images/app-icon-on-tile.jpg" title="A 'De Voorhoede' tile on a Window Phone 8" alt="windows phone" /></p>
1814<p>With Windows 8, Microsoft introduced the Metro style and the use of tiles: users can pin their favorite websites to their start screen, giving it it's own tile as a shortcut to the web page. We can specify the image and the background color (as a hex-color code) of the tile. The title is taken from the website's title.</p>
1815<p>The user can choose four different tile sizes:</p>
1816<ul>
1817<li>large (310 x 310 pixels)</li>
1818<li>wide (310 x 150 pixels)</li>
1819<li>medium (150 x 150 pixels)</li>
1820<li>small (70 x 70 pixels)</li>
1821</ul>
1822<h3 id="android-chrome-theme-color">Android Chrome theme color</h3>
1823<p><img src="https://www.voorhoede.nl/assets/images/android-theme-color.jpg" title="The overview mode on Android 5.0 Lollipop" alt="theme-color" /></p>
1824<p>Since version 39 of Chrome, not only can we add app icons to make our site more recognizable, we can add a custom background color as well. Google Chrome on Android 5.0 Lollipop displays open tabs in the 'overview mode', along with other running apps. For this overview mode, we are able to specify the background color of the toolbar, making sure it will match the look and feel of our site. </p>
1825<h2 id="some-helpful-tools">Some helpful tools</h2>
1826<p>Back in 1999, adding a favicon to your website was pretty simple and straightforward. Favicons were produced in ICO format and were simply added to the root folder of the domain as /favicon.ico.
1827Now that screen sizes and resolutions have become much more heterogeneous, we can no longer get away with a single graphic.</p>
1828<p> Creating the right app icons for all devices can take up a lot of time. Fortunately, there are some tools that can help you out:</p>
1829<ul>
1830<li><a href="http://realfavicongenerator.net/">The Real Favicon Generator</a></li>
1831<li><a href="http://iconogen.com/">Iconogen</a></li>
1832</ul>
1833<p>With these tools, all you have to do is upload one high definition picture. The tool will generate all the app icons for PC and Mac, iOS and Android, Windows Phones and tablets for you, as well as the required snippet of HTML.</p>
1834<p>App icons are literally a small part of your website. However, they are important for site recognition and branding, especially now that they are showing up in more and more places. Luckily, tools like the Real Favicon Generator and Iconogen save us a lot of time in generating all the app icons we need.</p>
1835]]></content:encoded>
1836 </item>
1837<item>
1838 <title>Email Template Guide</title>
1839 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/email-template-guide</guid>
1840 <pubDate>Mon, 02 Feb 2015 00:00:00 GMT</pubDate>
1841 <link>https://www.voorhoede.nl/en/blog/email-template-guide</link>
1842 <dc:creator><![CDATA[João]]></dc:creator>
1843 <category><![CDATA[email]]></category>
1844<category><![CDATA[e-mail]]></category>
1845<category><![CDATA[front-end guide]]></category>
1846<category><![CDATA[front end guide]]></category>
1847<category><![CDATA[template]]></category>
1848 <description><![CDATA[Our email template guide is a tool to simplify our process to develop, debug and build our email templates.]]></description>
1849 <content:encoded><![CDATA[<h1 id="email-template-guide">Email Template Guide</h1>
1850<p>I reluctantly open my favorite editor, clear my mind of most of the best practises I've been pushing myself to learn, create a blank HTML, turn my clock back to 1994 and start typing <code><table></code>... </p>
1851<p>Yes, I'm starting a new email newsletter and if you ever done one you know what I am talking about. If you didn't you are missing one of the best journeys that a front-end developer can have. From needing to do all <a href="http://backgrounds.cm/">this</a> for a simple image background, to having to inline all your css styles, passing by the fact that you have to add a span inside of a link to make sure you have a right color on your link:</p>
1852<pre><code class="lang-html"><a href="http://somesite.com/" style="color:#ff00ff">
1853 <span style="color:#ff00ff">this is a link</span>
1854</a>
1855</code></pre>
1856<p>The above examples are just the tip of the iceberg. And if you want to add responsive behaviour, it gets stripped out in Gmail for example. Even if the user's browser is capable of showing the behaviour. </p>
1857<p>When I start email developing I could use a demo template from <a href="http://zurb.com/ink/">Ink</a> or a <a href="http://mailchimp.com/features/email-templates/">free template from Mailchimp</a>. And during my progress I would definitely read posts from <a href="http://responsiveemailresources.com/">Responsive Email Resources</a>, <a href="https://litmus.com/blog/html-email-coding-101-infographic/email-coding-101">Litmus</a> or even <a href="https://www.campaignmonitor.com/resources/">Campaign Monitor</a>. Most of these post are written by people that have already been through hell and came back to help the living. But that would only help with part of the process.</p>
1858<p>There must be a better way <a href="https://www.youtube.com/watch?v=PBrQEcNMbQw">...</a></p>
1859<h2 id="introducing-the-email-template-guide">Introducing the Email Template Guide</h2>
1860<p>At De Voorhoede we are a big fans of automation. Whenever we are sure that the task we plan to do can be more effectively be done by a machine, we will try to automate it. For this reason we created for example our <a href="https://github.com/voorhoede/front-end-guide">front-end-guide</a> and based on the front-end-guide we created this nifty tool called Email Template Guide.</p>
1861<h3 id="so-what-is-the-email-template-guide-">So What is the Email Template Guide?</h3>
1862<p><img src="https://www.voorhoede.nl/assets/images/email-template-guide.jpg" title="Screenshot of the Email Template Guide" alt="Screenshot of the Email Template Guide" /> </p>
1863<p>The idea behind the Email Template Guide was to create a tool that would simplify our process to develop, debug and build our email templates. It achieves that by:</p>
1864<ul>
1865<li>Generating an HTML template built using components, because the email should be just one plain HTML page.</li>
1866<li>Inlining all style rules from generated stylesheets. Because not all email clients support stylesheets.</li>
1867<li>Allowing you to send generated templates to a testing service.</li>
1868<li>Allowing you to email generated templates to a real email address.</li>
1869</ul>
1870<h3 id="how-did-we-do-it-">How Did We Do It?</h3>
1871<p>Like our <a href="https://github.com/voorhoede/front-end-guide">front-end-guide</a> we built the Email Template Guide on top of <a href="https://www.npmjs.com/package/gulp">gulp</a>. We created a front end, where you can preview the different templates that you created based on your modules. These modules are nothing more than HTML with some <a href="https://github.com/mozilla/nunjucks">nunjucks</a> syntax. You can also check your css styles before they get <a href="https://github.com/jonkemp/gulp-inline-css">inlined</a>. And because we would like to make your day even more productive, we have implemented functionality to select one or more of your templates and send them to test. You have the option to send the selected template(s) to a specified email address via <a href="https://www.npmjs.com/package/nodemailer">nodemailer</a> or send them via Gulp to your <a href="https://www.npmjs.com/package/gulp-litmus">Litmus</a> account.</p>
1872<p><img src="https://www.voorhoede.nl/assets/images/litmus-example.jpg" title="Example of results for different web-based clients in Litmus" alt="Example of results for different web-based clients in Litmus" /> </p>
1873<p>Litmus is one of the best, if not the best, tool to thoroughly test your email newsletters on the different email clients. If you never used it you should give it a try, they have a <a href="https://litmus.com/signup/premium-plan">7 day trial period</a>.</p>
1874<h3 id="tell-me-more-">Tell Me More...</h3>
1875<p>This tool was based on other open source projects. So it would only make sense that we also made it available to everyone. You can find the project on <a href="https://github.com/voorhoede/email-template-guide">Github</a>.</p>
1876<p>If you want to know more about how to use the project, jump to our github repository and feel free to fork and/or give suggestions. Also make sure you read our <a href="https://github.com/voorhoede/email-template-guide#documentation">docs section</a>.</p>
1877<p>We already have some ideas for improvements on more stuff that would make this tool better but you can add yours to the <a href="https://github.com/voorhoede/email-template-guide/issues">issues list</a> if you wish.</p>
1878]]></content:encoded>
1879 </item>
1880<item>
1881 <title>Now We Git It!</title>
1882 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/now-we-git-it</guid>
1883 <pubDate>Thu, 22 Jan 2015 00:00:00 GMT</pubDate>
1884 <link>https://www.voorhoede.nl/en/blog/now-we-git-it</link>
1885 <dc:creator><![CDATA[Sanne]]></dc:creator>
1886 <category><![CDATA[version control]]></category>
1887<category><![CDATA[git]]></category>
1888<category><![CDATA[master class]]></category>
1889<category><![CDATA[academy]]></category>
1890 <description><![CDATA[We greatly extended our knowledge of the version control system by following Thoughtram's two-day workshop on the powers of Git.]]></description>
1891 <content:encoded><![CDATA[<h1 id="now-we-git-it-">Now We Git It!</h1>
1892<p>On the 15th and 16th of January, De Voorhoede attended <a href="http://thoughtram.io/">Thoughtram</a>'s <a href="http://thoughtram.io/git-master-class.html">Git Master Class</a>, a two-day workshop about the ins and outs of the Git version control system.</p>
1893<h2 id="why-should-you-use-version-control-">Why Should You Use Version Control?</h2>
1894<p>Version control is a system that records all of the changes to a file over time. It allows you to compare two versions of a file and revert files back to a previous version. Using version control also means that you can easily recover files if you messed up. These features make it an indispensable tool for developers.</p>
1895<p>At De Voorhoede, we use Git in all of our projects. Before the workshop, we were already familiar with most of Git's concepts: we knew how to fetch and merge changes, how to create a branch, etc.. However, we wanted to take our knowledge to the next level and be as productive as possible in our daily workflow. Thoughtram's workshop was a great opportunity for the Voorhoede developers to become real Git Masters.</p>
1896<h2 id="the-git-master-class">The Git Master Class</h2>
1897<p>The Git Master Class was supposed to be hosted at De Voorhoede office, but due to <a href="https://twitter.com/devoorhoede/status/543486032872624128">a little fire</a> in the building a few weeks ago, the venue was changed to the <a href="http://www.razmataz.nl/">Razmataz</a> restaurant. At Razmataz, De Voorhoede and the other attendees were welcomed by Thoughtram's trainers, <a href="https://twitter.com/cburgdorf">Christoph</a> and<a href="https://twitter.com/PascalPrecht">Pascal</a>.</p>
1898<p>During the introduction it became clear that most attendees joined the workshop for the same reason: we all know and use Git, but we wanted to truly grasp the underlying concepts and advance our knowledge about the version control system.</p>
1899<p>On day one, Christoph and Pascal walked us through the basics of version control and Git: What is a distributed version control system? What is the anatomy of a Git commit? What are branches and tags? These are a few of the questions that were answered in the morning. In the afternoon, we discussed more advanced topics including merge strategies and reset modes.
1900<img src="https://www.voorhoede.nl/assets/images/git-master-class2.jpg" title="null" alt="Class in session" /></p>
1901<p>During the second day, we dove in a little deeper and learned more about rebasing, working with remotes and how to cherry pick commits.</p>
1902<h2 id="what-did-we-learn-">What Did We Learn?</h2>
1903<p>A few of the most valuable lessons we learned are about Git branches and rebasing.</p>
1904<p>Git branches are part of our everyday development workflow. We create a new branch when we start working on a new feature or want to fix a bug. By creating a branch we make sure that we keep the code separate from the main code base. But what exactly is a branch? Even though we already used branches every day, we didn't know about the underlying implementation yet. To really understand the way Git handles branches, Christoph and Pascal first explained the way Git stores its data.</p>
1905<p>Git doesn't store data as a series of differences, but instead as a series of snapshots. When you make a commit, Git stores a commit object that contains a pointer to the snapshot of the content you staged. In Git, a branch is simply a movable pointer to a commit. When you create a new branch, all Git needs to do is to creates a new pointer - it doesn't change the repository in any other way.</p>
1906<p>To integrate committed changes from one branch into another branch we can use two techniques: merging and rebasing. At De Voorhoede, we commonly use the merge approach. However, we discovered that rebasing has some important benefits:</p>
1907<ul>
1908<li>Rebasing keeps your commit history clean, because there are no unnecessary merge commits.</li>
1909<li>If there's a conflict, the solution is not hidden in the merge commit, but in the actual commit.</li>
1910</ul>
1911<p>Branches and rebasing are a few of the key features of the Git version control system. During the workshop we have learned some clever tricks as well.</p>
1912<p>During everyday development, a small mistake is easily made. You can forget to stage a file or format your commit message the wrong way. The <code>git commit --amend</code> command is a convenient way to fix those little mistakes. It lets you combine staged changes with the previous commit instead of committing it as an entirely new snapshot, effectively modifying the previous commit.</p>
1913<p>During the workshop, Christoph and Pascal showed us how to set up aliases and shortcuts for git commands. Having aliases for commands that you use a lot makes your workflow a lot easier and faster. If you want to learn some useful Git aliases, have a look at <a href="http://dotfiles.github.io/">dotfiles.github.io</a>.</p>
1914<p>We had two fun and informative days. With the help of Thoughtram we were able to greatly extend our knowledge of Git. In the future, we will be able to work even more efficiently and productively.</p>
1915<p>More pictures of the workshop can be found at <a href="https://www.facebook.com/thoughtram/photos_stream">Thoughtram's Facebook page</a>.</p>
1916]]></content:encoded>
1917 </item>
1918<item>
1919 <title>Google glass in the port of Rotterdam Part 2</title>
1920 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/google-glass-in-the-port-of-rotterdam-part-2</guid>
1921 <pubDate>Mon, 27 Oct 2014 00:00:00 GMT</pubDate>
1922 <link>https://www.voorhoede.nl/en/blog/google-glass-in-the-port-of-rotterdam-part-2</link>
1923 <dc:creator><![CDATA[Tjerk]]></dc:creator>
1924 <category><![CDATA[Google glass]]></category>
1925<category><![CDATA[Rotterdam]]></category>
1926<category><![CDATA[port]]></category>
1927<category><![CDATA[harbor]]></category>
1928<category><![CDATA[harbour]]></category>
1929<category><![CDATA[augmented reality]]></category>
1930<category><![CDATA[research]]></category>
1931<category><![CDATA[safety]]></category>
1932 <description><![CDATA[Google Glass can help mechanics in the Port of Rotterdam to be more in control of his environment.]]></description>
1933 <content:encoded><![CDATA[<h1 id="google-glass-in-the-port-of-rotterdam-part-2">Google glass in the port of Rotterdam Part 2</h1>
1934<p>This is the second blog post about my thesis project I did at De Voorhoede. For the project, I have done research and made a testable prototype for a Google Glass application. The application has the goal to improve safety of mechanics in the port of Rotterdam. In my
1935<a href="/en/blog/google-glass-in-the-port-of-rotterdam/">last blogpost</a> I wrote about the general setting where my application will be used. In this blogpost I will explain more about what Google Glass is, and how it can assist the mechanics in their work.</p>
1936<p><img src="https://www.voorhoede.nl/assets/images/googleglassinportrotterdamwide.jpg" title="Google Glass in the port of Rotterdam" alt="Port of Rotterdam" /></p>
1937<h2 id="google-glass">Google Glass</h2>
1938<p>Google Glass has a small screen above the right eye where content can be displayed. The screen has a resolution of 640 x 360 pixels. The perceived size can be compared to standing in front of a 25" tv screen at 3 meters away. There is an integrated camera for taking pictures and recording videos. Glass is controlled by voice commands and a touchpad on the side of the device.</p>
1939<h2 id="middleware">Middleware</h2>
1940<p>With Bluetooth and Wi-Fi you can connect Glass with other smart devices, for instance with your smartphone. You can then receive and make calls through Glass and use your mobile internet connectivity and GPS. This is why Glass is also called 'middleware'. It can take over functionalities of other devices, and combine information of multiple sources to display relevant content for the user.
1941<img src="https://www.voorhoede.nl/assets/images/GoogleGlassWide.jpg" title="Google Glass" alt="Google Glass" /></p>
1942<h2 id="user-context">User Context</h2>
1943<p>Glass aims to make technology a more natural part of your daily activities. Through the display the user can access relevant information when he needs it. This can be done hands free, without the need to pick up an extra screen. To give the right information at the right time, Glass needs to know the context of the user. Where is he, what is he doing and what is happening around him? Glass can get the user context by using all kinds of data sources.</p>
1944<h2 id="mechanics-in-the-port-of-rotterdam">Mechanics in the Port of Rotterdam</h2>
1945<p>When mechanics are working in the terminal, a lot of times they are using both hands in their work. Also, they are moving from place to place. As described in my
1946 <a href="http://voorhoede.nl/blog/google-glass-in-the-port-of-rotterdam/">last blogpost</a>, the mechanics work in an environment with a lot of automated moving equipment, controlled by specialised software. Taking this in mind, how can they benefit from the use of Google Glass?
1947<img src="https://www.voorhoede.nl/assets/images/googleglassinportrotterdamwide2.jpg" title="Service mechanic at work with Google Glass" alt="Service mechanic with Google Glass" /></p>
1948<h2 id="information">Information</h2>
1949<p>Glass can give a mechanic direct information about his surroundings. This can be done using the data feed from the equipment software, the terminal operating system and the mechanic's GPS location. With Glass, the mechanic can access equipment status, the location of automated moving vehicles and their route. Combined with his own GPS-data, Glass can notify the mechanic when an automated vehicle approaches. Furthermore, it can give the mechanic information about new reports of failing equipment and show the equipment's maintenance history. With this information, the mechanic can take actions accordingly.</p>
1950<h2 id="communication">Communication</h2>
1951<p>But it doesn't stop with just information. With Glass, the mechanic can communicate directly with other people. He can call the control room, or video call an expert if he needs assistance for a specific problem. The expert can then watch through the eyes of the mechanic (or more specific, through Glass's camera) and guide him to fix the problem.
1952<img src="https://www.voorhoede.nl/assets/images/googleglassinportrotterdamsafety.jpg" title="Safety procedure on Google Glass" alt="Safety procedure" /></p>
1953<h2 id="safety-and-efficiency">Safety and Efficiency</h2>
1954<p>Glass can help the mechanic to be more in control of his environment. He can access all the information while he is on location, and do this hands free so that it doesn't interrupt his daily tasks. On the contrary: it will help him to be more efficient and, more importantly, be more safe.</p>
1955]]></content:encoded>
1956 </item>
1957<item>
1958 <title>Hacking with Angular 2.0</title>
1959 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/hacking-with-angular-20</guid>
1960 <pubDate>Tue, 16 Sep 2014 00:00:00 GMT</pubDate>
1961 <link>https://www.voorhoede.nl/en/blog/hacking-with-angular-20</link>
1962 <dc:creator><![CDATA[Maarten]]></dc:creator>
1963 <category><![CDATA[Angular]]></category>
1964<category><![CDATA[Angular 2.0]]></category>
1965<category><![CDATA[beta]]></category>
1966<category><![CDATA[components]]></category>
1967 <description><![CDATA[Our experience with Angular 2 beta during our hands-on workshop]]></description>
1968 <content:encoded><![CDATA[<h1 id="hacking-with-angular-2-0">Hacking with Angular 2.0</h1>
1969<p>At De Voorhoede, we've been using AngularJS for almost a year now. Meanwhile, Angular 2.0 is being designed in the open. I've been following its progress very closely. I get asked a lot to explain Angular to clients, and to advise them on architecture of apps and components. I often tell them about Angular 2 and the philosophy behind it, as we discuss different design practices. We use v1 eventually for its stability, but inspired by v2.</p>
1970<p>Last Friday, we organized an internal workshop to give everybody at De Voorhoede some first hands-on experience with Angular 2. In this post I’ll explain some of the things that I've learned personally, and share some experiences that we had during our workshop.</p>
1971<h2 id="before-the-workshop-following-angular">Before the Workshop: Following Angular</h2>
1972<p>Angular 2.0 was first announced on <a href="http://blog.angularjs.org/2014/03/angular-20.html">March 18 2014, on the Angular blog</a>. The blog post linked to a public <a href="https://drive.google.com/?pli=1#folders/0B7Ovm8bUYiUDR29iSkEyMk5pVUk">Google Drive folder containing design docs</a> and a <a href="https://drive.google.com/open?id=0AhgtL8yFJbacdEFmaUxJaEI0VVlPZDV5VE1Cd0wyTnc&authuser=0">progress tracker spreadsheet</a>.</p>
1973<p>Now, I'm one of those developers that just always has to look at all the Git commits that were involved in a release. For example, I just had to check how they implemented the <a href="https://github.com/angular/angular.js/commit/2ae4f40be1803d999ca2a8cc30ec17ff19ea6d86">asynchronous ng-model validators in v1.3.0-rc.0</a>, since I had once written my own, custom implementation for a project and was very curious to see how the official implementation ended up.</p>
1974<p>With Angular 2.0, it wasn't different. This Google Drive folder was a great chance to follow along with all the discussions and growing philosophy behind the framework. Besides keeping myself up-to-speed with the progress of the framework, the way they've been designing these components, continuously processing feedback from the community and doing all sorts of crazy code experiments has really been inspiring me.</p>
1975<p>Here are some of my favorite things that landed in v2:</p>
1976<h3 id="single-purpose-libraries">Single-purpose Libraries</h3>
1977<p>Before I started with Angular, I had done a lot with Backbone. It's often said that because Backbone is very minimal and unopinionated, one of the benefits of Backbone is that it encourages you to really think about your technical requirements. Designing an architecture specifically for those requirements, using your own selection of libraries to help you be more productive. When you use Angular, a big toolbox filled with everything you need to develop a web app, it's just very tempting stop thinking about architecture and let Angular lead the way. It seems like many developers just want someone to tell them how to build web appsÂ, as Brian Ford wrote it in <a href="http://briantford.com/blog/too-many-frameworks-qq">Stop Whining About New JS Frameworks</a>.</p>
1978<p>Angular 2 will not be an all or nothing framework, but a collection of single-purpose libraries. A first step in encouraging you to form your own opinions on application architecture. It's funny to see that once Angular's new dependency injection library had been released, it got picked up <a href="http://teropa.info/blog/2014/03/18/using-angular-2-0-dependency-injection-in-a-backbone-app.html">in the Backbone community</a> immediately. I love this kind of cross-pollination in open source.</p>
1979<h3 id="standards-modern-browsers-only">Standards & Modern Browsers Only</h3>
1980<p>Angular 1 is filled with non-standard APIs. Because of this, it can be very hard to integrate components in an Angular architecture when those components aren't written specifically for Angular. For example, when using a plain-JavaScript component that uses event handlers (the event handlers would need to be patched with digests). Similar problems arise when you want to use an asynchronous module loader or do anything with web components.</p>
1981<p>Angular was first released in 2010. The requirements of a web app architecture were very different from what they are now. Also, legacy browser support was much more of an issue than it is now. Angular 2 will focus on modern standards and browsers, allowing it to really push the envelope of possible and provide developers with a next generation experience.</p>
1982<p>These are a few of the technologies used in Angular 2:</p>
1983<ul>
1984<li>modules are <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla">ES6</a> or <a href="https://github.com/amdjs/amdjs-api/blob/master/AMD.md">AMD</a>, using <code>export</code> to provide values, functions and classes (services)</li>
1985<li><a href="http://webcomponents.org">Web Components</a>, <a href="http://www.w3.org/TR/shadow-dom/">shadow DOM</a>, <a href="(https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html"><code><template></code></a>);</li>
1986<li><a href="http://www.html5rocks.com/en/tutorials/es7/observe/">Object.observe</a></li>
1987<li><a href="https://developer.mozilla.org/en/docs/Web/API/MutationObserver">DOM mutation observers</a></li>
1988</ul>
1989<p>Development on v1 will be continued (and some features from v2 backported) as an alternative for projects that need the broader browser support.</p>
1990<h3 id="di-annotations">DI & Annotations</h3>
1991<p>Annotations are one of the few things in Angular 2 that aren't currently part of any standard. They were first explained at <a href="https://www.youtube.com/watch?v=_OGGsf1ZXMs">ng-conf 2014: DI by Vojta Jina</a>.</p>
1992<p>Before Angular 2, I had personally never used annotations. Once I started reading about them, I immediately liked how they separate meta data from the code. During recent projects, I’ve spoken a lot with Java developers, who have been familiar with using annotations for years. Simon Brown mentions annotations as a way to express software architecture as code, and to <a href="http://www.codingthearchitecture.com/2014/07/08/identifying_architectural_elements_in_current_systems.html">identify architectural elements</a> when navigating through a system.</p>
1993<p>Annotations appear all over the place in Angular 2, so for examples just keep on reading.</p>
1994<h3 id="new-directive-apis">New Directive APIs</h3>
1995<p>The directive API of v1 is pretty overwhelming. It makes learning Angular more difficult, and makes using a directive for a simple problem feel like overkill to some.</p>
1996<p>In Angular 2, <code>Directive</code> is an abstract class that you don't use directly. Instead, you use one of these three directive types, optimized for different purposes:</p>
1997<ul>
1998<li><code>DecoratorDirective</code>: decorate element, e.g. show/hide or add an event handler</li>
1999<li><code>TemplateDirective</code>: turn element into a template (example implementations: <a href="https://github.com/angular/templating/blob/master/src/lib/directive/ng_if.js">NgIf</a>, <a href="https://github.com/angular/templating/blob/master/src/lib/directive/ng_repeat.js">NgRepeat</a>)</li>
2000<li><code>ComponentDirective</code>: encapsulated JavaScript, HTML and CSS</li>
2001</ul>
2002<p>I like how these different APIs make you think: what kind of directive is it that you need? Do you need transclusion or an isolated execution context? You can’t have both. If you need both, make multiple directives and combine them in an umbrella component. It encourages smaller directives that work together. Smaller directives are easier to (unit) test, maintain and reuse.</p>
2003<h3 id="queryables">Queryables</h3>
2004<p>Basically the first thing we all had to unlearn when starting with Angular, is doing DOM queries. DOM queries are dangerous in an SPA, as the DOM is constantly changing and should not be talked to directly.</p>
2005<p>This is the role of controllers in Angular: they are the APIs of directives. The best-known examples are ng-model and ng-form. Models talk to forms, and forms talk to parent forms. They don't talk to the form <em>element</em>, though. They talk to the form <em>controller</em>. If you've ever written a custom ng-model validator, then you've registered your validator into the ng-model controller, instead of messing with the input element directly. It looks like this:</p>
2006<pre><code class="lang-javascript">angular.module('foo', [])
2007 .directive('fooValidator', function() {
2008 return {
2009 require: 'ngModel', // Find ngModel directive on the same element
2010 link: function(scope, element, attrs, ngModelController) {
2011 // Talk to ngModelController here...
2012 }
2013 };
2014 })
2015</code></pre>
2016<p>It's also possible to talk to parent controllers by using <code>^</code>:</p>
2017<pre><code class="lang-javascript">angular.module('foo', [])
2018 .directive('foo', function() {
2019 return {
2020 require: '^form', // Find parent (ng)form directive
2021 link: function(scope, element, attrs, ngFormController) {
2022 // Talk to the parent ngFormController here...
2023 }
2024 };
2025 })
2026</code></pre>
2027<p>You can't do it downwards, though. If the parent directive would query child directives, its result could get outdated pretty quickly because of the dynamic nature of the DOM in an SPA. This is why ng-models register themselves in parent forms, and deregister themselves when their scope is destroyed. This way, the form will always have an up-to-date representation of child models, which it will use to determine whether the form is valid or invalid. So you can safely use ng-if, ng-repeat etc around ng-models without the form getting an out-of-date representation.</p>
2028<p>Subtle detail: the order in which the ng-models are registered in their parent form, is the order in which they are instantiated. Which is not necessarily the current DOM order. Luckily this doesn't matter for ng-model, but what if your directive really needs them in the current DOM order (e.g., when binding arrow keys from above to cycle through menu items)?</p>
2029<p>Angular 2 introduces queryables for this. It provides a live representation of directives in the current DOM order. Querying directives is based on <em>roles</em> that directives can specify to make themselves queryable (so the name or selector of the directive is irrelevant).</p>
2030<p>This is how you would use it to add a custom validator to ng-model:</p>
2031<pre><code class="lang-javascript">@DecoratorDirective({selector: '[my-validator]'})
2032@Queryable('validator')
2033class MyValidator { ... }
2034</code></pre>
2035<p>NgModel would then inject all directives that are used on the same element and are queryable as a validator:</p>
2036<pre><code class="lang-javascript">@DecoratorDirective({selector: '[ng-model]'})
2037@Queryable('model')
2038class NgModel {
2039 // QueryScope.THIS will find directives on the same element
2040 constructor(@InjectQuery('validator', QueryScope.THIS) validators) {
2041 this.validators = validators;
2042 }
2043}
2044</code></pre>
2045<p>NgForm would inject both nested models and forms this way:</p>
2046<pre><code class="lang-javascript">@DecoratorDirective({selector: 'form'})
2047@Queryable('form')
2048class NgForm {
2049 // QueryScope.DEEP will go deeper down the DOM to find directives
2050 constructor(@InjectQuery('model', QueryScope.DEEP) models,
2051 @InjectQuery('form', QueryScope.DEEP) forms) {
2052 this.models = models;
2053 this.forms = forms;
2054 }
2055}
2056</code></pre>
2057<p>If you're curious like me and want to see the code behind this, take a look at Angular's <a href="https://github.com/angular/templating/blob/5785a2e7b9322e99d3a7f130162cbf3026bff337/src/lib/di/node_injector.js">Node Injector</a>.</p>
2058<h2 id="the-workshop-hands-on-angular-2">The Workshop: Hands-on Angular 2</h2>
2059<p>So, eversince that announcement on the Angular blog, I've been reading about Angular 2, hacking with it and talking to people about it. Up to the point where other Voorhoeders must have been annoyed by it. Still though, most of them attended the workshop I had prepared. Some of them had experience with Angular 1, others had no experience with Angular at all. It was intended as a one-hour session (starting at 10:00), but we continued until we just <em>had</em> to go for lunch, if you catch my drift.</p>
2060<h3 id="what-we-built">What We Built</h3>
2061<p>Those of us who had experience with Angular 1, were kind of confronted by how spoiled we've been by some of our favorite v1 features, of which most don't exist (yet) in v2. During our workshop we focused on rebuilding some of these favorite features, rather than trying to build an app. I envisioned myself building ng-model that morning, but I haven't really gotten around to it just yet ;).</p>
2062<p>We based our experiments on a <a href="https://github.com/mvbschot/hands-on-angular-2">Hands-On Angular 2 boilerplate</a> which already has all the required NPM modules, Bower components and Gulp tasks to instantly get your hands dirty.</p>
2063<p>The first exercise for everybody was building ng-cloak and ng-hide/ng-show. They're the simplest Angular features, so perfect to get familiar with the DecoratorDirective API and some basic routing to demonstrate the effect.</p>
2064<p>Result:</p>
2065<ul>
2066<li><a href="https://github.com/mvbschot/hands-on-angular-2/blob/master/src/directives/ng_cloak.js">NgCloak</a></li>
2067<li><a href="https://github.com/mvbschot/hands-on-angular-2/blob/master/src/directives/ng_show_hide.js">NgShow/NgHide</a></li>
2068<li><a href="https://github.com/mvbschot/hands-on-angular-2/blob/master/src/routes/ng_show_hide_demo.js">NgShow/NgHide demo route component</a></li>
2069<li><a href="https://github.com/mvbschot/hands-on-angular-2/blob/master/src/routes/ng_show_hide_demo.html">NgShow/NgHide demo view</a></li>
2070</ul>
2071<p>Another thing that I personally wanted to try, is the TemplateDirective API. I created two directives that work together, to change the content of the app header based on the current route.</p>
2072<p>Result:</p>
2073<ul>
2074<li><a href="https://github.com/mvbschot/hands-on-angular-2/blob/master/src/directives/title_bar.js">Title Bar Directives</a></li>
2075<li><a href="https://github.com/mvbschot/hands-on-angular-2/blob/master/src/index.html#L12">App header using <code>title-bar-view-port</code></a></li>
2076<li><a href="https://github.com/mvbschot/hands-on-angular-2/blob/master/src/routes/detail.html">Detail view using <code>title-bar-content</code> to display a link back to the overview</a></li>
2077</ul>
2078<h3 id="where-did-we-look">Where Did We Look</h3>
2079<p>There is absolutely no API reference for any of the libraries from Angular 2, at the moment. So we looked at design docs, examples and source code. We even looked at <a href="https://github.com/angular/templating/blob/5785a2e7b9322e99d3a7f130162cbf3026bff337/test/lib/compiler/selector.spec.js#L254">compiler unit tests</a> at some point to discover what kinds of selectors are supported for a directive.</p>
2080<p>It took us a while to discover <a href="https://github.com/angular/templating/blob/5785a2e7b9322e99d3a7f130162cbf3026bff337/src/lib/view_factory.js#L282"><code>on-*</code> attributes</a> this way, which aren't directives but nonetheless are the replacement of ng-click, ng-focus, etc.</p>
2081<p><code>bind-*</code> is another magical attribute that can be seen in the examples (used like this: <code><ANY ng-if bind-ng-if="expression"></code>) and it felt weird at first. Most of us kept feeling the instinct to write <code><ANY ng-if="expression"></code> like we do in Angular 1. The difference is now that the original attribute always contains a string (you can interpolate), and the <code>bind-*</code> variant is evaluated as an expression (using <a href="https://github.com/angular/expressionist.js">Expressionist</a> and can return other types as well (boolean, object, etc). The reasons for this separation are explained in <a href="https://t.co/FRdqvbgG7b">Databinding with Web Components by Misko Hevery & Rob Eisenberg</a>.</p>
2082<h3 id="how-did-we-feel">How Did We Feel</h3>
2083<p>There were mixed feelings ;).</p>
2084<p>People definitely struggled a bit with all the fancy new ES6, annotations and <a href="https://github.com/google/traceur-compiler">Traceur</a>, but at the same time loved that everything is based on standards. It may seem like a tiny thing to those who haven't worked with Angular 1, but to those who have, it was very satisfying to write a piece of asynchronous code (e.g., an event handler) and notice that it just works without having to wrap it with a<code>$scope.$apply()</code>.</p>
2085<p>I’ve seen that the lack of scope inheritance pissed some people off (also outside our workshop), personally I think it's a good thinking exercise. It will slow you down at first but it will also make you think carefully about the way you connect directives. When you inject controllers into each other (rather than just cross-referencing scopes), the directives end up so much easier to test and maintain.</p>
2086<p>The lack of an API reference was annoying on some level, but understandable as everything is still under heavy development. Personally I also enjoy digging into the source code and unit tests for hints on how to use something, but obviously I wouldn't want to use Angular 2 on anything with a deadline just yet ;).</p>
2087<h2 id="now-what-">Now What?</h2>
2088<p>Angular 2 has already changed the way I work, even when I'm using Angular 1. I think in decorator/template/component directives. I design smaller, single-purpose directives. I inject controllers into each other instead of cross-referencing scopes. I design component APIs, using the router to wire them together into workflows. All of these steps are helpful in making components more testable and maintainable.</p>
2089<p>At De Voorhoede, we'll still use Angular 1 for most of our projects on the short term. Angular 2 is a huge inspiration when we design our components; this will also help in upgrading apps when the time comes.</p>
2090<p>However, as we are starting to get more and more opinionated on how we think Angular components should look, we are currently in the design stage of some components that we will release into the open. We design for Angular 2 first (mobile first is so passe, ha ha), then backport the design to Angular 1. Check out our <a href="https://drive.google.com/folderview?id=0B-U4cWmra7tGU0FKbFZaVDUxX2M&usp=sharing">Voorhoede Angular Components folder on Google Drive</a> if you would like to take a peek, or better, participate in the discussion.</p>
2091<p>How about you? Have you tried Angular 2 yet? If you have, I would love to hear how you've experienced it. If you haven't tried it yet but are attending <a href="http://ngeurope.org/">ngEurope</a>, there will be lots of talks about Angular 2. And if you want to get your hands dirty, do try the <a href="https://github.com/mvbschot/hands-on-angular-2">boilerplate from our workshop</a>. It may be a nice quick start for you too. Exciting times for Angular developers.</p>
2092]]></content:encoded>
2093 </item>
2094<item>
2095 <title>Google glass in the port of Rotterdam</title>
2096 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/google-glass-in-the-port-of-rotterdam</guid>
2097 <pubDate>Wed, 11 Jun 2014 00:00:00 GMT</pubDate>
2098 <link>https://www.voorhoede.nl/en/blog/google-glass-in-the-port-of-rotterdam</link>
2099 <dc:creator><![CDATA[Tjerk]]></dc:creator>
2100 <category><![CDATA[Google glass]]></category>
2101<category><![CDATA[Rotterdam]]></category>
2102<category><![CDATA[port]]></category>
2103<category><![CDATA[harbor]]></category>
2104<category><![CDATA[harbour]]></category>
2105<category><![CDATA[augmented reality]]></category>
2106<category><![CDATA[research]]></category>
2107<category><![CDATA[safety]]></category>
2108 <description><![CDATA[How can a Google Glass application assist and increase the safety of mechanics in the port of Rotterdam?]]></description>
2109 <content:encoded><![CDATA[<h1 id="google-glass-in-the-port-of-rotterdam">Google glass in the port of Rotterdam</h1>
2110<p>The last few months at De Voorhoede I have worked on a project for my thesis. For this project, I'm doing research and making a testable prototype for a Google Glass application. The application has the goal to improve safety of mechanics in the port of Rotterdam. In this post, I will describe the general setting where my application will be used.</p>
2111<p><img src="https://www.voorhoede.nl/assets/images/container-terminal.jpg" title="Container Terminal at the port of Rotterdam" alt="container terminal" /></p>
2112<h2 id="port-of-rotterdam">Port of Rotterdam</h2>
2113<p>The port of Rotterdam is one of the largest and most advanced ports of the world. Yearly, more than 33.000 sea-ships ship more than 440 million tons of goods. A large portion consists of bulk goods like oil and ore, but there is also a considerate amount of break-bulk goods in containers.</p>
2114<p>To handle such large quantities, container terminals are running 24 hours, 365 days a year. Container terminals in Rotterdam are highly optimised for cost efficiency and productivity. Thats why parts of the handling process are fully automatic.</p>
2115<p><img src="https://www.voorhoede.nl/assets/images/agv-area.jpg" title="The area of automated guided vehicles" alt="automated guided vehicles" /></p>
2116<h2 id="automated-guided-vehicles">Automated Guided Vehicles</h2>
2117<p>When a sea ship enters a terminal, quay cranes load the containers off the ship onto the shore, on a Automated Guided Vehicle (AGV). The AGV moves the container from the crane to the stack. The stack is where the containers are stored until inland transport is ready.</p>
2118<p>The AGV and the area where the AGV is driving, between the quay crane and stack, is where we will put our focus on. The AGV moves the containers fully automatically. It moves along a transponder grid in the pavement of the terminal. Its movement is controlled by software called TEAMS (see below), made by <a href="http://www.tba.nl/">TBA</a>.</p>
2119<p><img src="https://www.voorhoede.nl/assets/images/teams.jpg" title="graphical interface of TEAMS software" alt="TEAMS GUI" /></p>
2120<h2 id="maintenance-and-safety">Maintenance and Safety</h2>
2121<p>Like all mechanical equipment, AGVs can break down. When this happens, a mechanic has to go into the AGV area to fix it. A part of the area where the AVGs move will be blocked, so the mechanic is not in danger of being hit by another AVG. Blocking an area is done by an operator in the control-room, with the use of the TEAMS software.</p>
2122<p>This situation is what my thesis is about. How can a Google Glass application assist and increase the safety of a mechanic when he is working in the AGV area? I did a lot of research to answer this question. Not only desktop-research, but also field research. I went to the port of Rotterdam, to see the dispatching of containers for myself. For my user research I also interviewed mechanics. This gave me a much better insight into what the end user's goals and needs are.</p>
2123<p><img src="https://www.voorhoede.nl/assets/images/interview.jpg" title="Interviewing a terminal mechanic" alt="Interviewing terminal mechanic" /></p>
2124<p>With all the information I gathered, I'm now in the middle of designing the actual application. My plan is to finish the first version at the end of this month. </p>
2125<h2 id="further-reading">Further Reading</h2>
2126<p>In my second <a href="/en/blog/google-glass-in-the-port-of-rotterdam-part-2/">second blogpost</a> about my thesis and this project I will discuss how I came up with this topic, and why I chose Google Glass to be the platform for my application. And, of course, I will write more about the application itself.</p>
2127]]></content:encoded>
2128 </item>
2129<item>
2130 <title>Hooked on Behavior Design</title>
2131 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/hooked-on-behavior-design</guid>
2132 <pubDate>Tue, 29 Apr 2014 00:00:00 GMT</pubDate>
2133 <link>https://www.voorhoede.nl/en/blog/hooked-on-behavior-design</link>
2134 <dc:creator><![CDATA[Tjerk]]></dc:creator>
2135 <category><![CDATA[behaviour]]></category>
2136<category><![CDATA[behavior]]></category>
2137<category><![CDATA[Meetup]]></category>
2138 <description><![CDATA[Our takeaways from the Behaviour Design Amsterdam meetup on the principles, safety and habit forming.]]></description>
2139 <content:encoded><![CDATA[<h1 id="hooked-on-behavior-design">Hooked on Behavior Design</h1>
2140<p>April 24th De Voorhoede was at the <a href="http://www.meetup.com/Behavior-Design-AMS/events/173715882/">Behavior Design Amsterdam</a> meetup for the first time. This meetup-group talks about how you can base your design on human behaviour or, the other way around, how you can design to influence human behaviour. A very interesting topic for us as front-end developers as well. In our agile scrum working approach we work closely with interaction designers. Understanding about each others work field is a key aspect in this process. Besides that I’m always curious what the underlying principles are of the stuff I develop. So enough reasons to go to this meetup!
2141<img src="https://www.voorhoede.nl/assets/images/karsalfrink.jpg" title="Kars Alfrink explaining principles of behavior design" alt="Kars Alfrink" /></p>
2142<h2 id="first-talk-principles-of-behavior-design">First Talk: Principles of Behavior Design</h2>
2143<p>First talk was from <a href="http://leapfrog.nl/">Kars Alfrink</a>, the principal designer at <a href="http://whatsthehubbub.nl/">Hubbub</a>. He talked about the principles of behavior design based on the <a href="http://www.implementationscience.com/content/6/1/42/">COM-B system</a>. COM-B is a ‘behaviour system’, involving three essential conditions: capability, opportunity, and motivation.</p>
2144<p>Kars used an intriguing quote in his presentation: “Just because you can measure it, doesn’t mean you shouldâ€. He explained that measuring is the first step in commoditization. Commoditization is the process by which goods and services that once had economic value and distinction end up becoming simple commodities in the eyes of the market consumers. Commoditization of design is bad, because it makes everything look and feel the same. At the end this will result in dull design, not interesting to the user.</p>
2145<p>Kars gave an example in games, where coded (and measured) behaviour prevents the user to be co-owner of the game. If you give the players more freedom, and give them the chance to play the game with there own rules, they will be much more connected and involved with your game.
2146<img src="https://www.voorhoede.nl/assets/images//dariugavrila.jpg" title="Dariu Gavrilla talking about 'Smart' cars" alt="Dariu Gavrilla" /></p>
2147<h2 id="second-talk-smart-cars">Second Talk: 'Smart' Cars</h2>
2148<p>Second talk was from <a href="http://www.gavrila.net/">Dariu Gavrila</a>. He is a senior research scientist at <a href="http://www.daimler.com">Daimler R&D</a>. There he is leading a team that works on ‘smart’ cars, cars that see (and act). The fruit of his labor can be found in the Mercedes-Benz E-class and S-Class models (2013). The amount of technology that is put in those cars is incredible. For example, the cars have 8 cameras with all kinds of sensors that collect data. With that data you can do all sorts of things. For instance, scanning the road in front of the car for bumps and adjust the shock absorbers accordingly. You can glide over the road that way. Or what about adaptive cruise control, with which the car can drive itself?</p>
2149<h3 id="pedestrian-safety">Pedestrian Safety</h3>
2150<p>The most important thing Dariu talked about was pedestrian safety. The smart cars can see when a pedestrian suddenly crosses the road, and can give the driver a warning or even use the brake by itself. Detecting whether there is actually somebody crossing the road is very hard. Thats why the cameras and sensors used in the cars are very advanced, and can make an almost 3d image of the surroundings.</p>
2151<figure data-type="video" class="wy-figure-full">
2152 <iframe class="youtube-video" src="//www.youtube.com/embed/6pF0GF3W-HQ?rel=0&autohide=1&showinfo=0" frameborder="0" allowfullscreen="">
2153 </iframe>
2154</figure>
2155
2156<p>Dariu also talked about what the future has in store for us. Daimler is now working on making the system even smarter. They want to predict in advance if a pedestrian wants to cross the road. Dariu and his team are using facial recognition and analyse the movement to see if this is the case. With facial recognition it is possible to see if a person sees the approaching car. They are also testing with camera’s facing the driver, so they can see if the driver is looking the right direction to see if a person is crossing the road.
2157<img src="https://www.voorhoede.nl/assets/images//nireyal.jpg" title="Nir Eyal talking about his book How to Build Habit-Forming Products" alt="Nir Eyal" /></p>
2158<h2 id="third-talk-habit-forming">Third Talk: Habit Forming</h2>
2159<p>The final talk was from <a href="http://www.nirandfar.com/">Nir Eyal</a>, author of the book <a href="http://www.nirandfar.com/hooked">‘Hooked: How to Build Habit-Forming Products’</a>. He studies behaviour design and habit forming. Nir talked about how technology pursuits people. How big companies like Twitter, Facebook and WhatsApp manage to make people develop new behaviour.</p>
2160<h3 id="the-hook">The Hook</h3>
2161<p>If your website or application has a business model that requires daily use to succeed, it’s important your website makes the user form a new habit. Nir has made a framework called ‘Hook’, that can help you achieve this. The Hook framework contains 4 elements: Trigger, Action, Reward and Investment.
2162<img src="https://www.voorhoede.nl/assets/images/hooked.jpg" title="Figurative presentation of the 'Hook'" alt="The Hook" /></p>
2163<h4 id="trigger">Trigger</h4>
2164<p>A trigger can be external, like a button or alarm, or internal, like an emotion. An example of an internal trigger is people visiting Facebook when they are lonely, or using Google if they are unsure about some information. A good design keeps this internal trigger in mind. Something that is mostly forgotten.</p>
2165<h4 id="action">Action</h4>
2166<p>The next element is the action. This is what the user does after the trigger. The action should be a very small thing, and is done in anticipation of a reward. Like hitting the search button on Google, or pressing play on Youtube.</p>
2167<h4 id="reward">Reward</h4>
2168<p>The reward is what follows the action. A real eye-opener to me was that the reward itself is not the most important thing. The anticipation for the reward is much more powerfull. This is called ‘the power of the unknown’. The reward can have many forms. For example, it can be a piece of content, like a search result on Google or a video on Youtube.</p>
2169<p>This was the part that fascinated me most of Nir's talk. It made me look at some web applications in a totally different way. Netflix for instance. I never understood why they don’t show a list of movies and tv series that are being added each month. Instead you have a slow and endless scroll page, where you go through all the content. Now I know why: because of the power of the unknown. You never know if you’ll find something good between all the mediocre content. And it works, at least for me. I regularly go back to Netflix, just to see if maybe I can find something I like.</p>
2170<h4 id="investment">Investment</h4>
2171<p>The last element is the investment. Investment loads the next trigger of the ‘hook’. Every message on WhatsApp is an investment. It’s an open invitation for an external trigger to be returned. The external trigger in this case is the message you get when you receive a reply.</p>
2172<p>There is a lot more behind the hook framework from Nir Eyal. I just bought his book and I’m planning to write more about the ‘hook’ in the future.</p>
2173<h2 id="recommended">Recommended</h2>
2174<p>This was a great Meetup. Very high level of speakers and very diverse talks. From more philosophical to practical, with real life examples. I can really recommend <a href="http://www.meetup.com/Behavior-Design-AMS/">this meetup-group</a>) for anyone who is interested in design and human behaviour. There is something for everyone!</p>
2175]]></content:encoded>
2176 </item>
2177<item>
2178 <title>Presentation-oriented Templating Syntax</title>
2179 <guid isPermaLink="true">https://www.voorhoede.nl/en/blog/presentation-oriented-templating-syntax</guid>
2180 <pubDate>Wed, 23 Apr 2014 00:00:00 GMT</pubDate>
2181 <link>https://www.voorhoede.nl/en/blog/presentation-oriented-templating-syntax</link>
2182 <dc:creator><![CDATA[João]]></dc:creator>
2183 <category><![CDATA[presentation]]></category>
2184<category><![CDATA[template]]></category>
2185<category><![CDATA[code]]></category>
2186<category><![CDATA[syntax]]></category>
2187<category><![CDATA[django]]></category>
2188<category><![CDATA[twig]]></category>
2189<category><![CDATA[nunjucks]]></category>
2190<category><![CDATA[liquid]]></category>
2191<category><![CDATA[swig]]></category>
2192<category><![CDATA[jinja]]></category>
2193<category><![CDATA[macros]]></category>
2194<category><![CDATA[filters]]></category>
2195 <description><![CDATA[The benefits of using semantic templates containing only presentation logic.]]></description>
2196 <content:encoded><![CDATA[<h1 id="presentation-oriented-templating-syntax">Presentation-oriented Templating Syntax</h1>
2197<p>As a web developer you have probably come across Presentation-Oriented Templating Syntax <abbr title="Presentation-Priented Templating Syntax">POTS</abbr> like this:</p>
2198<pre><code class="lang-html">{% block content %}
2199 <h1>{{ section.title }}</h1>
2200 {% for story in stories %}
2201 <h2>
2202 <a href="{{ story.url }}">
2203 {{ story.title }}
2204 </a>
2205 </h2>
2206 <p>{{ story.teaser }}</p>
2207 {% endfor %}
2208{% end block %}
2209</code></pre>
2210<p>Without any prior experience of using templating engines, I’m pretty sure it was obvious how it worked. At least you knew what result to expect.</p>
2211<p>This is by design: <em>the template system is meant to express presentation, not program logic</em>.</p>
2212<p>Django, a Python framework, first introduced this templating syntax which was later adapted to work with other frameworks and rendering engines like Jinja (Python), Twig (PHP), H2o (PHP), Nunjucks (JavaScript) and Liquid (Ruby). While other different programming languages and frameworks, the templating syntax for each is almost identical. Each supports the same notation for variables, filters, conditionals, inheritance, includes and comments.</p>
2213<p>This kind of templating engine provides tags which function similarly to some programming constructs – if tag for boolean tests, a for tag for looping, etc.; template inheritance and includes – for managing layouts and components;</p>
2214<p>In the following moments you will be able to get the key points of this kind of templating and also some small differences between the different languages that use them.</p>
2215<h2 id="why-pots-is-great">Why POTS is great</h2>
2216<ul>
2217<li>it has the same semantic and expressive syntax (notation) to bind data to markup for all frameworks using it</li>
2218<li>can be used interchangeably between different frameworks and rendering engines</li>
2219<li>has advanced methods to extend and include other templates</li>
2220<li>is easy to read and write, both for developers and designers</li>
2221</ul>
2222<p>To the advantages pointed before, the best that we could add is that: if you know one, you really know how to work with all of them. Right? Well, while they are pretty much the same, each one has some particular functionality that is usually related to the framework/language they are build on. So what are those little details and why should we care about it?</p>
2223<p>First of all, because the syntax is similar on different back-ends, we can be sure that we can use it no matter which backend language is used. Secondly, even though they all look pretty much the same, the project can benefit from a specific variation of the syntax. To understand the differences between the variations of templating frameworks using <abbr>POTS</abbr>, we will be focusing on variables,
2224filters, tags/conditionals and template inheritance.</p>
2225<h3 id="syntax-key-points">Syntax key points</h3>
2226<p>We will be comparing four variations of templating frameworks using <abbr>POTS</abbr>:</p>
2227<ul>
2228<li>Django ( the ‘original’ Python flavour)</li>
2229<li>Twig ( the PHP version)</li>
2230<li>Nunjucks ( the JavaScript version)</li>
2231<li>Liquid ( the ‘Shopify’ Ruby version)</li>
2232</ul>
2233<p>Since we can use the same data structure, we will use the following as an example:</p>
2234<pre><code class="lang-javascript">{
2235 "title": "Fishing experiences",
2236 "stories": [
2237 {
2238 "title": "In my own town",
2239 "teaser": "My journey from noob to fishing expert",
2240 "url": "/story/2",
2241 },
2242 {
2243 "title": "Meristics",
2244 "teaser": "Introduction to Meristics basics",
2245 "url": "/story/3",
2246 }
2247 ]
2248}
2249</code></pre>
2250<pre><code class="lang-html">{% block content %}
2251 <h1>{{ section.title }}</h1>
2252 {% for story in stories %}
2253 <h2>
2254 <a href="{{ story.url }}">{{ story.title }}</a>
2255 </h2>
2256 <p>{{ story.teaser }}</p>
2257 {% endfor %}
2258{% endblock %}
2259</code></pre>
2260<p>And the output would be:</p>
2261<pre><code class="lang-html"><h1>Fishing experiences</h1>
2262<h2><a href="/story/2">In my own town</a></h2>
2263<p>My journey from noob to fishing expert</p>
2264<h2><a href="/story/3">Meristics</a></h2>
2265<p>Introduction to Meristics basics</p>
2266</code></pre>
2267<h4 id="variables">Variables</h4>
2268<pre><code class="lang-html">{{ foo.bar }}
2269</code></pre>
2270<p>The application passes variables to the templates. Variables may have attributes or elements on them you can access as well. What a variable looks like heavily depends on the application providing it.</p>
2271<p>This is the variable lookup order behind the scenes:</p>
2272<p>foo.bar</p>
2273<ul>
2274<li>check if there is an attribute called bar on foo.</li>
2275<li>if there is not, check if there is an item 'bar' in foo.</li>
2276<li>if there is not, return an undefined object.</li>
2277</ul>
2278<p>foo['bar']</p>
2279<ul>
2280<li>check if there is an item 'bar' in foo.</li>
2281<li>if there is not, check if there is an attribute called bar on foo.</li>
2282<li>if there is not, return an undefined object.</li>
2283</ul>
2284<p>Twig does a slightly different approach:</p>
2285<ul>
2286<li>check if foo is an array and bar a valid element;</li>
2287<li>if not, and if foo is an object, check that bar is a valid property;</li>
2288<li>if not, and if foo is an object, check that bar is a valid method (even if bar is the constructor - use __construct()instead);</li>
2289<li>if not, and if foo is an object, check that getBar is a valid method;</li>
2290<li>if not, and if foo is an object, check that isBar is a valid method;</li>
2291<li>if not, return a null value.</li>
2292</ul>
2293<p>foo['bar'] on the other hand only works with PHP arrays:</p>
2294<ul>
2295<li>check if foo is an array and bar a valid element;</li>
2296<li>if not, return a null value.</li>
2297</ul>
2298<p>It's important to know that the curly braces are not part of the variable, but of the print statement. If you access variables inside tags, don't put the braces around. If a value is undefined or null, nothing is displayed. The same behavior occurs when referencing undefined or null objects. You can also set variables inside the block scope. Twig flavored syntax adds extra functionalities like <a href="http://twig.sensiolabs.org/doc/templates.html#global-variables">global variables</a> to help the developer.</p>
2299<h4 id="filters">Filters</h4>
2300<p>You can modify variables for display by using filters.</p>
2301<p>Filters look like this: <code>{{ name | lower }}</code> . This displays the value of the <code>{{ name }}</code> variable after being filtered through the lower filter, which converts text to lowercase. Use a pipe <code>(|)</code> to apply a filter.</p>
2302<p>Filters can be “chained.†The output of one filter is applied to the next. <code>{{ text | escape | linebreaks }}</code> is a common idiom for escaping text contents, then converting line breaks to <code><p></code> tags.</p>
2303<p>Some filters take arguments. A filter argument looks like this: <code>{{ bio | truncatewords:30 }}</code>. This will display the first 30 words of the bio variable. Filter arguments that contain spaces must be quoted; for example, to join a list with commas and spaced you’d use <code>{{ list | join:", " }}</code>.</p>
2304<p>All of the flavored syntaxes have a set of base filters like: capitalize, escape (sometimes shortened to just e), join, last, lenght, lower, random, reverse, slice, sort and float.</p>
2305<p>But some of them extend their base with:</p>
2306<ul>
2307<li>Twig adds <a href="http://twig.sensiolabs.org/doc/filters/date_modify.html"><code>date_modify</code></a>, <a href="http://twig.sensiolabs.org/doc/filters/json_encode.html"><code>json_encode</code></a>, <a href="http://twig.sensiolabs.org/doc/filters/nl2br.html"><code>nl2br</code></a></li>
2308<li>Liquid adds <a href="https://github.com/Shopify/liquid/wiki/Liquid-for-Designers#standard-filters"><code>truncatewords</code></a></li>
2309</ul>
2310<p>You can always add your own custom filters.</p>
2311<h3 id="conditionals-tags">Conditionals / Tags</h3>
2312<p>Tags look like this: <code>{% tag %}</code>. Tags are more complex than variables: Some create text in the output, some control flow by performing loops or logic, and some load external information into the template to be used by later variables.</p>
2313<p>Some tags require beginning and ending tags (i.e. <code>{% tag %} ... tag contents ... {% endtag %}</code>). The most common include: <code>if</code>, <code>for</code>, <code>extend</code>, <code>include</code>, <code>macros</code> and <code>comments</code>.</p>
2314<h4 id="if">If</h4>
2315<p><code>if</code> tests a condition and lets you selectively display content. It behaves exactly as javascript's <code>if</code> behaves.</p>
2316<pre><code class="lang-html">{% if fishes %}
2317 We have some {{fishes}}
2318{% endif %}
2319</code></pre>
2320<h4 id="for">For</h4>
2321<p>for iterates over arrays and dictionaries.<br></p>
2322<pre><code class="lang-html">{% for item in items %}
2323 {{ item.title }}
2324{% endfor %}
2325</code></pre>
2326<h4 id="macros">Macros</h4>
2327<p>Macros are comparable with functions in regular programming languages. They are useful to reuse often used HTML fragments to not repeat yourself.</p>
2328<pre><code class="lang-html">{% macro input(name, value, type) %}
2329 <input type="{{ type | default("text") }}" name="{{ name }}" value="{{ value | escape }}"/>
2330{% endmacro %}
2331</code></pre>
2332<p>And then they could be used like:</p>
2333<pre><code class="lang-html"><dl>
2334 <dt>Fish name</dt>
2335 <dd>{{ input_field(fish_name) }}</dd>
2336 <dt>Scientific name</dt>
2337 <dd>{{ input_field("scientific_name") }}</dd>
2338</dl>
2339</code></pre>
2340<p>One special note about the <code>{% raw %}</code> tag. If you are using a server-side template, to not parse that part of the code as a template.</p>
2341<pre><code class="lang-html">{% raw %}
2342 {% if %} this will {{ not be processed }} {% endif %}
2343{% endraw %}
2344</code></pre>
2345<h4 id="comments">Comments</h4>
2346<p>You can write comments using . Comments are completely stripped out when rendering. Comments are nothing more than a Tag.</p>
2347<pre><code class="lang-html">{# disabled type of catched fished because of Marine Conservation Institute
2348 {% for fish in fishes %}
2349 ...
2350 {% endfor %}
2351#}
2352</code></pre>
2353<h3 id="bonus-from-specific-variations-">Bonus from specific variations:</h3>
2354<ul>
2355<li>Nunjucks adds <a href="http://jlongster.github.io/nunjucks/templating.html#asynceach"><code>asyncEach</code></a> and <a href="http://jlongster.github.io/nunjucks/templating.html#asyncall"><code>asyncAll</code></a> for working with asynchronous javascript</li>
2356<li>Liquid adds <a href="https://github.com/Shopify/liquid/wiki/Liquid-for-Designers#if--else">unless</a> for negation of if statements, and <a href="https://github.com/Shopify/liquid/wiki/Liquid-for
2357Designers#cycle">cycle</a> to alternate between different tasks</li>
2358</ul>
2359<h3 id="template-inheritance">Template inheritance</h3>
2360<p>Template inheritance is a way to make it easy to reuse templates. When writing a template, you can define "blocks" that child templates can override
2361You start by defining a ‘base’ template:</p>
2362<pre><code class="lang-html"><!DOCTYPE html>
2363<html>
2364 <head>
2365 {% block head %}
2366 <link rel="stylesheet" href="style.css" />
2367 <title>{% block title %}{% endblock %}</title>
2368 {% endblock %}
2369 </head>
2370 <body>
2371 <div id="content">{% block content %}{% endblock %}</div>
2372 </body>
2373</html>
2374</code></pre>
2375<p>And then you extend the base layout, by filling the blocks with content:</p>
2376<pre><code class="lang-html">{% extends "base.html" %}
2377{% block title %}Index{% endblock %}
2378{% block head %}
2379{% endblock %}
2380{% block content %}
2381 <h1>Index</h1>
2382 <p class="important">
2383 Welcome to Fishing experiences.
2384 </p>
2385{% endblock %}
2386</code></pre>
2387<h2 id="to-wrap-up">To wrap up</h2>
2388<p>With variables and tags you can simply cycle through any content. Filters let you customize the output given from the data source. Macros help you don’t repeat yourself and with templating inheritance you organize your templates in a structured way.</p>
2389<p>If you want to know more you can check this references:</p>
2390<ul>
2391<li><a href="http://en.wikipedia.org/wiki/Template_engine_(web)">http://en.wikipedia.org/wiki/Template_engine_(web)</a></li>
2392<li><a href="http://twig.sensiolabs.org/doc/templates.html">http://twig.sensiolabs.org/doc/templates.html</a></li>
2393<li><a href="http://jlongster.github.io/nunjucks/templating.html">http://jlongster.github.io/nunjucks/templating.html</a></li>
2394<li><a href="https://docs.djangoproject.com/en/1.6/topics/templates/">https://docs.djangoproject.com/en/1.6/topics/templates/</a></li>
2395<li><p><a href="https://github.com/Shopify/liquid/wiki/Liquid-for-Designers">https://github.com/Shopify/liquid/wiki/Liquid-for-Designers</a></p>
2396<p>Some alternatives:</p>
2397</li>
2398<li><a href="https://github.com/speedmax/h2o-php">H20</a></li>
2399<li><a href="http://jinja.pocoo.org/">Jinja</a></li>
2400<li><a href="http://paularmstrong.github.io/swig">Swig</a></li>
2401</ul>
2402]]></content:encoded>
2403 </item>
2404 </channel>
2405 </rss>