<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>Ham Vocke</title>
		<description>Hermann Vocke writing about software development, mostly</description>		
		<link>https://www.hamvocke.com</link>
		<atom:link href="https://www.hamvocke.com/feed.xml" rel="self" type="application/rss+xml" />
		
			<item>
				<title>Book Review: “Tidy First?”</title>
				        
				<pubDate>Tue, 12 Dec 2023 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;Hardly any author shaped the way I think about software development more than Kent Beck. It took me a while to put the ideas in &lt;a href=&quot;https://www.goodreads.com/book/show/387190.Test_Driven_Development&quot;&gt;“Test-Driven Development: By Example”&lt;/a&gt; into proper practice, and once I did it changed the way I wrote code forever. &lt;a href=&quot;https://www.goodreads.com/book/show/67833.Extreme_Programming_Explained&quot;&gt;Extreme Programming&lt;/a&gt; (XP) and its focus on embracing inevitable change, keeping options open, staying flexible, pair programming and automated testing remains my favorite way to build software in an effective and sustainable way.&lt;/p&gt;

&lt;p&gt;Kent Beck publishes ideas about software design on his &lt;a href=&quot;https://tidyfirst.substack.com&quot;&gt;“Tidy First?” Newsletter&lt;/a&gt;. This newsletter is the source for his book &lt;em&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/171691901-tidy-first&quot;&gt;“Tidy First?: A Personal Exercise in Empirical Software Design”&lt;/a&gt;&lt;/em&gt;. 
I only recently stumbled across “Tidy First?” and finished it last week. This is my review.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/tidy-first.jpg&quot; alt=&quot;&amp;quot;Tidy First?&amp;quot; book cover&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;whats-tidy-first-all-about&quot;&gt;What’s “Tidy First?” all about?&lt;/h2&gt;

&lt;p&gt;Kent Beck introduces the concept of &lt;em&gt;tidyings&lt;/em&gt;, tiny changes to the structure (not the behavior) of your code to make your code more manageable, readable, and flexible, one small change at a time.&lt;/p&gt;

&lt;p&gt;Beck starts by explaining a number of distinct tidyings you can apply to your code every day. He discusses how tidyings, small &lt;em&gt;structural&lt;/em&gt; changes, can make it easier to implement your next &lt;em&gt;behavior&lt;/em&gt; change. And he explains how to avoid falling into the trap of tidying for the sake of tidying, keeping a focus on what’s important to your users: a change in your code’s behavior, not its structure.&lt;/p&gt;

&lt;p&gt;The book comes in three parts.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;The “What”&lt;/strong&gt;: An introduction to the idea of &lt;em&gt;tidyings&lt;/em&gt;, small structural code changes to support your next behavior code change&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The “When”&lt;/strong&gt;: An analysis &lt;em&gt;when&lt;/em&gt; its best to apply tidyings as part of your workflow: before, during, or after a behavioral code change&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The “Why”&lt;/strong&gt;: An explanation how tidyings can lead to looser coupling, increased cohesion, and keep more options open for longer so that you can deal with change better&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first part is quick and fun. It explains how small changes like extracting code into helper functions, using guard clauses, or explanatory variables, can help make your code more readable. For the seasoned developer this might sound familiar. For developers new to the trade this will be practical and invaluable and give them a clear set of ideas to improve the code they encounter over their career. The first part reads like a modern, less dogmatic take on &lt;a href=&quot;https://www.goodreads.com/book/show/3735293-clean-code&quot;&gt;Robert Martin’s &lt;em&gt;“Clean Code”&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The second part is where things get more spicy. Staying true to &lt;abbr title=&quot;Extreme Programming&quot;&gt;XP&lt;/abbr&gt; principles, Beck highlights how tidying is about solving an immediate need, not thinking too far into the future. Tidying can be fun and make you feel like you’re making progress, but the real thing you’re after is changing the &lt;em&gt;behavior&lt;/em&gt; of your code, not its &lt;em&gt;structure&lt;/em&gt;. Or, to use Kent Beck’s words:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Tidyings are the Pringles of software design&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One tidying often leads to another, and then another. You have to know when to stop.&lt;/p&gt;

&lt;p&gt;Beck goes on to analyze whether its smarter to tidy &lt;em&gt;before&lt;/em&gt; , &lt;em&gt;while&lt;/em&gt; or &lt;em&gt;after&lt;/em&gt; you change the behavior of your code. This central question explains why the book is called &lt;em&gt;“Tidy First?”&lt;/em&gt;. The answer, as so often, can be boiled down to an &lt;em&gt;“it depends”&lt;/em&gt; - and Beck’s analysis is inspiring, especially for people who have a tendency to fall into the trap of cleaning up non-stop, or – even worse – not at all.&lt;/p&gt;

&lt;p&gt;The third and final part, the &lt;em&gt;“why”&lt;/em&gt;, was my favorite. It’s full of challenging ideas that connect the simple concept of “tidyings” to much larger, more systemic effects. Beck explains the concepts of &lt;em&gt;optionality&lt;/em&gt;, the time value of money, coupling and cohesion. This analysis ties the seemingly innocent idea of cleaning up messy code to the fundamental idea that being able to deal with uncertainty and change is valuable, in a monetary sense. Systems that are easy to change are worth more. Things that are easy to reverse are preferable to things that aren’t. A dollar today is better than a dollar tomorrow. Earning more money, sooner, with greater likelihood is good. Spending less money, later, with less likelihood is good.&lt;/p&gt;

&lt;h2 id=&quot;my-takeaway&quot;&gt;My Takeaway&lt;/h2&gt;
&lt;p&gt;Kent Beck’s “Tidy First?” is a fun read full of insightful advice. If you’ve developed software for a while it will start out seeming obvious, maybe even too trivial, by explaining simple “tidyings”. Don’t skip those, let them be a reminder of simple changes you can do to make your code easier to work with. If you have never heard of the tidyings Beck explains in the first part, you’re getting valuable advice for your entire career as a software developer. The last few years I hesitated recommending Robert Martin’s “Clean Code” to newer developers as I found it too opinionated, too dogmatic, and too dusty from today’s perspective. “Tidy First?” will be my go-to recommendation moving forward, not just due to the list of tidyings it explains but due to the insightful analysis around the “when” and “why”.&lt;/p&gt;

&lt;p&gt;The “when” and “why” parts are where “Tidy First?” goes way beyond a pattern book and starts hitting heavier. Part 2, the “when”, helps appreciate when you’ve tidied enough and keep an eye on the actual goal, and it explains how pushing tidyings too far into the future can backfire. Both of these are traps I’ve found myself and others fall in over and over again. The grand finale, Beck’s explanation of optionality, the time value of money, coupling and cohesion and how all of these work together to build valuable software are fascinating. These ideas aren’t completely new to me as they’re deeply rooted in XP and have always been key to the goal of &lt;em&gt;embracing change&lt;/em&gt;. Reading them this clearly helped me better connect the dots and gave me new ways to think about software design.&lt;/p&gt;

&lt;p&gt;Go ahead and read it if you haven’t. It’s a short, enjoyable read full of great ideas. It’ll be worth it!&lt;/p&gt;

</description>
				<link>https://www.hamvocke.com/blog/tidy-first-review/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/tidy-first-review/</guid>
				
			</item>
		
			<item>
				<title>Path to Production Mapping</title>
				        
				<pubDate>Wed, 08 Mar 2023 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;Wanna hear something reassuring? Every software development team has problems getting their shit into production. There, I said it. Now take a big sigh of relief, feel better about the absolute mess your team is in, and close the browser tab. &lt;strong&gt;Or&lt;/strong&gt; read on and learn about a tool that can help you tackle these problems.&lt;/p&gt;

&lt;p&gt;When it comes to getting your software from your grimy old Macbook Pro into the sweaty metaphorical hands of your users, one thing is a given: there’s &lt;em&gt;always&lt;/em&gt; something to improve. No matter where you are on your Continuous Delivery journey.&lt;/p&gt;

&lt;p&gt;Sure, some teams are better off than others on the &lt;em&gt;“our path to production sucks”&lt;/em&gt; scale. While some are more on the &lt;em&gt;“well, this is mildly annoying”&lt;/em&gt; side of things, others might find themselves on the &lt;em&gt;“holy shit, we’ll go out of business if we don’t fix this”&lt;/em&gt; end. Some teams are struggling to deploy more than once a year, while others might be able to do so 10 times a day but they are annoyed by their stupidly slow integration test suite or their constantly flaky end-to-end tests that nobody really trusts anyways.&lt;/p&gt;

&lt;p&gt;When I was doing consulting at Thoughtworks, I often worked with teams who were unhappy about their development cadence. They didn’t like how often they were able to ship new stuff to real users. Continuous Delivery was a hot topic back then (still is, honestly) and companies asked us to help them get started or get better with it.&lt;/p&gt;

&lt;p&gt;One tool we used a lot back then, a tool I keep using today even after my consulting days are over is &lt;strong&gt;“Path to Production Mapping”&lt;/strong&gt;. This tool might sound like a secret weapon but it really is something everyone can do. Thoughtworks &lt;a href=&quot;https://www.thoughtworks.com/radar/techniques/path-to-production-mapping&quot;&gt;call it out on their Technology Radar&lt;/a&gt;, but unfortunately don’t go into detail what this is all about. I’m here to fix that. I’ll explain how I usually do “Path to Production Mapping” with teams I work with, and how you can do the same.&lt;/p&gt;

&lt;h2 id=&quot;path-to-production-mapping-in-a-nutshell&quot;&gt;“Path to Production Mapping” in a Nutshell&lt;/h2&gt;

&lt;p&gt;Okay, here’s the summary for those of you with the attention span of a squirrel:&lt;/p&gt;

&lt;p&gt;When you run a “Path to Production” exercise, you lock a software development team into a room and don’t let them out before they have created a map that answers the following question:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What does it take us &lt;strong&gt;today&lt;/strong&gt; to get a change from a developer’s computer into the hands of a real user in production?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You start with a blank canvas and something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/img/uploads/path-to-prod-canvas.jpg&quot;&gt;&lt;img src=&quot;/assets/img/uploads/path-to-prod-canvas.jpg&quot; alt=&quot;Path to Production: Empty state&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;…and ask people to fill in the big &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;???&lt;/code&gt; space in the middle. Easy peasy.&lt;/p&gt;

&lt;p&gt;You’ll get heated discussions, maybe some yelling, inevitable bike shedding, and finally agreement. You write down the sequence of all the manual and automated steps, the people involved, the tools used, and whatever else is important to get your stuff out to production.&lt;/p&gt;

&lt;p&gt;After a while you’ll have something like this (click image to see a larger version):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/img/uploads/path-to-prod-example.jpg&quot;&gt;&lt;img src=&quot;/assets/img/uploads/path-to-prod-example.jpg&quot; alt=&quot;Path to Production Map: A full example&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’re there you can pat yourselves on the backs because you finally collectively understand what it takes to ship a change to your users. Now it’s time to crank up the heat and find ways to improve.&lt;/p&gt;

&lt;p&gt;Sounds cool? Cool. Read on.&lt;/p&gt;

&lt;h2 id=&quot;get-clarity-identify-pain-points--improve&quot;&gt;Get Clarity, Identify Pain Points &amp;amp; Improve&lt;/h2&gt;

&lt;p&gt;So what? This is just a bunch of sticky notes. What’s the big deal?&lt;/p&gt;

&lt;p&gt;You’re a software team. The only software that matters is the one your users can use. Getting your software into the hands of your users efficiently and frequently is important. &lt;a href=&quot;https://www.continuousdelivery.com/&quot;&gt;Continuous Delivery&lt;/a&gt; (&lt;abbr title=&quot;Continuous Delivery&quot;&gt;CD&lt;/abbr&gt;, or “CI/CD” as everyone seems to call it by now) has emerged as a practice to help you pull that off. Doing CD effectively is a game changer. I’m not making this shit up, &lt;a href=&quot;https://www.devops-research.com/research.html&quot;&gt;we’ve got great research to back this up&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Chances are that you &lt;a href=&quot;https://stackoverflow.blog/2021/12/20/fulfilling-the-promise-of-ci-cd/&quot;&gt;claim to “do CI/CD” but you’re lying to yourself&lt;/a&gt; because all you’ve got is an automated build running on every pull request someone puts out there (&lt;a href=&quot;https://martinfowler.com/bliki/ContinuousIntegrationCertification.html&quot;&gt;that doesn’t even qualify as “CI”&lt;/a&gt;, my friend!). Or maybe you’re stuck in the dark ages and haven’t taken &lt;strong&gt;any&lt;/strong&gt; steps towards automating build, test, deployment to release software to production reliably and frequently. And maybe, just maybe, you’re actually doing CD quite well already, but somehow your deployment pipeline has grown so large by now that you don’t really quite know all the things that happen. Or you secretly loathe the fact that you’ve got to retrigger your pipeline about twice per day because these stupid integration tests are constantly breaking for no good reason. Look, we all struggle with these things, we’re all on a different part of this journey, and there’s &lt;em&gt;always&lt;/em&gt; something to improve about your path to production. And that’s why you want to explicitly map it out with a “Path to Production Mapping” exercise.&lt;/p&gt;

&lt;p&gt;Running this exercise can help you to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;get clarity and a shared understanding about your current path to production (you’ll be surprised how different people &lt;em&gt;will&lt;/em&gt; have different understanding of what’s actually going on)&lt;/li&gt;
  &lt;li&gt;identify bottlenecks, brittle steps, unnecessary work and things that are completely unknown to the team today&lt;/li&gt;
  &lt;li&gt;come up with plans to improve, automate, eliminate, parallelize steps on your path to production&lt;/li&gt;
  &lt;li&gt;figure out that no single person actually understands the whole process&lt;/li&gt;
&lt;/ul&gt;

&lt;aside&gt;

&lt;h3&gt;Quick Detour: On &quot;Value Stream Mapping&quot;&lt;/h3&gt;

&lt;p&gt;This whole &quot;Path to Production Mapping&quot; thing is not new, really. It's mostly a simplified version of a technique called &lt;a href=&quot;https://en.wikipedia.org/wiki/Value-stream_mapping&quot;&gt;Value Stream Mapping&lt;/a&gt; that folks who love to say &quot;Lean&quot; and waffle about Toyota's production system have been using for ages.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Value Stream Maps&lt;/em&gt; sketch out all the steps in a business process that add value to your customer (or some other person who's interested in the outcome) and show how long each step takes. People use value stream maps to show what a process currently looks like, how long it takes, where bottlenecks are, where things go to waste. They often create another value stream map of the desired future process to show where the current process can be improved.&lt;/p&gt;

&lt;p&gt;The &quot;value stream&quot; in a &lt;em&gt;path to production&lt;/em&gt; exercise is the journey of a code change from a developer's machine into production. Often this value stream is built as an automated deployment pipeline. But quite often there are also manual steps involved that are worth tracking. And sometimes, if teams haven't even started working towards Continuous Delivery, there might not even be an automated deployment pipeline yet.&lt;/p&gt;

&lt;p&gt;Mary and Tom Poppendieck have written some more about Value Stream Mapping in the context of software development in &lt;a href=&quot;https://www.oreilly.com/library/view/lean-software-development/0321150783/&quot;&gt;&quot;Lean Software Development: An Agile Toolkit&quot;&lt;/a&gt;.&lt;/p&gt;

&lt;/aside&gt;

&lt;h2 id=&quot;how-to-create-your-path-to-production-map&quot;&gt;How to Create Your Path to Production Map&lt;/h2&gt;

&lt;p&gt;Maybe you’re sold on the idea that that mapping your path to production could help you make sense of the mess you’re in. Here are detailed instructions for you if you’re eager to run this exercise with a team:&lt;/p&gt;

&lt;p&gt;To create your own Path to Production Map, you set up a workshop where the right people come together to discuss and write down the individual steps of your path to production. This sounds simple, but it will be &lt;strong&gt;intense&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You should plan to take between &lt;strong&gt;2 to 3 hours&lt;/strong&gt; for this meeting. If you need more time, schedule a follow up meeting, because people’s brains will be fried after this.&lt;/p&gt;

&lt;h3 id=&quot;invite-the-right-people&quot;&gt;Invite the right people&lt;/h3&gt;

&lt;p&gt;Aim for a diverse set of opinions in this workshop. You want to have people from the different disciplines involved in getting a change out of the door. You want people with a lot of experience and people who are new to the team. Don’t listen to your rock star developer when he says &lt;em&gt;“we don’t need this meeting, it’s all super simple and I can simply sketch this out in 10 minutes”&lt;/em&gt;. That’s bullshit, and you’ll prove it.&lt;/p&gt;

&lt;p&gt;Think about inviting the following people. You don’t need to invite literally everyone, but you should have a good mix of roles and experience:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;some of the people who build the software. software developers, data engineers, designers&lt;/li&gt;
  &lt;li&gt;some of the people who build and maintain the infrastructure your software is built, tested, and run on: software developers, operations folks, site reliability engineers, platform engineers, “DevOps engineers” &lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; , you know who I’m talking about&lt;/li&gt;
  &lt;li&gt;some of the people who are involved in testing: quality engineers, software developers, testers, product managers&lt;/li&gt;
  &lt;li&gt;some of the people who decide what gets built and shipped, and when: product managers, project managers, maybe even someone from marketing&lt;/li&gt;
  &lt;li&gt;maybe even some of the people who take a higher level perspective of what the team is doing: team leads, engineering managers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don’t run this workshop with 20 people unless you want mayhem. 5-9 people seems to be the sweet spot allowing you to have a healthy discussion and avoiding endless debate and bike shedding.&lt;/p&gt;

&lt;h3 id=&quot;prepare-a-canvas&quot;&gt;Prepare a Canvas&lt;/h3&gt;

&lt;p&gt;I don’t care whether you do this in person or in a virtual setting. You either take a huge physical space (a whiteboard could be a good start, spreading a huge roll of paper out on a conference table is a good alternative), or you use a &lt;strong&gt;collaborative&lt;/strong&gt; diagramming tool (I’ve used &lt;a href=&quot;https://miro.com&quot;&gt;Miro&lt;/a&gt; before, but others will work fine, too).&lt;/p&gt;

&lt;p&gt;Bring lots of sticky notes in at least 4 different colors. Bring markers for every participant. If you do this virtually, you don’t need this, of course.&lt;/p&gt;

&lt;p&gt;Set up the canvas by showing what each sticky notes’ color is used for (you can swap the colors if you feel frisky)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Yellow: &lt;strong&gt;Steps&lt;/strong&gt; (automated and manual)&lt;/li&gt;
  &lt;li&gt;Blue: &lt;strong&gt;People&lt;/strong&gt; involved&lt;/li&gt;
  &lt;li&gt;Green: &lt;strong&gt;Tools&lt;/strong&gt; involved&lt;/li&gt;
  &lt;li&gt;Red: &lt;strong&gt;Time&lt;/strong&gt; for each step, and time &lt;em&gt;between&lt;/em&gt; steps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; add more types to the mix if you think it’s worth capturing more: It might be useful to capture &lt;em&gt;comments &amp;amp; questions&lt;/em&gt; that come up as part of your discussion, or &lt;em&gt;outputs&lt;/em&gt; of certain steps, or &lt;em&gt;environments&lt;/em&gt; you run your stuff on. This is your tool, feel free to add what you and your crew thinks is helpful to understand your path to production better.&lt;/p&gt;

&lt;h3 id=&quot;go-wild&quot;&gt;Go Wild!&lt;/h3&gt;
&lt;p&gt;Once you’ve got everyone in the room and your canvas prepared, explain what you’re doing: You want to sketch out &lt;strong&gt;all the steps&lt;/strong&gt; it takes right ow to get code from a developer’s machine into the hands of your users. You want to capture &lt;strong&gt;who is involved&lt;/strong&gt; in these steps and &lt;strong&gt;which tools are used&lt;/strong&gt; during each step. And finally you want to write down how long each of these steps usually takes, and how much idle time is spent waiting for this step to happen.&lt;/p&gt;

&lt;p&gt;Usually there’s going to be some chaos and hesitation in the beginning. People are shy to start, argue about the right level of detail, get lost in meta-discussions. It’s okay to let these happen for a bit but after a few minutes you should encourage them to &lt;em&gt;just fucking do it&lt;/em&gt; and write something down to get the ball rolling. This is not an exam, there’s nobody grading what he team comes up with. If you’ve set this workshop for 2 hours, tell them they should be done with the “mapping” part after 1 hour. This will give you some room to extend their time, but it’ll give the team a sense of urgency.&lt;/p&gt;

&lt;p&gt;During the mapping exercise, expect that the team will come up with some obvious steps rather quickly, while others are surprisingly controversial and come with a lot of discussion, questions, and back and forth. This is a great time for newer team members to ask questions, for people in non-technical roles to learn more about the technology used, and for the technical folks to better understand what business decisions are driving your development process.&lt;/p&gt;

&lt;p&gt;Be mindful about rabbit holes and derailing conversations. Teams often get lost in details that don’t quite matter in the grand scheme of things. If you spot these discussions, make sure to help the team get out of it by breaking it up, putting down a sticky note with the open question so that you can revisit later, and move on.&lt;/p&gt;

&lt;h3 id=&quot;analyse-the-map&quot;&gt;Analyse the Map&lt;/h3&gt;
&lt;p&gt;Once the path to production map is done, you should take a deep breath and a short break. The next step is to analyze the map the team has created. You could either do this as part of the one session you planned or schedule a follow up. Be mindful of the energy levels in the room, creating the map can be exhausting and people might be fried by now.&lt;/p&gt;

&lt;p&gt;When it comes to analyzing the path to production map, to take a look at all of the steps you outlined and the time each step takes. Discuss where you can find room for improvement. Highlight the pain points and write down first ideas that come up to tackle these problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some things to think about:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Which steps take a lot of time today? could you cut that time down by using better automation or changing your approach completely?&lt;/li&gt;
  &lt;li&gt;Where do you have handovers that lead to a lot of waiting time?&lt;/li&gt;
  &lt;li&gt;Are there manual steps you could &lt;strong&gt;automate&lt;/strong&gt;?&lt;/li&gt;
  &lt;li&gt;Are there steps that don’t provide a lot of value that you could &lt;strong&gt;eliminate&lt;/strong&gt; or cut back on? Be rigorous. Over time a lot of cruft creeps as it’s always easier to add something than to remove something. Often you learn over time that something that sounded like a good idea a year ago isn’t actually pulling its own weight.&lt;/li&gt;
  &lt;li&gt;Are there steps you could &lt;strong&gt;parallelize&lt;/strong&gt; instead of running them in sequence?&lt;/li&gt;
  &lt;li&gt;Are there steps you could take off the “hot path”? Could you get your changes out to production without waiting for the result of certain steps? Feature flags can help to &lt;a href=&quot;https://www.thoughtworks.com/en-us/radar/techniques/decoupling-deployment-from-release&quot;&gt;decouple deployments from releases&lt;/a&gt;, which can be useful to buy you much more safety and flexibility in these regards.&lt;/li&gt;
  &lt;li&gt;Are there things to streamline and &lt;strong&gt;simplify&lt;/strong&gt;? Do you, for example, have three different deployment methods for your various environments that you could unify?&lt;/li&gt;
  &lt;li&gt;Are the steps in the right order and optimize for &lt;strong&gt;fast feedback&lt;/strong&gt;? Watch out for long running tasks that run earlier and push out quick verification steps to a later point in time and see if that’s worth fixing. Usually, you’d want your unit tests to run before your integration tests, for example, since they’ll give you valuable feedback much quicker.&lt;/li&gt;
  &lt;li&gt;Which steps are currently unreliable and could be made more resilient? Do you have certain deployments that often fail? A flaky test suite? Think about making these more reliable, replacing them with a different approach that &lt;em&gt;is&lt;/em&gt; more reliable, or getting rid of them altogether.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you discuss these things, write down the pain points and possible solutions. Let the conversation flow, there will probably be a lot of ideas, some good, some bad. Capture them all for now. Think about giving the team an opportunity to add more ideas even after the workshop’s done.&lt;/p&gt;

&lt;h3 id=&quot;follow-up&quot;&gt;Follow Up&lt;/h3&gt;
&lt;p&gt;After this exercise you will have a few things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A visual map showing how you get your software into the hands of your users &lt;em&gt;today&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;A shared understanding and agreement on your path to production&lt;/li&gt;
  &lt;li&gt;A lot of ideas where you could improve your current process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don’t let this go to waste. The Path to Production Map is great for onboarding new team members. It’s a great living document you could change as your path to production changes. Think about making this visible to your team in an easy way.&lt;/p&gt;

&lt;p&gt;More importantly, the list of improvements is something very actionable that could help you turn your current process from something that everyone resents into something that allows you to experiment, innovate, and ship stuff reliably and frequently. Make sure to prioritize the work accordingly.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;If you and your team (or a team you know and care about) are frustrated with how you ship your software to production, it’s tempting to quickly jump to conclusions, flail around aimlessly and try to improve &lt;em&gt;something, anything&lt;/em&gt; by writing yet another script or including yet another tool. Mapping out your Path to Production can be a smarter approach that allows you to take a step back, see the bigger picture first, create shared understanding and have structured discussions about what’s painful at the moment and why everything sucks so much.&lt;/p&gt;

&lt;p&gt;Shipping software to production is more of a social problem than a lot of us developers are ready to admit. Treat it accordingly. Gather everyone in a room, map out your path to production, analyze where your problems truly are and discuss the big ideas to improve your situation together.&lt;/p&gt;

&lt;p&gt;I hope this exercise helps you as much as it has helped me in the past. If you’ve got questions, doubts, feedback, or comments, feel free to send them my way. All my contact data is crammed into the footer of this page.&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/lean-software-development/0321150783/&quot;&gt;Lean Software Development: An Agile Toolkit&lt;/a&gt; by Mary Poppendieck and Tom Poppendieck for more details about value stream mapping (see Chapter 1).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://learning.oreilly.com/library/view/continuous-delivery-reliable/9780321670250/&quot;&gt;Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation&lt;/a&gt; by David Farley and Jez Humble for a lot of great advice around setting up a deployment pipeline for your automated path to production and for a fundamental introduction to Continuous Delivery&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;get ready for people with their pitchforks. Don’t say you haven’t been warned! &lt;a href=&quot;https://dzone.com/articles/devops-is-not-a-title-it-is-a-philosophy&quot;&gt;DevOps is not a title&lt;/a&gt;. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/path-to-production/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/path-to-production/</guid>
				
			</item>
		
			<item>
				<title>Browser Bookmarks on the Command Line</title>
				        
				<pubDate>Mon, 31 Oct 2022 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;I wrote a small tool. It’s merely more than a script, actually. This tool has been immensely helpful for me over the past few weeks and so I’m sharing it more broadly.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks&lt;/code&gt;&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; is a command line tool that allows you to search through a list of bookmark and open them in your default browser.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/lnks.jpg&quot; alt=&quot;a screenshot of lnks in action&quot; /&gt;
&lt;em&gt;Search and open your bookmarks from the command line&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can find the code and more instructions on &lt;a href=&quot;https://github.com/hamvocke/lnks&quot;&gt;my GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;p&gt;Here’s all you need to do to get started:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/junegunn/fzf#installation&quot;&gt;Install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fzf&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git clone&lt;/code&gt; &lt;a href=&quot;https://github.com/hamvocke/lnks&quot;&gt;the repository&lt;/a&gt; or download the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.sh&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.txt&lt;/code&gt; files yourself if that’s your thing&lt;/li&gt;
  &lt;li&gt;Edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bookmarks.txt&lt;/code&gt; file and put your bookmarks in there (see &lt;a href=&quot;#managing-bookmarks&quot;&gt;Managing Bookmarks&lt;/a&gt; for details)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Run the script from your command line.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./lnks.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Use the &lt;kbd&gt;↑&lt;/kbd&gt; / &lt;kbd&gt;↓&lt;/kbd&gt; arrows or &lt;kbd&gt;Ctrl&lt;/kbd&gt; + &lt;kbd&gt;P&lt;/kbd&gt; / &lt;kbd&gt;Ctrl&lt;/kbd&gt; + &lt;kbd&gt;N&lt;/kbd&gt; to navigate the list of visible bookmarks up and down.&lt;/p&gt;

&lt;p&gt;Hit &lt;kbd&gt;Enter&lt;/kbd&gt; to open a selected bookmark in your browser.&lt;/p&gt;

&lt;p&gt;Type some text to run a fuzzy search against all your bookmarks. Delete typed characters with &lt;kbd&gt;Backspace&lt;/kbd&gt;.&lt;/p&gt;

&lt;p&gt;Exit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks&lt;/code&gt; with &lt;kbd&gt;Esc&lt;/kbd&gt; or &lt;kbd&gt;Ctrl&lt;/kbd&gt; + &lt;kbd&gt;C&lt;/kbd&gt;.&lt;/p&gt;

&lt;h2 id=&quot;managing-bookmarks&quot;&gt;Managing Bookmarks&lt;/h2&gt;
&lt;p&gt;The script will read all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.txt&lt;/code&gt; files that are located in the same directory as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks.sh&lt;/code&gt; script itself to create your list of bookmarks. You can add all your bookmarks to a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bookmarks.txt&lt;/code&gt; file, or create multiple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.txt&lt;/code&gt; files, totally up to you.&lt;/p&gt;

&lt;p&gt;A bookmark text file needs to follow these conventions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;One bookmark per line&lt;/li&gt;
  &lt;li&gt;Each line has a searchable name and a URL&lt;/li&gt;
  &lt;li&gt;The URL is the last part of your line, separated from the searchable name with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;space&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;A bookmark file needs to have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.txt&lt;/code&gt; extension&lt;/li&gt;
  &lt;li&gt;You can have as many bookmark files next to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks.sh&lt;/code&gt; script as you want&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;demo&quot;&gt;Demo&lt;/h2&gt;
&lt;p&gt;Here’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks&lt;/code&gt; in action.&lt;/p&gt;

&lt;video src=&quot;/assets/video/lnks.webm&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; controls=&quot;&quot;&gt;&lt;/video&gt;

&lt;h2 id=&quot;create-an-alias-for-easier-access&quot;&gt;Create an Alias for Easier Access&lt;/h2&gt;
&lt;p&gt;Here’s a pro-tip: to make opening your bookmarks a little more convenient, add an alias to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.zshrc&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.profile&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lnks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'~/your/directory/lnks/lnks.sh'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This way you can open your bookmarks from anywhere simply by typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;or-bind-it-to-a-hotkey&quot;&gt;Or Bind it to a Hotkey&lt;/h2&gt;
&lt;p&gt;You could take this one step further by binding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks&lt;/code&gt; to a global keyboard shortcut. That way, your bookmarks will pop up by triggering a key-combo of your choice.&lt;/p&gt;

&lt;p&gt;How to can bind custom commands to certain keyboard shortcuts depends on your operating system (and desktop environment) of choice. On Mac, you’d have to dig into &lt;a href=&quot;https://support.apple.com/guide/automator/welcome/mac&quot;&gt;Automator&lt;/a&gt;. On Gnome on Linux, you can &lt;a href=&quot;https://help.gnome.org/users/gnome-help/stable/keyboard-shortcuts-set.html&quot;&gt;set up a custom keyboard shortcut&lt;/a&gt; in your keyboard settings. Other desktop environments will allow similar customization. In window managers like i3 or Sway, you can bind a custom command to a key combination in your config (&lt;a href=&quot;https://github.com/hamvocke/dotfiles/blob/f4938fb6a1e4275d06e01c2777ea85ca193d07bd/sway/.config/sway/config#L132-L133&quot;&gt;check out how I did this in my own Sway config&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;You get the idea. You tell your operating system launch your terminal application of choice and then execute the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks.sh&lt;/code&gt; script from the right directory whenever you trigger the right key combination. Depending on your terminal application the command to trigger will look slightly different, but it should be somewhat similar to one of these:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# gnome-terminal:&lt;/span&gt;
gnome-terminal &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; bash &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; ~/dev/lnks/lnks.sh
&lt;span class=&quot;c&quot;&gt;# -&amp;gt; replace this ^^^^ with your shell of choice if you're not a bash user&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# alacritty:&lt;/span&gt;
alacritty &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; bash &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; ~/dev/lnks/lnks.sh

&lt;span class=&quot;c&quot;&gt;# foot&lt;/span&gt;
foot bash &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; ~/dev/lnks/lnks.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is going to be much more fun if your terminal and shell startup times are fairly snappy.&lt;/p&gt;

&lt;h2 id=&quot;how-the-sausage-is-made&quot;&gt;How the Sausage is Made&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks&lt;/code&gt; uses &lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fzf&lt;/code&gt; - the incredibly practical command-line fuzzy finder&lt;/a&gt; to do all the heavy lifting of searching and displaying stuff in a neat UI. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks&lt;/code&gt; is merely orchestrating a few Unix tools, really.&lt;/p&gt;

&lt;p&gt;The script simply reads all adjacent &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.txt&lt;/code&gt; files and passes their content over to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fzf&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fzf&lt;/code&gt; then lists each bookmark on one line. As you select a line, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fzf&lt;/code&gt; shows the last segment of the line (the actual URL) in a &lt;em&gt;preview&lt;/em&gt; window at the top. The rest of a line will be used as the name of the bookmark, this is also what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fzf&lt;/code&gt; runs your search query against. Finally, I configured up a key binding in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fzf&lt;/code&gt; so that pressing the &lt;kbd&gt;Enter&lt;/kbd&gt; key opens the bookmark’s URL in your default browser.&lt;/p&gt;

&lt;h2 id=&quot;why-you-might-want-to-use-this&quot;&gt;Why You Might Want to Use This&lt;/h2&gt;
&lt;p&gt;As software developers, we often access a lot of bookmarks and important URLs throughout our day. Production systems, staging environments, bug trackers, observability tools, CI/CD pipelines, you know what I’m talking about.&lt;/p&gt;

&lt;p&gt;Of course you could manage these bookmarks within your browser like a normal person. But you didn’t click the link to this blog post because you’re looking for vanilla solutions to everyday problems, did you?&lt;/p&gt;

&lt;p&gt;Chances are that you’ve got a terminal open all day so navigating bookmarks from a terminal might feel like second nature. And if you use something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; (&lt;a href=&quot;/blog/a-quick-and-easy-guide-to-tmux&quot;&gt;check out my tmux guide&lt;/a&gt; if you don’t!) you can dedicate a small pane to keep &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks&lt;/code&gt; open at all times.&lt;/p&gt;

&lt;p&gt;The nice thing about keeping all your bookmarks in plain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.txt&lt;/code&gt; files is that you can share them easily with people you work with. Most likely they will need access to the same things as you do, so sharing these bookmarks is a great way to keep important bookmarks up to date and point people to the right places at all times. A good way to do this is to fork &lt;a href=&quot;https://github.com/hamvocke/lnks&quot;&gt;the GitHub repository&lt;/a&gt;, check in your own bookmark files, and share your fork with your team.&lt;/p&gt;

&lt;p&gt;I learned to love this kind of bookmark sharing when I worked with a software development team at &lt;a href=&quot;https://www.otto.de&quot;&gt;Otto&lt;/a&gt;, a German online retailer. We did a lot of pair programming and switched machines frequently. Someone on the team had built a small bookmarks website that looked pretty much just like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lnks&lt;/code&gt; and allowed you to search through important bookmarks for the team. As we were pairing, we could always rely on having quick and easy access to that bookmark website and therefore to all our test environments, logs, bug trackers, code repos, you name it.&lt;/p&gt;

&lt;p&gt;I’m getting a lot of mileage out of this small script. I hope you find it helpful, too.&lt;/p&gt;

&lt;h3 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h3&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;that’s “links” for people who want to save a keystroke – my contribution to the myth of German efficiency! &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/lnks-command-line-bookmarks/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/lnks-command-line-bookmarks/</guid>
				
			</item>
		
			<item>
				<title>Book Review: “Learning Test-Driven Development”</title>
				        
				<pubDate>Wed, 15 Dec 2021 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;Earlier this year I received an email from my friend and former coworker Saleem Siddiqui. Saleem must have thought that spare time was overrated since he told me that he was &lt;a href=&quot;https://www.oreilly.com/library/view/learning-test-driven-development/9781098106461/&quot;&gt;writing a book on Test-Driven Development&lt;/a&gt; and O’Reilly agreed to publish it. He asked if I wanted to be one of his technical reviewers and read through early versions of the book to make sure that it is logically sound, that code samples are correct and to chime in with other suggestions.&lt;/p&gt;

&lt;p&gt;I was thrilled.&lt;/p&gt;

&lt;p&gt;Saleem is a person who had a huge impact on who I am as a professional. We worked together on a ThoughtWorks project in Hamburg, building software for a smart home device and its cloud ecosystem. Pair-programming with Saleem was what made &lt;abbr title=&quot;Test-Driven Development&quot;&gt;TDD&lt;/abbr&gt; truly click for me. Saleem is a gifted teacher and an advocate for keeping software simple and maintainable by driving software design with automated tests. I was fortunate enough to have worked with Saleem in person. It’s amazing that he decided to take his passion and talent for teaching to a wider audience by writing this book.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/learning-test-driven-development/9781098106461/&quot;&gt;&lt;img src=&quot;/assets/img/uploads/learning-tdd-cover.jpg&quot; alt=&quot;Learning Test-Driven Development book cover&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Full disclosure:&lt;/strong&gt; This is my personal review of &lt;em&gt;Learning Test-Driven Development&lt;/em&gt;. I’m not paid for it, I don’t get any affiliate money, and nobody asked me to write this. I don’t have any financial stakes in this book. Yet, this is not an unbiased review. It couldn’t be, for the reasons I’ve outlined above. I hope this can still be a helpful review for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;learning-test-driven-development-in-a-nutshell&quot;&gt;&lt;em&gt;Learning Test-Driven Development&lt;/em&gt; in a nutshell&lt;/h2&gt;

&lt;p&gt;The summary is in the title, really. &lt;em&gt;Learning Test-Driven Development&lt;/em&gt; teaches software developers how to do Test-Driven Development (&lt;em&gt;TDD&lt;/em&gt;). Throughout the book, you’re building a small application that is able to calculate with and translate between different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Currencies&lt;/code&gt;. After a short setup, you will build this application in a true TDD way. You start with a failing test, get it to pass by writing code, and then clean up and refine. Rinse and repeat until the application is done. The book uses the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Money&lt;/code&gt; example Kent Beck used in his seminal &lt;em&gt;“Test-Driven Development by Example”&lt;/em&gt; and gives it a more modern spin. You can choose between three programming languages – JavaScript, Python and Go – and learn hands-on how to iteratively build a currency converter in either (or all) of these languages driven by tests. By the end of the book you will have a good understanding of what TDD feels like and how to apply it. You will use the “red-green-refactor” cycle ad nauseam (which is good) and experience how tests help you keep your code malleable and clutter-free.&lt;/p&gt;

&lt;h2 id=&quot;who-should-read-this-book&quot;&gt;Who should read this book?&lt;/h2&gt;

&lt;p&gt;This book is great for:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Developers who have never used TDD and want to learn it from scratch&lt;/li&gt;
  &lt;li&gt;Developers who have tried TDD in the past and discarded it because it didn’t click for them&lt;/li&gt;
  &lt;li&gt;Developers who want to level-up their automated testing skills without necessarily becoming TDD evangelists&lt;/li&gt;
  &lt;li&gt;Developers who are curious to dive into JavaScript, Python or Go (or all three of them) and see how they compare&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are just starting out in your programming career and learned one popular programming language already, I highly recommend working through this book. Testing is one of the most important skills to master as a software developer and pays compound interest. Make your life as a developer better by learning this crucial skill early on.&lt;/p&gt;

&lt;p&gt;If you are a seasoned programmer with doubts about TDD, this book might help you get a new perspective. Maybe you got fed up with TDD after working with someone who &lt;em&gt;just wouldn’t shut up&lt;/em&gt; about TDD. Or you might have been annoyed by an overbearing manager who demanded you hit 100% test coverage and did not understand that this was a silly goal. You might have tried TDD on a gnarly legacy codebase only to find out that everything is too tedious and taking you twice as long, and that unit tests are rarely helpful anyways. Take this book for a spin and follow the examples hands-on to see if it clicks for you.&lt;/p&gt;

&lt;p&gt;If you are an experienced TDD practitioner or someone who has written a fair amount of unit tests in the past and understands their benefits and shortcomings, this book will not teach you many new tricks. If, on the other hand, you consider training others to become more proficient with TDD and test automation, this book might serve as a nice workbook to use for this kind of training.&lt;/p&gt;

&lt;h2 id=&quot;whats-in-the-book&quot;&gt;What’s in the book?&lt;/h2&gt;

&lt;p&gt;The book is best used as a hands-on workbook. I recommend not just reading it but actually working through the examples on your own as you read the book. Open an editor, write those tests, see them fail, make them pass. You’ll only get a fraction out of the book if you’re merely reading it back to back. By writing code on your own, you’ll make sure to truly &lt;em&gt;experience&lt;/em&gt; the TDD cycle and the benefits of guiding your implementation by writing tests first.&lt;/p&gt;

&lt;h3 id=&quot;the-money-problem&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Money&lt;/code&gt; problem&lt;/h3&gt;

&lt;p&gt;The book revolves around a simple exercise: Build an application that allows you to calculate with and convert between different currencies. This program will be able to answer questions like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;What's 42 USD + 12 EUR in CHF?&lt;/code&gt;. It is a fairly well-known code kata (popularized by Kent Beck’s book on TDD) that stays fairly simple. You are not building a web application. You are not talking to a database. There is no &lt;del&gt;silly&lt;/del&gt; &lt;ins&gt;fancy&lt;/ins&gt; blockchain. It is a simple program doing simple calculations. This is a good thing because it allows you to keep focused on the essence of learning the TDD cycle. However, if you want to learn about advanced patterns of testing (how do I deal with caching? how do I simulate HTTP requests? how do I test code that talks to a database?), this book won’t help much (read on for some recommendations if this is your concern).&lt;/p&gt;

&lt;h3 id=&quot;python-or-go-or-javascript-or-all-of-them&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Python&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Go&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JavaScript&lt;/code&gt;? Or all of them?&lt;/h3&gt;

&lt;p&gt;The subtitle of this book promises that this is  &lt;em&gt;“A Polyglot Guide to Writing Uncluttered Code”&lt;/em&gt;. And it keeps that promise. The book uses three parallel language tracks to walk you through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Money&lt;/code&gt; example. You can choose between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JavaScript&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Python&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Go&lt;/code&gt; as the language to work with. You can also choose to work with two (or even all three) languages in parallel. Totally up to you.&lt;/p&gt;

&lt;p&gt;If you are mostly looking for a quick introduction (or a refresher) on TDD in a language you know, I recommend picking one language and working your way through the book. You should be done in a handful of hours and leave with a better understanding for TDD in you chosen language.&lt;/p&gt;

&lt;p&gt;If you are curious about learning either of these three languages, the simple nature of the code sample is a great way to learn basic syntax, build and test commands.&lt;/p&gt;

&lt;p&gt;If you are curious about statically vs. dynamically typed or compiled vs. interpreted languages and want to experience how writing code and tests feels with each of those, I recommend picking two or three languages when working your way through the book.&lt;/p&gt;

&lt;h3 id=&quot;red---green---refactor&quot;&gt;Red - Green - Refactor&lt;/h3&gt;

&lt;p&gt;The mantra of TDD - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Red - Green - Refactor&lt;/code&gt; - describes the small feedback cycle you use to develop software in a test-driven way. You start with a failing (red) test, write code to make it pass (green) and then take your time to clean up and refactor. And back to square one. It’s one thing to read about the “RGR” cycle and nod in agreement. It’s another thing to apply it. This is where most people start struggling when the rubber hits the road in my experience. They try to get started with TDD but feel like they are going too slow and become frustrated. Or they are taking too big steps at once and lose track of what they’re doing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Learning TDD”&lt;/em&gt; drives this point home. Saleem explains the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Red - Green - Refactor&lt;/code&gt; cycle and demonstrates over and over again how to apply it. He is giving valuable advice how you can use &lt;em&gt;“RGR”&lt;/em&gt; to speed up when you’re confident and slow down and take baby-steps when the task ahead becomes scary and hard to grasp.&lt;/p&gt;

&lt;p&gt;Working through this book will give you a profound understanding for this small feedback cycle. Chances are you will finish the book longing for similarly short and snappy feedback cycles for your day to day work as a software developer. &lt;strong&gt;Fast feedback&lt;/strong&gt; is a great boost to productivity in software development. Continuous Delivery and Agile methodologies try to establish this concept on a team-wide level. TDD is your own personal tool to get fast feedback while you fix bugs or work on new features.&lt;/p&gt;

&lt;h3 id=&quot;unit-testing-design-and-maintainability&quot;&gt;Unit Testing, Design and Maintainability&lt;/h3&gt;

&lt;p&gt;TDD is not primarily about unit testing. It is a tool to help you design your software - and you get unit tests and long-term maintainability as helpful byproducts. By writing unit tests first you think about the design of your APIs, your classes, methods and functions. You end up with working examples calling your code and asserting correct behavior. You have an automated test suite that allows you and everyone else on your team to change and improve your code in a safe way.&lt;/p&gt;

&lt;p&gt;You will take a quick detour into software design. The book briefly explains how loose coupling and high cohesion make your code more maintainable. It touches on &lt;em&gt;Dependency Injection&lt;/em&gt;, a crucial pattern to help with decoupling and testing. And here sits my main gripe with the book: These aspects fall a little too short to my taste. There is just enough information for beginners to learn the important terms and concepts but experienced developers &lt;em&gt;will&lt;/em&gt; feel like they need more details here. I understand that explaining good design and waffling about low coupling and high cohesion is out of scope for this book - but I think it is an important aspect to follow up on.&lt;/p&gt;

&lt;p&gt;This book demonstrates the ideas behind TDD rather than endlessly explaining philosophical aspects. You will write tests, write code, clean up, refactor, delete code, and improve iteratively while having a test suite backing you up on each step. If you’ve ever wanted to refactor an unwieldy, complicated and untested piece of code, you know how daunting that is. Here, you will experience what the alternative feels like - and trust me, once you’ve experienced this, you don’t want to go back.&lt;/p&gt;

&lt;h3 id=&quot;a-practical-developer-workflow&quot;&gt;A Practical Developer Workflow&lt;/h3&gt;

&lt;p&gt;Finally, this book puts emphasis on an effective developer workflow. You will use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; to version control your changes from the very beginning. Every step you take will be wrapped up by creating distinct commits in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; to conclude you work. On top of that, Saleem dedicates an entire chapter to demonstrate how to set up a &lt;a href=&quot;https://en.wikipedia.org/wiki/Continuous_integration&quot;&gt;Continuous Integration&lt;/a&gt; (CI) build using &lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are relatively new to the trade, this will be an excellent and no-frills explanation of two immensely useful tools in a developer’s toolkit: Version Control and Continuous Integration. If you are a seasoned developer and familiar with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; already, it’s nice to see how you can use TDD’s “RGR” cycle to size your commits into helpful and small chunks.&lt;/p&gt;

&lt;h2 id=&quot;should-i-read-this-book-or-kent-becks-tdd-by-example&quot;&gt;Should I read this book or Kent Beck’s &lt;em&gt;“TDD by Example”&lt;/em&gt;?&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;“Learning Test-Driven Development”&lt;/em&gt; uses an approach that’s very similar to Part I of &lt;a href=&quot;https://en.wikipedia.org/wiki/Continuous_integration&quot;&gt;Kent Beck’s &lt;em&gt;“Test-Driven Development by Example”&lt;/em&gt;&lt;/a&gt;. So why would you read this book instead of the original? And are there any reasons to prefer Kent Beck’s book to this one?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Learning TDD”&lt;/em&gt; is a modern take on Kent Beck’s 20 year old seminal book on TDD. Instead of using a rather dated flavour of Java, you can choose between JavaScript, Python and Go. &lt;em&gt;“Learning TDD”&lt;/em&gt; is using modern workflows that are widely regarded a good idea when developing software today (namely version control and CI). Finally, &lt;em&gt;“Learning TDD”&lt;/em&gt; is a beginner-friendly, approachable, no frills, hands-on guide to get you up to speed with Test-Driven Development. Nothing more, nothing less. It’s not trying to sell you philosophical aspects of TDD, it’s showing you how to practice it. It assumes that you’re either willing to learn TDD or looking for a refresher, it does not assume you need to be fundamentally convinced that TDD is a good thing.&lt;/p&gt;

&lt;p&gt;Kent Beck’s &lt;em&gt;“TDD by Example”&lt;/em&gt; goes beyond being a hands-on workshop. On top of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Money&lt;/code&gt; code kata, Kent Beck’s original will cover fundamental thoughts and additional patterns more explicitly. In his last part, Beck goes on to explain patterns that make writing tests and testable code easier. As an example, Beck explains how to use Mock objects to test awkward interactions (like database calls), which is a quite common need web development. &lt;em&gt;“Learning TDD”&lt;/em&gt; doesn’t come with a dedicated “Patterns” section but rather demonstrates some of those patterns and concepts as part of the journey the reader is going through. If you’re the person who prefers reading a pattern catalogue, Beck’s book might have what you’re looking for.&lt;/p&gt;

&lt;h2 id=&quot;where-does-this-book-fall-short&quot;&gt;Where does this book fall short?&lt;/h2&gt;

&lt;p&gt;Learning and mastering Test-Driven Development is a long and nuanced journey. I’ve been using TDD for the majority of my career. I’ve &lt;a href=&quot;https://martinfowler.com/articles/practical-test-pyramid.html&quot;&gt;written extensively about testing&lt;/a&gt;. I’ve taught others. Yet there are still things I don’t know. I still write tests that are low-value. I still end up with tests that are tied too close to the implementation. And, of course, I still get silly bugs into production that could’ve been prevented by a certain test. You will discover new patterns and approaches the longer you stick with it but you have to keep an open mind and keep exploring.&lt;/p&gt;

&lt;p&gt;If you’re looking for a book that helps you get beyond the mechanics of TDD, a book that shows you advanced patterns and helps you navigate tricky situations, this book might not be what you’re looking for.&lt;/p&gt;

&lt;p&gt;Here are some things that are &lt;strong&gt;not covered&lt;/strong&gt; by &lt;em&gt;“Learning Test-Driven Development”&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;How to introduce TDD in a legacy codebase. I recommend &lt;a href=&quot;https://www.goodreads.com/book/show/44919.Working_Effectively_with_Legacy_Code&quot;&gt;Michael Feather’s &lt;em&gt;Working Effectively with Legacy Code&lt;/em&gt;&lt;/a&gt; or the &lt;a href=&quot;https://understandlegacycode.com/&quot;&gt;Understanding Legacy Code Newsletter&lt;/a&gt; if this is important to you.&lt;/li&gt;
  &lt;li&gt;How to deal with databases, caches, network calls? The book briefly introduces the (essential) concept of &lt;em&gt;Dependency Injection&lt;/em&gt; but doesn’t go into too much detail. You might want to read &lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;Mocks Aren’t Stubs&lt;/a&gt; for more details here.&lt;/li&gt;
  &lt;li&gt;Advanced and nuanced patterns of test automation. Gerard Meszaros’ &lt;em&gt;&lt;a href=&quot;http://xunitpatterns.com/index.html&quot;&gt;xUnit Test Patterns&lt;/a&gt;&lt;/em&gt; is a tried and trusted (but a little dated) pattern book that can help you here. You can also read a lot of the patterns online if you’re curious about &lt;a href=&quot;http://xunitpatterns.com/Test%20Smells.html&quot;&gt;Test Smells&lt;/a&gt;, &lt;a href=&quot;http://xunitpatterns.com/Test%20Organization.html&quot;&gt;Organizing Tests&lt;/a&gt; or how to work with &lt;a href=&quot;http://xunitpatterns.com/Test%20Double%20Patterns.html&quot;&gt;Test Doubles&lt;/a&gt; (Mocks, Stubs, Spies and Fakes).&lt;/li&gt;
  &lt;li&gt;What are the limits of unit testing? When should you reach for different kinds of tests? And how do those fit into your TDD cycle? I tried capturing some of those thoughts in &lt;em&gt;&lt;a href=&quot;https://martinfowler.com/articles/practical-test-pyramid.html&quot;&gt;The Practical Test Pyramid&lt;/a&gt;&lt;/em&gt; but this is a very nuanced discussion.&lt;/li&gt;
  &lt;li&gt;How does TDD help drive more modular, decoupled designs? This is tangentially covered but you might long for a more in-depth discussion about cohesion, coupling, dependency injection and how TDD can be at the root of those.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these topics are omitted on purpose. This book aims to teach new and seasoned developers alike how to get to grips with Test-Driven Development and does not try to go beyond that. It is a start of a very rewarding journey. And the good news is that learning the very basics will equip you with a very powerful mindset that you can immediately use and expand over the coming years to write more maintainable code.&lt;/p&gt;

&lt;h2 id=&quot;i-heard-tdd-is-dead-why-should-i-bother-learning-tdd-today&quot;&gt;I heard TDD is dead. Why should I bother learning TDD today?&lt;/h2&gt;

&lt;p&gt;Yeah… no. Don’t fall for &lt;a href=&quot;https://dhh.dk/2014/tdd-is-dead-long-live-testing.html&quot;&gt;hyperbolic posts&lt;/a&gt; meant to drive clicks and spark controversy. TDD is a tool that helps you think differently about the way you write code. I recommend you give it a try and see if it clicks for you. I’m convinced that TDD helps write you write better and more maintainable code like no other tool in your toolbox but you don’t have to take my word as gospel. Learn it, play around with it, try to stick with it and see for yourself.&lt;/p&gt;

&lt;p&gt;Initially it will feel unnatural. It will feel tedious. You might think your productivity is tanking and you will be tempted to go back to your tried and trusted way of writing code.&lt;/p&gt;

&lt;p&gt;Stick with it. You will be grateful for your past self who has written automated tests when you come back to your code in the future. TDD will make it easier for your future self and your team members to read, reason about, and change your code for a long time. Over time you will learn that TDD is a tool in your toolbox. And as every other tool it has its limitations. If you are building a throwaway prototype, testing &lt;em&gt;might&lt;/em&gt; not be helpful. If you are spiking a new framework and have no clue how things fit together, testing &lt;em&gt;might&lt;/em&gt; not be helpful. On the other hand, you will be surprised to see how much TDD can help in prototyping and exploratory situations to provide a quick way of testing and asserting unknown behavior. As with every tool its best to get first-hand experience with TDD, learn where it falls short and take that as a chance to either reconsider your approach or reconsider your usage of TDD for this particular situation. Do not give up on TDD as soon as you hit the first obstacle.&lt;/p&gt;

&lt;h2 id=&quot;my-recommendation&quot;&gt;My recommendation&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Learning Test-Driven Development - A Polyglot Guide to Writing Uncluttered Code&lt;/em&gt; keeps its promises.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It teaches you how to use TDD&lt;/li&gt;
  &lt;li&gt;It demonstrates TDD in three different languages&lt;/li&gt;
  &lt;li&gt;It emphasizes refactoring, cleaning up, and de-cluttering code as you go&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is as hands-on as it gets and you should treat this book as something to &lt;em&gt;work&lt;/em&gt; with to get the most out of it. Your mileage may vary if you’re reading it back to back before going to sleep.&lt;/p&gt;

&lt;p&gt;Saleem Siddiqui has written a modern and to-the-point version of Kent Beck’s “Test-Driven Design by Example”. Every developer who wants to pick up (or refresh) TDD skills will get a lot out of this book. If you’re not willing to give TDD a chance because you already made up your mind that TDD sucks and you write better code without it, this book is not for you. If you allow yourself to tackle this book with an open mind, I promise that you will be rewarded with a new (or refined) tool in your toolbox – a tool that I personally consider the most valuable one in my own developer toolbox. I was fortunate enough to learn TDD directly from Saleem earlier in my career and I’m excited to see that now everyone can get a similar experience by working through this book.&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/learning-tdd-review/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/learning-tdd-review/</guid>
				
			</item>
		
			<item>
				<title>How remote work changed my life</title>
				        
				<pubDate>Mon, 21 Dec 2020 00:00:00 +0000</pubDate>

				
				<description>&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“Hey Ham, how’s this remote work thing going for you?”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I often heard this question after starting a new job at &lt;a href=&quot;https://stackoverflow.com/business&quot;&gt;Stack Overflow&lt;/a&gt; remotely more than 1.5 years ago.Sometimes people asked out of genuine curiosity. They couldn’t imagine how working without ever being in an office could be a thing.&lt;/p&gt;

&lt;p&gt;Other times people seemed to be concerned about my well-being, wondering if I slowly turned into a hermit who never got to see the sunlight again.&lt;/p&gt;

&lt;p&gt;A year later, after the global Corona pandemic forced a lot of people to work from home for the greater part of 2020, that question had been replaced with&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“Does your remote work experience suck as much as mine?”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All I can say is: It’s going great. I’m happier than I’ve ever been. And I wouldn’t want to change it back.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/moving-on/&quot;&gt;Quitting my job&lt;/a&gt; and moving to the countryside was a big step for me and my family. It was packed with concerns and anxiety. Would the new job be fun? Is working remotely something for me? Will rural life become boring after a few months? Looking back on 1.5 years of living this life I’m feeling grateful, content and happy with how well things turned out. As the year is coming to an end and I have some free time, I’m going to reflect on how leaving the city for a remote job and living in the small town I grew up in changed my life - and because the year has been enough of a shit show, I promise it’s going to be really positive.&lt;/p&gt;

&lt;h2 id=&quot;more-time&quot;&gt;More Time&lt;/h2&gt;
&lt;p&gt;Working remotely comes with one fundamental advantage: I save a lot of time. Instead of spending 2 hours on public transport on a typical weekday (or worse if I was travelling to clients) my daily commute now consists of grabbing a coffee and going from the kitchen to my office. That’s 2 hours of extra time each day. 10 hours each week. And I can use them for whatever &lt;strong&gt;I&lt;/strong&gt; want, not whatever my commute permits.&lt;/p&gt;

&lt;p&gt;Having more free time has a compound effect. More free time means more time for my family, for myself, for hobbies, exercising, sleeping well, reading, 
running errands, doing chores. All of these things help improve my mental and physical health and I can feel it. More time is the foundation for all the other benefits I’m seeing in working remotely.&lt;/p&gt;

&lt;h2 id=&quot;more-space&quot;&gt;More Space&lt;/h2&gt;
&lt;p&gt;I grew up in a small town where rent was affordable. Being a home owner was common, not a privilege for the richest 10%. Growing up with this kind of perception of the world made accepting cost of housing in a metropolitan area extra hard for me. There was no way how our combined household income could ever allow us to buy a house or an apartment we liked in Hamburg.&lt;/p&gt;

&lt;p&gt;Working remotely allowed us to escape the ridiculous rents and costs of living in a large city. A year after moving back to the small town I grew up in, we bought a house that was both cheaper and larger than anything we’d have gotten in any metropolitan area.&lt;/p&gt;

&lt;p&gt;Besides a bigger place to live in, I benefit from more space in general. Nature is just a step away and I can go for nice long walks easily. I enjoy being outside, experiencing nature and the sense of calm and solitude. Especially if I get to enjoy sceneries like this regularly:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/nature.jpg&quot; alt=&quot;a view on my evening walk&quot; /&gt;
&lt;em&gt;A shot from one of my evening walks in fall 2020&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;my-dog-lenny&quot;&gt;My dog, Lenny&lt;/h2&gt;
&lt;p&gt;With a home, a yard and a lot of surrounding nature, it felt obvious that a dog would be a great companion for our family. I’m at home all day and on some days wouldn’t have a real reason to leave the house. With a dog by my side, I’d have a buddy hanging out in my office with me each day, someone I could talk to and, most importantly, I’d have a reason to get out multiple times a day.&lt;/p&gt;

&lt;p&gt;So about half a year after I started working remotely, we got Lenny, a Labrador mix, and he’s the best buddy I could imagine.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/lenny.jpg&quot; alt=&quot;Lenny&quot; /&gt;
&lt;em&gt;My dog, Lenny, snoozing in his bed&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With Lenny, I get to enjoy nature every day. My wife and I usually walk the dog together and it’s become my favorite ritual to start and end the workday.&lt;/p&gt;

&lt;h2 id=&quot;more-exercise&quot;&gt;More Exercise&lt;/h2&gt;
&lt;p&gt;Exercise has become an important aspect of my life about 7-8 years ago. As a young adult, I struggled with obesity and unhealthy lifestyle choices until health problems made me change my habits and lose a good amount of weight. I joined a gym, started to go running and be more mindful around the stuff I’d put into my mouth. About 3 years ago, I saved some money to invest in a small home gym setup that I put together in the basement of our rented apartment in Hamburg. Nothing fancy - a rack, a barbell, some weights and a bench - but good enough to keep me moving and improving my physical fitness. I experimented with different workout plans and managed to get the occasional workout in each and every week but I was nowhere as consistent as I wanted to be.&lt;/p&gt;

&lt;p&gt;Now, with a remote work setup and more time at hand, I have the luxury of more routine that allows me to exercise more regularly. This year, I pretty consistently managed to work out 4 times a week for about 1 hour each time. Usually, I’ll take my late morning or lunchtime hours when the majority of my colleagues in later time zones are still asleep to step away from work for an hour and work out in the garage gym. This has worked incredibly well so far and allows me to work on my physical health, get some quality time away from work and come back refreshed and ready to tackle the second half of my workday.&lt;/p&gt;

&lt;p&gt;Thanks to regular exercise paired with walking the dog daily, I’m feeling happy, energized and more resilient than ever before in my life. With a job that’s mostly mentally exhausting and otherwise involves sitting in a chair for 8 hours a day, I feel it’s really important to strike a good balance and make sure you get your body to be properly exhausted as well.&lt;/p&gt;

&lt;h2 id=&quot;quality-time&quot;&gt;Quality Time&lt;/h2&gt;
&lt;p&gt;I noticed that I spend more of my free time in ways I’d consider quality time: time spent with my family, with friends, working on things that are important to me, building meaningful connections, picking up new hobbies.&lt;/p&gt;

&lt;p&gt;Part of this is possible because moving meant that I’d live a lot closer to a big part of my family and my friends. Many of them live within walking distance from my home now. Being physically close to family and friends allows to drop by frequently and spontaneously. I can visit my parents, bring a bowl of soup I cooked to my grandma (you should see the joy!), help a friend with renovation work when they call and ask for help, meet at the pub to play a round of &lt;em&gt;Doppelkopf&lt;/em&gt; and have a beer or  two. All of this is far away from my day job. No computers, no programming, no digital anything. Just people, human relationships, getting your hands dirty or grabbing a beer with friends.&lt;/p&gt;

&lt;p&gt;I often compare this to how I spent my free time during my previous job. I moved to Hamburg for the job, so naturally the vast amount of connections I had came from work - that’s how you meet people as an adult. With some people I felt like I’d have made rather meaningful connections and I love them dearly. Still, whenever we’d meet up, we ended up talking about work and work-related stuff.&lt;/p&gt;

&lt;h2 id=&quot;a-tight-knit-community&quot;&gt;A tight-knit community&lt;/h2&gt;
&lt;p&gt;As a small town kid I was used to the fact that I knew a lot of people around me and people knew me. This is both fun and frightening at the same time. When I left after graduating from school I was certain that I’m never going to miss the fact that everyone knew anyone.&lt;/p&gt;

&lt;p&gt;And yet years later I started missing it. Being a totally anonymous person when buying bread at your baker, not knowing your neighbors (or caring about them at all) and being able to live side by side without ever bothering to get to know each other even in the most shallow way was bugging me ever so slightly.&lt;/p&gt;

&lt;p&gt;I learned that I get a sense of joy from being part of a tight-knit community. When I buy bread from the bakery they know my name, we have a short chat about what’s going on in town and occasionally they’ll shove an extra sweet raisin bun into my bag. My neighbors care about each other and invite us over for a beer and barbecue on summer nights. If I need fresh eggs I send a text message to a buddy who’s got chickens in their yard and they’ll leave a pack of eggs out on their porch for me to pick up in exchange for a glass of cherry jam from my garden. If I need firewood I know this guy from the next village I can call who’s got plenty waiting to be picked up. Every so often, people need help with renovations, moving or work around the house - and they’ll just call and ask for help. Need a hand? Ask around and people will show up in no time. Need a tractor for some nasty yard work? A friend of a friend’s got one, ask and they’ll be there. It’s all about small favors and giving back every once in a while. This may sound cheesy to some but to me this feels like I belong to a community and it feels really nice.&lt;/p&gt;

&lt;h2 id=&quot;fewer-options&quot;&gt;Fewer options&lt;/h2&gt;
&lt;p&gt;Small town living is not all sunshine and rainbows, of course. Living in a city does bring its benefits and the most obvious one is certainly the vast choice of bars, restaurants, cafes, theatres, museums, concerts and other things to choose from. Over here, there’s merely a handful of pubs and a similar amount of restaurants to go to. Museums, theatres and cinemas are rare.&lt;/p&gt;

&lt;p&gt;I can cope with the limited choice just fine. When I’d go out for a drink in Hamburg it’d usually be one of the same five bars. I’m not getting a huge kick out of posh restaurants or the latest foodie trends. And if I want to go to a concert, I’ll have to get tickets for a show in another city and drive there or get a place to stay for the night. For me, this works just fine but I acknowledge that 2020 has been an extreme outlier where a lot of public places have been closed for the better part of the year anyways.&lt;/p&gt;

&lt;h2 id=&quot;a-steady-pace&quot;&gt;A steady pace&lt;/h2&gt;
&lt;p&gt;Looking back on 1.5 years of working remotely from a small town makes me feel like I’m at a happy place at this point in my life. After quitting my previous job due to burnout, I try to consistently do a pulse check to see where my mental and physical health is heading and whether I’m still on the right track. After starting a job remotely, I feel like I’ve been running at a healthy and steady pace. I’ve got rich interactions in my daily life, within and outside of work. I feel a great sense of belonging, spend more quality time with my family than ever before and still have plenty of personal time. All of this is happening while I can still work on interesting things at Stack Overflow that impacts the life of a lot of people out there.&lt;/p&gt;

&lt;p&gt;I’m truly grateful to be where I am today.&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/remote-work-changed-my-life/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/remote-work-changed-my-life/</guid>
				
			</item>
		
			<item>
				<title>Doppelkopf — 3 Years Later</title>
				        
				<pubDate>Wed, 11 Nov 2020 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;Almost exactly three years ago, I wrote &lt;a href=&quot;/blog/doppelkopf/&quot;&gt;an announcement&lt;/a&gt; about a new side project I started working on: &lt;strong&gt;Doppelkopf&lt;/strong&gt;, a browser-based version of the popular German card game with the same name.&lt;/p&gt;

&lt;p&gt;I’ve been quiet about its progress ever since. It’s not like I’ve written lots of other stuff either, but I’ve also been quiet about &lt;em&gt;that&lt;/em&gt; project in particular. You might be wondering about the project’s fate. Did I give up? Hit a roadblock? Nuke the entire Git repository by accident?&lt;/p&gt;

&lt;p&gt;Nope, none of it! Almost 3 years and over &lt;em&gt;1024 commits&lt;/em&gt; later &lt;a href=&quot;https://github.com/hamvocke/doppelkopf&quot;&gt;the project&lt;/a&gt; is still alive and kicking and, just like when I started out, it continues to be a lot of fun to build.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hey you… If you’re just here looking for the &lt;strong&gt;Play the Game&lt;/strong&gt; button: Here it is. But you’ve gotta come back and read on, you hear?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://doppelkopf.party&quot; target=&quot;_blank&quot;&gt;
&lt;img src=&quot;/assets/img/uploads/doppelkopfTeaser.png&quot; alt=&quot;game teaser&quot; /&gt;
&lt;em&gt;Go ahead, play the game right here&lt;/em&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contributions haven’t always been steady. Life happens. I &lt;a href=&quot;/blog/moving-on/&quot;&gt;changed jobs&lt;/a&gt;, moved to the countryside, got married, bought a house, got &lt;a href=&quot;https://twitter.com/hamvocke/status/1294311723520983041&quot;&gt;a fluffy coworker&lt;/a&gt;, baked at least a dozen really decent pizzas, wrestled a dinosaur, a lot of grown-up stuff. I’m trying to get my priorities straight and a browser-based card game surely doesn’t take the pole position in my life (sad, I know).&lt;/p&gt;

&lt;p&gt;When daily life gets more calm, it’s my own meandering that gets in the way of steady progress. I like it that way since I’m partially this project to get my hands dirty with technology I’m curious about and to escape from the everyday chaos.&lt;/p&gt;

&lt;p&gt;Sometimes I feel bad for not getting something usable out there sooner but then I remember that no one out there gives a damn because it’s not on anyone’s radar anyways.&lt;/p&gt;

&lt;p&gt;I’ve meant to write an official update, an announcement of sorts, for at least 2 years now. Never wrote it. Mostly because I felt that the game just wasn’t ready yet. &lt;em&gt;“Just these three more features, then we’ll write the announcement”&lt;/em&gt; I’d keep telling myself.&lt;/p&gt;

&lt;p&gt;Yes, I know the &lt;em&gt;The Lean Startup&lt;/em&gt; says that I should get stuff out while I’m still embarrassed or I’ve waited too long. My job at ThoughtWorks consisted of reminding people that releasing frequently and getting user feedback early is super-duper important. I’ve used lofty words like &lt;a href=&quot;https://en.wikipedia.org/wiki/Minimum_viable_product&quot;&gt;&lt;em&gt;“MVP”&lt;/em&gt;&lt;/a&gt; unironically. All that only to ignore what I’d know better.&lt;/p&gt;

&lt;p&gt;And you know what? It doesn’t matter. We’re not trying to be the &lt;em&gt;Uber for niche card games&lt;/em&gt; or the &lt;em&gt;Tinder for people who can hold 10 cards in their hand while drinking a beer with the other&lt;/em&gt;. There’s no rush, no deadlines, no pressure. Just a blissful journey towards creating an Open Source card game; and maybe one day someone has fun playing it.&lt;/p&gt;

&lt;p&gt;Now that I’ve explained that slacking is cool when &lt;strong&gt;I&lt;/strong&gt; do it, let’s move on and look at the things that have changed since I wrote the first few lines of code 3 years ago, shall we?&lt;/p&gt;

&lt;h2 id=&quot;basic-gameplay&quot;&gt;Basic gameplay&lt;/h2&gt;

&lt;p&gt;When I wrote the first blog post about this project, I didn’t have much more than a bunch of unit tests and primitive game logic in place. You could create cards, sort them, find out if one card beats another card. Low-level building blocks, only held together by unit tests.&lt;/p&gt;

&lt;p&gt;Fast forward to today and we’ve got a playable single-player game in place, presented with a decent user interface. You can start a game, play multiple rounds, win a game, lose a game (the computer players are crap - you better win this, my friend!), get extra points for &lt;em&gt;catching a Fox&lt;/em&gt; or &lt;em&gt;winning a Doppelkopf&lt;/em&gt; and get correct scores after each round.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/doppelkopfGameplay.png&quot; alt=&quot;Doppelkopf gameplay&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yes, the experienced Doppelkopf aficionado will immediately notice that some things are still missing: You can’t play a solo. You can’t make any announcements. The computer players (think I should start calling them &lt;strong&gt;AI&lt;/strong&gt; and score millions in venture capital?) make questionable moves. And yet it’s fun to play already.&lt;/p&gt;

&lt;h2 id=&quot;user-interface&quot;&gt;User interface&lt;/h2&gt;
&lt;p&gt;The game’s got an interactive user interface powered by plain old HTML, CSS and Vue.js. When you build a browser game, one of the fundamental decisions to make is how you want to render your user interface. You get a few choices:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;use the good old &lt;a href=&quot;https://en.wikipedia.org/wiki/Document_Object_Model&quot;&gt;DOM&lt;/a&gt; and reap the benefits that decades of web development have brought us, including CSS and all its clever layout technologies (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flex&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grid&lt;/code&gt; are heaven-sent)&lt;/li&gt;
  &lt;li&gt;render everything in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas&quot;&gt;Canvas&lt;/a&gt; if you favor low-level control and don’t want the comforts of CSS or need extra performance&lt;/li&gt;
  &lt;li&gt;use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API&quot;&gt;WebGL&lt;/a&gt; if you want to get &lt;em&gt;really&lt;/em&gt; fancy&lt;/li&gt;
  &lt;li&gt;write everything in Flash and publish your game on newgrounds.com (just kidding, this isn’t 2003. Seriously, don’t do this!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doppelkopf is not a fast-paced 3D action shooter. We’re not rendering a lot of flashy animations nor do we care about high performance to let 4 players play one card turn by turn. On the contrary, we’re mostly dealing with rectangular shapes (cards), some icons and text that need to be moved around the virtual table neat and orderly. And this is where CSS and HTML are a great combo.&lt;/p&gt;

&lt;p&gt;With Vue.js we can add a good amount of interactivity to handle simple interactions like “clicking on a card” or “pressing a button”. On top of that, its reactive programming model makes it really pleasant to represent the inner state of the game in the user interface without having to do any DOM manipulation by hand.&lt;/p&gt;

&lt;p&gt;I decoupled the game logic from the user interface logic as strict as I could. The game is running entirely client-side, so both the game logic as well as the user interface are written in JavaScript. This makes it easy for the game logic’s and user interface’s boundaries to bleed into each other, making things harder to reason about in the long run.&lt;/p&gt;

&lt;p&gt;Using a strict test-driven approach to developing the game logic helped keep these boundaries in place as it allowed designing APIs that are usable from tests only without any user interface in place. This way the game logic becomes its own, very expressive and isolated layer in the code that can represent the entire game’s state and behavior in plain old JavaScript. Vue.js is taking care of the user interface representation only and builds the components that allow us to display information and react on user input. I’m really happy about this strict separation as it makes testing painless and allows us to steer away from tedious state-management libraries like Vuex.&lt;/p&gt;

&lt;h2 id=&quot;design&quot;&gt;Design&lt;/h2&gt;
&lt;p&gt;My Kryptonite! The game doesn’t look like ass, and that’s the most positive thing you’ll catch me say out loud. Somewhere deep down I know that the game’s visual design is &lt;em&gt;okay&lt;/em&gt; - the color scheme is decent and doesn’t look like &lt;a href=&quot;https://blog.codinghorror.com/a-tribute-to-the-windows-31-hot-dog-stand-color-scheme/&quot;&gt;Hot Dog Stand&lt;/a&gt;, I’ve used some rather smooth CSS animations, and I’ve made sure to check some accessibility aspects that I know of. This isn’t meant to be fishing for compliments but when it comes to visual design, I’m incredibly picky yet unable to produce something great by myself.&lt;/p&gt;

&lt;p&gt;This is why improving the visual design of the game is a massive time sink for me. I’ve spent days finding and tweaking colors on &lt;a href=&quot;https://coolors.co/&quot;&gt;coolors.co&lt;/a&gt; and &lt;a href=&quot;https://colorhunt.co/&quot;&gt;Color Hunt&lt;/a&gt;. I’ve searched, sketched, scribbled logos more than I can count, only to come up with… two overlapping cards? Well, at least it’s all CSS and has got a slick hover animation!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/doppelkopfLogo.gif&quot; alt=&quot;the animated Doppelkopf logo&quot; /&gt;
&lt;em&gt;Whoop whoop! It moves!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’m okay with where we’re at right now but I know that there’s so much room for improvement. I want to break out of the bleak and ordinary look of the game and make it a little more fun, a notch more quirky. I’d love to use illustrations, print stickers and card decks and send them out to players, contributors, or project sponsors - but I think I’ll need some help there.&lt;/p&gt;

&lt;h2 id=&quot;infrastructure&quot;&gt;Infrastructure&lt;/h2&gt;
&lt;p&gt;This is a simple system. We’re not building a cloud-native, webscale, serverless event-driven microservice architecture (I really tried with the buzzwords here).&lt;/p&gt;

&lt;p&gt;We’re talking about a backend process in Python that we need to run on a server, and we’re talking about a bunch of HTML, CSS and JavaScript that we need to get to our users’ browsers. And strictly speaking, right now it doesn’t even matter if the backend wasn’t available 24/7 (and it’d be cool if it stays that way in the future).&lt;/p&gt;

&lt;p&gt;As much as anybody else I’m a big fan of keeping things simple. At the same time, I want to take this project as an opportunity to learn a bunch of new things. So we’ve gotta balance things to avoid falling off a cliff.&lt;/p&gt;

&lt;p&gt;I’ve set up enough build pipelines and server infrastructure to know what it takes to get software out to production in an automated and repeatable way. At the same time, building servers, dealing with networking, watching build pipelines and provisioning scripts to finish and working on all the plumbing and duct tape required to combine these aspects is something that makes me consider quitting my developer life and moving to a farm at least three times a year.&lt;/p&gt;

&lt;p&gt;For Doppelkopf’s infrastructure I wanted to find a pragmatic middle-ground. Something more modern than a hand-crafted snowflake server running in my mom’s basement. And certainly something less ridiculous than a full-fledged Kubernetes cluster running in a multi availability-zone setup with a global CDN in place. Let’s get some users first before we drown ourselves in infrastructure debt, shall we?&lt;/p&gt;

&lt;p&gt;With all the noise and hype in our industry I found it incredibly hard to find the sweet spot and not fall for the siren sounds of cloud vendors and tool builders out there. Ultimately, I’ve ended up with this setup:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.terraform.io/&quot;&gt;Terraform&lt;/a&gt; is automatically spinning up the infrastructure - servers, domains, networking and very basic provisioning&lt;/li&gt;
  &lt;li&gt;The Terraform configuration comes as an extra Git repository. Whenever I push changes there, a &lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt; pipeline will automatically build a new environment and deploy the application&lt;/li&gt;
  &lt;li&gt;Everything’s running on a single instance of the cheapest server you can get on &lt;a href=&quot;https://www.terraform.io/&quot;&gt;DigitalOcean&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;The backend and frontend applications are built as &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt; images and pushed to a Docker registry with every change (again, a CircleCI build pipeline kicking in)&lt;/li&gt;
  &lt;li&gt;For deployment I &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt; into the target servers, pull both images from the Docker registry and start them with a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose up&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://caddyserver.com/v2&quot;&gt;Caddy&lt;/a&gt; takes care of setting up HTTPS using &lt;a href=&quot;https://caddyserver.com/&quot;&gt;Let’s Encrypt&lt;/a&gt; and serving the applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup is simple and effective. And most importantly: It’s fully automated. This way, I can work on infrastructure after not touching it for months without having to curse my past self for what they’ve done.&lt;/p&gt;

&lt;p&gt;Yes, there are obvious shortcomings: no load balancing, no redundancy, no sophisticated content delivery networks involved. And you know what? At this point in time I couldn’t care less. All of these are the kind of problems to solve once you’ve got enough users playing your damn game. Before that happens, I’m not going to lose any sleep over my lack of redundancy for serving something’s that’s basically a silly static website.&lt;/p&gt;

&lt;h2 id=&quot;a-boring-mature-tech-stack&quot;&gt;A &lt;del&gt;boring&lt;/del&gt; &lt;ins&gt;mature&lt;/ins&gt; tech stack&lt;/h2&gt;
&lt;p&gt;Remember how we all made the same lame joke about the JavaScript ecosystem? The one where the popular JavaScript frameworks change every other week? Yeah, I do remember and I’m totally guilty of that.&lt;/p&gt;

&lt;p&gt;When I started this project, I placed a few technology bets and - believe it or not - they’ve held up nicely: Modern JavaScript, Vue.js, Jest, Python and Flask, Terraform, Docker are the main drivers.&lt;/p&gt;

&lt;p&gt;None of these were risky bets when I made them. And that’s precisely the point: I chose mature and &lt;a href=&quot;http://boringtechnology.club/&quot;&gt;boring technology&lt;/a&gt; and I’m certain that this is why I still keep pushing 3 years later. Vue.js had been around for a good while. With &lt;a href=&quot;https://cli.vuejs.org/&quot;&gt;vue-cli&lt;/a&gt; you get scaffolding with sane defaults to get started easily with an ecosystem that can quickly be overwhelming. JavaScript has matured significantly since its early days and with Babel and Webpack set up you don’t have to worry about compatibility all that much. Needless to say that Flask and Python have been a sane choice for the backend as well. The backend doesn’t do much more than provide a simple REST API and a few admin screens so pretty much every web framework out there would’ve done the job, but Python and Flask have been practical and pleasant to use, so there’s that.&lt;/p&gt;

&lt;p&gt;That’s not to say that all of these technologies were rainbows and unicorns at all times. JavaScript - of course - continues to have its quirks and larger-scale refactorings are beginning to become tedious. Wrestling Webpack configuration has made me swear like a sailor more than once. And sometimes I wish I’d just bite the bullet and use a simple PaaS solution like Heroku to deal with all my infrastructure worries. But all of those are concerns that future Ham can deal with.&lt;/p&gt;

&lt;h2 id=&quot;the-road-ahead&quot;&gt;The road ahead&lt;/h2&gt;
&lt;p&gt;A lot has happened and the project has seen slow but steady progress. There’s still a lot of work to be done and I try to be transparent about the road ahead. I maintain a &lt;a href=&quot;https://github.com/hamvocke/doppelkopf/projects/1&quot;&gt;Product roadmap&lt;/a&gt; on GitHub for everyone to see. I’m excited about contributions of any kind (issue reports, documentation, design, feature ideas, code, you name it!) and I’m trying to make the project as welcoming as I can. If you want to join, be my guest. I’d be glad to have you!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/hamvocke/doppelkopf/projects/1&quot;&gt;&lt;img src=&quot;/assets/img/uploads/doppelkopfRoadmap.png&quot; alt=&quot;the product roadmap&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that I finally got this heartbeat out in the open, I plan to write more regular updates with more detailed topics on specific aspects of the project in the upcoming weeks. Watch this space, &lt;a href=&quot;https://doppelkopf.party&quot;&gt;check out the game&lt;/a&gt; and if you feel adventurous, come join me over &lt;a href=&quot;https://github.com/hamvocke/doppelkopf&quot;&gt;on GitHub&lt;/a&gt;!&lt;/p&gt;

</description>
				<link>https://www.hamvocke.com/blog/doppelkopf-3-years/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/doppelkopf-3-years/</guid>
				
			</item>
		
			<item>
				<title>Building a Jira integration for Stack Overflow for Teams</title>
				        
				<pubDate>Wed, 11 Mar 2020 00:00:00 +0000</pubDate>

				
				<description>I built an integration between Stack Overflow for Teams and Jira. This post takes a peek under the hood of that integration.</description>
				<link>https://stackoverflow.blog/2020/03/11/building-a-jira-integration-for-stack-overflow-for-teams/</link>
				<guid isPermaLink="true">https://stackoverflow.blog/2020/03/11/building-a-jira-integration-for-stack-overflow-for-teams/</guid>
				
			</item>
		
			<item>
				<title>Distraction-free writing with vim</title>
				        
				<pubDate>Sun, 02 Feb 2020 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;I’m a sucker for aesthetics.&lt;/p&gt;

&lt;p&gt;And for command line tools.&lt;/p&gt;

&lt;p&gt;And for things that just do their damn job.&lt;/p&gt;

&lt;p&gt;From time to time, I feel like writing down my thoughts. That’s why this blog is a thing. My tool of choice is &lt;strong&gt;vim&lt;/strong&gt;, a notorious command line editor that stood the test of time. It’s free, ridiculously fast (if you don’t slow it down with reckless plugins) and command-line based. This puts vim &lt;em&gt;very&lt;/em&gt; close to my personal sweet spot.&lt;/p&gt;

&lt;p&gt;A few years ago, &lt;em&gt;distraction-free writers&lt;/em&gt; became a thing, beautifully designed applications with the sole purpose of letting you write stuff down. No frills. No gimmick. No distraction. Everything is presented to you, the writer, in a minimalistic design. Much like sitting in front of a typewriter, just you and the blank page. Scary!&lt;/p&gt;

&lt;p&gt;I don’t know if distraction-free writing is really going to be the game changer for you to write the next best-seller novel - or even your first blog post for what it’s worth. But I do know that they’re fun to use.&lt;/p&gt;

&lt;p&gt;With vim being my editor of choice, I didn’t want to switch to a different tool just to do what I could already perfectly do with vim, just in a more pleasurable design.&lt;/p&gt;

&lt;p&gt;Luckily, vim has a good plugin system and there are some talented plugin writers out there. &lt;a href=&quot;https://github.com/junegunn&quot;&gt;Junegunn Choi&lt;/a&gt; has written &lt;a href=&quot;https://github.com/junegunn/goyo.vim&quot;&gt;&lt;strong&gt;goyo.vim&lt;/strong&gt;&lt;/a&gt;, a plugin that turns vim into a distraction-free writer as soon as you type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:Goyo&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/img/uploads/goyo-vim.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;/assets/img/uploads/goyo-vim.png&quot; alt=&quot;goyo.vim in action&quot; /&gt;&lt;em&gt;goyo.vim in action&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need some distraction for your distraction-free writing, go and check out &lt;a href=&quot;https://github.com/junegunn/limelight.vim&quot;&gt;&lt;strong&gt;limelight.vim&lt;/strong&gt;&lt;/a&gt;, written by the same author. limelight.vim will highlight the region around your cursor and display everything else in a more dim color. Just type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:Limelight&lt;/code&gt; to get let your current paragraph shine in the spotlight.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/img/uploads/goyo-limelight-vim.apng&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;/assets/img/uploads/goyo-limelight-vim.apng&quot; alt=&quot;limelight.vim and goyo.vim in action&quot; /&gt;&lt;em&gt;goyo.vim with limelight.vim enabled&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install either plugin using your favourite plugin manager. You’ll find instructions and more details in the respective repository on GitHub.
There you go. Distraction-free writing that’s hitting the sweet spot between aesthetics, command line efficiency and doing one job well.&lt;/p&gt;

</description>
				<link>https://www.hamvocke.com/blog/distraction-free-writing/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/distraction-free-writing/</guid>
				
			</item>
		
			<item>
				<title>Moving On</title>
				        
				<pubDate>Fri, 05 Apr 2019 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;For the past 4.5 years I was a consultant and software developer at &lt;a href=&quot;https://www.thoughtworks.com/&quot;&gt;ThoughtWorks&lt;/a&gt; in Hamburg. It’s fair to say that there has never been a period in my life where I’ve learned so much about my profession, myself, society and my fellow human beings. My time at ThoughtWorks was a wild and exciting ride and an incredible experience.&lt;/p&gt;

&lt;p&gt;Still, I felt it was time to move on.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/ham-was-here.jpg&quot; alt=&quot;A graffito left on my favorite mug&quot; /&gt;
&lt;em&gt;You bet he was!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Being a consultant is a unique chance to learn a lot in a short time. Even more so when you’re surrounded by passionate and incredibly talented people as it’s the case at ThoughtWorks. You see different projects, work with clients who want to stir things up, and get the opportunity to hone your technology and people skills in a way you don’t see elsewhere.&lt;/p&gt;

&lt;p&gt;It was a huge privilege to work alongside so many talented people, not few of them writing books, publishing blogs and giving talks that change the software industry at large. I had so much to learn from my fellow colleagues, sometimes about technology-related things, more often about the ways people interact and how I could become a better pairing partner, team member and consultant. It amazes me how much I learned about communication, architecture, programming, influencing, empathy, coaching, mentoring, leadership, issues in society, reflection, feedback, respect and not taking yourself too seriously.&lt;/p&gt;

&lt;p&gt;For all of these experiences, for all the people that were there for me as friends, coaches, sponsors, sponsees, and colleagues, I’m grateful beyond belief.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/hamburg-strand.jpg&quot; alt=&quot;Hamburg Elbstrand&quot; /&gt;
&lt;em&gt;Schietwetter on Hamburg’s Elbstrand&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Being a consultant, however, comes with a flipside. The most obvious one is the flexibility that you need to bring to the table. As a consultant, you work with clients on &lt;em&gt;their&lt;/em&gt; challenges. That often means being onsite, playing by their rules, listening to where their pain points are. There’s nothing wrong with that and if you’re joining a consultancy, that’s exactly what you sign up for. However, this flexibility around work location and topics you’re working on can take its toll. Personally, I was very lucky as most of my projects were located in Hamburg and didn’t require that I’d travel much - being a father, travel can become really tricky.&lt;/p&gt;

&lt;p&gt;What really got me after a while was probably a combination of multiple things.&lt;/p&gt;

&lt;p&gt;Uncertainty around my future (what would I do in half a year to come once my current engagement comes to an end?) often felt like a pending threat to me as travel was always a likely option for the next project. That would have meant shifting my family’s routine massively and put a lot of burden on my partner.&lt;/p&gt;

&lt;p&gt;Frequent rotation of projects and roles means that you have the privilege to get to know a lot of people - colleagues as well as clients. Being a social and rather outgoing person, I usually got along well with most of them and was happy to get to know new people. I had to learn fast that every new relationship had an expiry date. With me or them leaving the project, chances reduced (sometimes drastically) that you’d meet again in a meaningful way. Relationships tended to remain shallow, real friendships remained few.&lt;/p&gt;

&lt;p&gt;My commute was a bigger driver. We lived on the fringe of Hamburg. Public transportation is solid and we had a station close to our home. However, every single day I’d spend 2 hours on the train. That’s 10 hours a week of sitting on the train. I know, for a lot of metropolitan areas that’s common. Eventually I was fed up with the time spent commuting.&lt;/p&gt;

&lt;p&gt;Cost of living is another big topic. Paying rent for the rest of my life doesn’t sound like a smart idea. Owning a home in Hamburg (even on the outskirts), however, was prohibitively expensive for us.&lt;/p&gt;

&lt;p&gt;All of these were minor annoyances compared to the final straw: burning out.&lt;/p&gt;

&lt;p&gt;ThoughtWorks is a place full of drive. People are ambitious and they know their shit. Having so many smart people around often gives you a feeling of not contributing enough. Imposter syndrome hits you, even if you know rationally that you don’t need to worry and that you’re getting a wrong perception by focusing on the collective highlights of hundreds of colleagues. In a system that rewards you for being engaged, driven and showing impact, I tend to strive. My journey at ThoughtWorks was quite successful (so I’d say) and I got great feedback over the years. In 2018 I discovered that this could kick-off a dangerous spiral of trying to over-achieve. At ThoughtWorks we are trying to be very mindful of that and have support structures in place that help people reflect on their situation to avoid running into dangerous situations. As I stepped into an internal, singular role in 2018, I lacked these routine support structures, however. This allowed me to grind myself down without having a team noticing. Luckily, I had a colleague coaching me during this time and she helped me recognizing my situation and hitting the brakes.&lt;/p&gt;

&lt;p&gt;After weeks and months of being stressed, grumpy, short-tempered, depressed and sleeping badly, I realized that it was time for a radical change. After long reflections with my family we ended up leaving the urban life behind, quitting our jobs and moving back to the countryside, where me and my partner grew up. I’m fortunate to have a strong social network in the place where I grew up. Family and lots of friends I know from my teenage years are still there or came back after venturing out - and I’m happy that I’ve never lost touch. Cost of living is a different dimension, so is being close to nature and still having all the infrastructure I need for my daily life.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;I’m so stoked that I was able to find a job that accommodates this change of scenery. Starting on Monday, I’m going to work remotely for &lt;a href=&quot;https://stackoverflow.com/&quot;&gt;Stack Overflow&lt;/a&gt;, a company that has always been part of my professional life. Working remotely always seemed intriguing to me ever since I’ve read &lt;a href=&quot;https://basecamp.com/books/remote&quot;&gt;Remote: Office Not Required&lt;/a&gt; and I’m grateful that I get a chance to experience this first-hand.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/ham-stack-overflow.jpg&quot; alt=&quot;Ham at Stack Overflow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’m aware that this lifestyle change is drastic and might come with certain drawbacks. I will miss people, I will miss the wide range of opportunities of a beautiful city like Hamburg, I will have to adapt to another lifestyle. However, I’m more than happy to have more time for my family, my friends and myself and a more calm lifestyle while being able to work on something exciting and meaningful.&lt;/p&gt;

&lt;p&gt;Wish me luck!&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/moving-on/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/moving-on/</guid>
				
			</item>
		
			<item>
				<title>Ham</title>
				        
				<pubDate>Fri, 05 Apr 2019 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;My name is &lt;em&gt;Hermann&lt;/em&gt;. And so is my father’s name. Growing up, I found this more annoying than charming. Living in one household with another person sharing the same name can lead to weird situations.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/ham-stickers.jpg&quot; alt=&quot;Ham stickers&quot; /&gt;
&lt;em&gt;Going with a name like “Ham” gives you a perfect excuse to print silly stickers.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When my mother yelled &lt;em&gt;“Hermann!”&lt;/em&gt; it was always a guessing game who was supposed to answer. Sometimes I could tell by her tone of voice, especially if I knew that it was either me or my father who was in trouble.&lt;/p&gt;

&lt;p&gt;Deciphering the intended recipient for letters and packets was annoying. So was explaining insurance companies, banks or automobile clubs (looking at you, ADAC) that my father and I are not the same person.&lt;/p&gt;

&lt;p&gt;The worst memory I have, though, is answering the phone. Having a small handyman shop, my father often went out to install or repair things. Living in a small town in the 90s and early 00s, a lot of communication was done over landline phones. My parents always encouraged me and my siblings to pick up the phone to help them.&lt;/p&gt;

&lt;p&gt;It was a disaster.&lt;/p&gt;

&lt;p&gt;Once my voice started to sound exactly like my father’s people couldn’t tell us apart on the phone. And answering the phone with &lt;em&gt;“Hello, this is Hermann Vocke speaking”&lt;/em&gt; (of course I said this in German, not English) did not help avoiding that confusion at all. After a couple dozen calls from strangers who rambled about their broken washing machines, ordered parts for their dishwasher or yelled at me because they were not happy with “my” previous job, I simply refused to answer the phone. I suspect this was the root cause for my anxiety of talking to strangers on the phone for years to come.&lt;/p&gt;

&lt;p&gt;Luckily enough, my family was good with nicknames. Growing up, I had quite a couple of them. Some were more playful, some were super awkward, and some more presentable. The one that ultimately stuck was &lt;em&gt;“Ham”&lt;/em&gt; (pronounced either &lt;em&gt;[hæm]&lt;/em&gt; - as in the English word for porky meat or &lt;em&gt;[ha:m]&lt;/em&gt; with a German pronunciation, both are fine).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ham&lt;/em&gt; or &lt;em&gt;Häm&lt;/em&gt; is a quite common nickname for people named &lt;em&gt;Hermann&lt;/em&gt; where I grew up. When &lt;a href=&quot;https://en.wikipedia.org/wiki/Low_German&quot;&gt;Low German (“Plattdeutsch”)&lt;/a&gt; was the main spoken language about two generations ago, Hermanns became Häms the same way as Heinrichs became Hinnerks. For extra credit, you’d put the last name in front and use it in a possessive way: &lt;em&gt;“Vocken Häm”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Over the past couple of years, I embraced that name more and more as it has some adorable traits:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;It’s short.&lt;/strong&gt; Three letters, one syllable. I can completely enter it into old-school arcade game high scores, how cool’s that?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It’s unique.&lt;/strong&gt; At least in combination with my last name. I can easily go with &lt;em&gt;“hamvocke”&lt;/em&gt; as my handle when I sign up for an online service. Searching for &lt;em&gt;Ham Vocke&lt;/em&gt; gets you to all things that are related to me. And once I started writing a bit more, it was helpful to establish &lt;em&gt;Ham Vocke&lt;/em&gt; consistently as my online identity (a hint Martin Fowler gave me).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It’s personal.&lt;/strong&gt; With its origin in a regional dialect there’s a regional touch to it.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It’s fun.&lt;/strong&gt; People usually think of the meaty product first and are confused. Being a legit name of Low German origin it has nothing to do with meat, of course. Still, it allows me to embrace this double meaning in a tongue-in-cheek way. Like printing hundreds of really spiffy &lt;em&gt;ham&lt;/em&gt; vinyl stickers that I can put on my stuff and hand out to people to remember me.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Being &lt;em&gt;Ham&lt;/em&gt; has always been a lot of fun. The name has got personality and charm and that’s why I love it. ♥️&lt;/p&gt;

&lt;p&gt;Ham 🍖&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/ham/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/ham/</guid>
				
			</item>
		
			<item>
				<title>Using 'make' to Make Your Code Easy to Work With</title>
				        
				<pubDate>Mon, 04 Mar 2019 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;In my daily work, I often switch between codebases. Each brings its own ecosystem of tools to create, manage, build and publish source code. One thing to help with the frequent switching is to have a single entry point to work with the source code in every project. I like to have a single wrapper script that allows me to run common commands I need for my daily developer life, no matter if I’m using &lt;a href=&quot;https://yarnpkg.com/en/&quot;&gt;Yarn&lt;/a&gt;, &lt;a href=&quot;https://github.com/rust-lang/cargo/&quot;&gt;Cargo&lt;/a&gt;, &lt;a href=&quot;https://gradle.org/&quot;&gt;Gradle&lt;/a&gt;, &lt;a href=&quot;https://pipenv.readthedocs.io/en/latest/&quot;&gt;Pipenv&lt;/a&gt; or a wild combination of tools under the hood.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/make.png&quot; alt=&quot;make automation in action&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At ThoughtWorks, we often call this a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go&lt;/code&gt; script (which, admittedly, became confusing after &lt;em&gt;go&lt;/em&gt;, the programming language, has become a thing). Teams at ThoughtWorks often create these scripts to make it easy run common tasks automatically: I can call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./go build&lt;/code&gt; to compile my source code, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./go test&lt;/code&gt; to run the test suite, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./go run&lt;/code&gt; to start the application locally, regardless of the tools that are used under the hood. &lt;a href=&quot;https://twitter.com/ph1&quot;&gt;Pete Hodgson&lt;/a&gt; wrote a nice series of articles &lt;a href=&quot;https://www.thoughtworks.com/insights/blog/praise-go-script-part-i&quot;&gt;in praise of the go script&lt;/a&gt; to describe this practice in more detail (&lt;a href=&quot;https://www.thoughtworks.com/insights/blog/praise-go-script-part-ii&quot;&gt;Part II is here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Having a script as a single entry point makes your code more accessible to other developers (and your future self!). It’s easy to do the things you want to do without memorizing long-winded commands. It’s easy to switch between different projects as the commands stay mostly the same. And it’s easy to discover what’s possible (by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./go help&lt;/code&gt;) which helps getting new people up to speed.&lt;/p&gt;

&lt;h2 id=&quot;go-scripts-an-example-in-bash&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go&lt;/code&gt; Scripts: An Example in Bash&lt;/h2&gt;
&lt;p&gt;Most of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go&lt;/code&gt; scripts I’ve seen were written in &lt;em&gt;bash&lt;/em&gt; and roughly followed the same structure of parsing the first parameter and then mapping that to certain actions:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;usage &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# print usage information&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;build &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# trigger build process&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# run test suite&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$# &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-lt&lt;/span&gt; 1 &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;usage
  &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$TARGET&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;help&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    usage
  &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;build&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    build
  &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    fail &lt;span class=&quot;s2&quot;&gt;&quot;Unknown command '&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;'&quot;&lt;/span&gt;
    usage
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
  &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Bash&lt;/em&gt; is a natural choice for simple automation tasks like this as it’s often available on developer machines (and your continuous delivery server) and is undeniably powerful.&lt;/p&gt;

&lt;p&gt;More recently I discovered that using &lt;a href=&quot;https://en.wikipedia.org/wiki/Make_(software)&quot;&gt;make&lt;/a&gt; can be a better fit for what we’re trying to achieve here. Let’s see how.&lt;/p&gt;

&lt;h2 id=&quot;make-and-makefiles&quot;&gt;make and Makefiles&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; itself is more powerful than what we’re using it for here. Usually it’s used for build automation and especially popular in the C/C++ universe for compiling source code but that doesn’t stop it from being useful for other things.&lt;/p&gt;

&lt;p&gt;If we want to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; as a simple wrapper to interact with our source code, we don’t need all of its bells and whistles and can start with understanding a few basics:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; looks for a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; in your current directory to figure out what it’s supposed to do. A Makefile is a plain text file that defines the different &lt;strong&gt;rules&lt;/strong&gt; you can execute.&lt;/p&gt;

&lt;p&gt;A rule follows this pattern:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;target: dependencies
    system command to execute
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The target defines how you call the rule from your command line. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make initialize-database&lt;/code&gt; would look for a rule called &lt;em&gt;“initialize-database”&lt;/em&gt; and execute the commands you defined.&lt;/p&gt;

&lt;h2 id=&quot;an-example-using-make&quot;&gt;An Example Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Let’s assume, we have a Python codebase using &lt;a href=&quot;http://flask.pocoo.org/&quot;&gt;Flask&lt;/a&gt; and want to have a simple way to perform three different actions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;run unit tests&lt;/li&gt;
  &lt;li&gt;start the application locally&lt;/li&gt;
  &lt;li&gt;run a code formatter&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A corresponding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.PHONY: test run format

test:
&amp;#09;pipenv run pytest

run:
&amp;#09;export FLASK_ENV=development &amp;amp;&amp;amp; \
&amp;#09;export FLASK_APP=myapp &amp;amp;&amp;amp; \
&amp;#09;pipenv run flask run

format:
&amp;#09;pipenv run black myapp/&lt;/code&gt;
&lt;/pre&gt;

&lt;div class=&quot;highlighted&quot;&gt;&lt;strong&gt;Note&lt;/strong&gt;: keep in mind that &lt;code&gt;make&lt;/code&gt; is picky about indentation. You need to indent your commands with a &lt;strong&gt;Tab&lt;/strong&gt;.&lt;/div&gt;

&lt;p&gt;Once we put this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; at the root of our project we can simply run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make test&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make run&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make format&lt;/code&gt; from our command line to perform the tasks we defined.&lt;/p&gt;

&lt;h2 id=&quot;phony-targets&quot;&gt;.PHONY targets&lt;/h2&gt;
&lt;p&gt;If you take a close look at the first line of our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; you’ll see a line starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.PHONY:&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.PHONY: test run format
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This line declares all three of our targets as &lt;em&gt;phony&lt;/em&gt; targets, i.e. targets that do not produce or depend on files on our file system. &lt;a href=&quot;https://stackoverflow.com/a/2145605/208660&quot;&gt;This answer on Stack Overflow&lt;/a&gt; does a fantastic job of explaining what this is all about. In a nutshell: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; usually expects to create files as output of the targets we run. If these files are in place, make won’t do anything.&lt;/p&gt;

&lt;p&gt;As an example:
Take the above Makefile. If we had a file called &lt;em&gt;“format”&lt;/em&gt; next to our Makefile and didn’t declare the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;format&lt;/code&gt; target as a phony target, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; would lazily refuse to do anything once we run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make format&lt;/code&gt;. It would just claim:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;make: `format' is up to date.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can’t avoid that someone creates a file with the same name as our make targets. To avoid breaking our make automation, we declare all our targets as phony targets. This way we’re safe from running into the pitfall of having name clashes with files on our file system.&lt;/p&gt;

&lt;h2 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h2&gt;
&lt;p&gt;One of the strengths of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; is the possibility to declare dependencies between targets. Usually this is meant to work with files on our file system again but we can also use it to chain the rules we have created in our makefile.&lt;/p&gt;

&lt;p&gt;Imagine you have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clean&lt;/code&gt; target that removes all compiled files from your file system. Occasionally you want to run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clean&lt;/code&gt; target by itself but you also want to run it every time before you compile your source code again (because you have way too much time at hand and incremental builds are just not your cup of tea 🤨). In this case you could declare the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clean&lt;/code&gt; target as a dependency for your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; target and make would run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clean&lt;/code&gt; every time before it runs the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; target:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;clean:
    rm -rf build/

build: clean
    # whatever you have to do to build your code
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;autocompletion&quot;&gt;Autocompletion&lt;/h2&gt;
&lt;p&gt;Another cool gimmick when using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; is that some shells provide autocompletion for your targets, either out of the box or by installing a small utility package. &lt;a href=&quot;http://zsh.sourceforge.net/&quot;&gt;zsh&lt;/a&gt; and &lt;a href=&quot;https://fishshell.com/&quot;&gt;fish&lt;/a&gt; support make autocompletion out of the box. If you’re a &lt;a href=&quot;https://www.gnu.org/software/bash/&quot;&gt;bash&lt;/a&gt; you can get autocompletion - not only for make - by installing &lt;a href=&quot;https://github.com/scop/bash-completion&quot;&gt;this package&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With make autocompletion in place, you can start typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; in your command line and hit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tab&lt;/code&gt; repeatedly to cycle through the available targets defined in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;caveats&quot;&gt;Caveats&lt;/h2&gt;
&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; is an easy way to make your project’s source code easy to work with. Make certainly is powerful and that power comes with great responsibility. Makefiles can grow out of hand quickly. Personally, I wouldn’t use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; for anything that’s way more complex than what we’ve outlined here. If you just need small wrappers around a certain set of commands, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; is a good way to go. It’s available on most systems and your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; can be simple and maintainable. As with every tool, you can go overboard easily and produce something that will haunt you for years to come.&lt;/p&gt;

&lt;p&gt;Find your sweet spot, and don’t forget what the people collaborating with you feel comfortable with. Just because you’re cool with a big plate of Makefile spaghetti it might not be the best idea to write everything in make. My personal take is that if you need scripts that are more complex than a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verb&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;noun&lt;/code&gt; combination (i.e. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go deploy production --version=latest&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make test&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go build&lt;/code&gt;) you might want to look into something different than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; - bash or your scripting language of choice being good options.&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/makefiles-for-accessibility/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/makefiles-for-accessibility/</guid>
				
			</item>
		
			<item>
				<title>Testing Ansible Provisioning Locally</title>
				        
				<pubDate>Fri, 14 Sep 2018 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;Whenever I need to provision servers I reach for bash scripts or use &lt;a href=&quot;https://www.ansible.com/&quot;&gt;Ansible&lt;/a&gt; to do the tedious work of installing packages and configuring services for me. In contrast to other provisioning tools both Ansible and bash have no built-in way to test that the scripts you’re writing actually do what you want them to do. Spinning up a real server in order to test your scripts, can either become expensive or simply annoying. Time to fix that.&lt;/p&gt;

&lt;p&gt;With the help two little tools, we can make local testing of provisioning scripts faster and more pleasant. It’s my go to way these days - there might be more sophisticated approaches out there but this is what works well for me (I’m not doing any rocket science anyways).&lt;/p&gt;

&lt;p&gt;We’re going to use &lt;a href=&quot;https://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt; to spin up a local VM, provision that VM with Ansible and then use &lt;a href=&quot;https://serverspec.org/&quot;&gt;Serverspec&lt;/a&gt; to verify that everything worked as intended.&lt;/p&gt;

&lt;h2 id=&quot;example-code-repository&quot;&gt;Example Code Repository&lt;/h2&gt;
&lt;p&gt;You can find a simple example of everything I describe here in my &lt;a href=&quot;https://github.com/hamvocke/ansible-local-testing-sample&quot;&gt;example repository on GitHub&lt;/a&gt;. Check it out, fork it and use it as a foundation for your next project.&lt;/p&gt;

&lt;h2 id=&quot;vagrant-setup&quot;&gt;Vagrant Setup&lt;/h2&gt;
&lt;p&gt;After you’ve &lt;a href=&quot;https://www.vagrantup.com/docs/installation/&quot;&gt;installed Vagrant&lt;/a&gt; on your machine you’re ready to spin up a virtual machine on your local computer.&lt;/p&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vagrantfile&lt;/code&gt; in our project root will configure Vagrant. With this file you declare the operating system image Vagrant should use for the VM. You can also configure networking and provide additional steps to provision the VM.&lt;/p&gt;

&lt;p&gt;The following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vagrantfile&lt;/code&gt; will make Vagrant spin up an Ubuntu machine and run Ansible during Vagrant’s provisioning step. Ansible will run on the VM, not on the host, as we’re using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ansible_local&lt;/code&gt;, not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ansible&lt;/code&gt; as our provisioner. After running Ansible, Vagrant will then use Serverspec to run our tests.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;Vagrant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;box&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ubuntu/xenial64&quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;provision&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ansible_local&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'all'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inventory_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'hosts'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;playbook&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'local.yml'&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;provision&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:serverspec&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'test/*_spec.rb'&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# pattern for test files&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Before we can use this configuration, we need to install the &lt;a href=&quot;https://github.com/vvchik/vagrant-serverspec&quot;&gt;vagrant-serverspec&lt;/a&gt; plugin:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ vagrant plugin install vagrant-serverspec
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;ansible-configuration&quot;&gt;Ansible Configuration&lt;/h2&gt;
&lt;p&gt;I like to use Ansible playbooks and roles, even if what I’m doing is quite small. In the example repository I’ve added a simple role that installs nginx on our virtual machine. This can be a good starting point for you to go crazy and add more steps to your roles, more roles and do whatever you have to do in order to provision your server.&lt;/p&gt;

&lt;h3 id=&quot;inventory&quot;&gt;Inventory&lt;/h3&gt;
&lt;p&gt;Ansible uses a so-called &lt;em&gt;inventory&lt;/em&gt; to find out which hosts to provision. For testing, we declare localhost (the &lt;em&gt;[local]&lt;/em&gt; block). We also declare all our other remote servers that we want to provision in this file (similar to the &lt;em&gt;[some-other-server&lt;/em&gt; block).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[local]
127.0.0.1 ansible_python_interpreter=/usr/bin/python3

[some-other-server]
&amp;lt;some_remote_ip&amp;gt; ansible_python_interpreter=/usr/bin/python3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;playbook&quot;&gt;Playbook&lt;/h3&gt;
&lt;p&gt;Playbooks are a way to tell Ansible what roles to apply to which hosts and how to connect to these hosts. For our local testing, we have a special playbook called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;local.yml&lt;/code&gt;. In our Vagrantfile we tell the Ansible provisioner to use this file as the playbook that should be executed for provisioning the VM.&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;local&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;local&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yes&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become_user&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;root&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nginx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we’ve configured &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ansible_local&lt;/code&gt; as the provisioner for Vagrant, we tell our playbook to use a local connection to the host declared with the name &lt;em&gt;local&lt;/em&gt;  in the Inventory (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hosts&lt;/code&gt; file). Remember, Ansible is executed on the VM directly, not on the host, that’s why we use a &lt;em&gt;local&lt;/em&gt; connection instead of &lt;em&gt;ssh&lt;/em&gt; here. Also, we define that our playbook should execute the &lt;em&gt;nginx&lt;/em&gt; role only.&lt;/p&gt;

&lt;p&gt;Besides the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;local.yml&lt;/code&gt; playbook, we can have multiple other playbooks that we can then use to tell Ansible how to provision our real servers and what roles to apply. I’ve added an example for remote server provisioning in the example repository.&lt;/p&gt;

&lt;h2 id=&quot;serverspec-tests&quot;&gt;Serverspec Tests&lt;/h2&gt;
&lt;p&gt;Vagrant and Ansible are set up and we have a simple Ansible role in place. It’s time to look at our Serverspec tests in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Change the tests according to your needs and provisioning steps. Make sure that all your test files end with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_spec.rb&lt;/code&gt; pattern so that our Vagrant provisioner can find them.&lt;/p&gt;

&lt;p&gt;This is what a simple test will look like:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require_relative&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'spec_helper'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'nginx'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_running&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_listening&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href=&quot;https://serverspec.org/resource_types.html&quot;&gt;Serverspec documentation&lt;/a&gt; gives you an overview over a lot of helpful resource types you can use for your tests.&lt;/p&gt;

&lt;h2 id=&quot;workflow&quot;&gt;Workflow&lt;/h2&gt;
&lt;p&gt;With this in place, you can go ahead, write your Ansible roles and test them properly with Serverspec.&lt;/p&gt;

&lt;p&gt;To test your provisioning scripts locally, simply use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant up&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant provision&lt;/code&gt; to spin up and provision your Vagrant VM. After a short while you’ll see the output of both, Ansible and Serverspec in your terminal and you’ll know if everything worked as intended or if there’s a problem with your ansible scripts:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PLAY [local] *******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [127.0.0.1]
TASK [nginx : Install packages] ************************************************
changed: [127.0.0.1] =&amp;gt; (item=[u'nginx'])
TASK [nginx : Restart nginx] ***************************************************
changed: [127.0.0.1]
PLAY RECAP *********************************************************************
127.0.0.1                  : ok=3    changed=2    unreachable=0    failed=0
==&amp;gt; default: Running provisioner: serverspec...
..
Finished in 0.53478 seconds (files took 0.08154 seconds to load)
2 examples, 0 failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once you’re sure that your provisioning scripts work correctly, you can provision your remote servers by calling Ansible with a different playbook:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ansible-playbook remote.yml -u root -i hosts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s all there is. Go ahead, provision and test all you can!&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/local-ansible-testing/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/local-ansible-testing/</guid>
				
			</item>
		
			<item>
				<title>A &quot;Doppelkopf&quot; Browser Game</title>
				        
				<pubDate>Sun, 26 Nov 2017 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;I grew up in the countryside of northern Germany. Growing up sorrounded by woods and fields you get to appreciate some rather traditional, maybe even old-fashioned parts of German culture. One of these things is learning to play card games like &lt;a href=&quot;https://en.wikipedia.org/wiki/Skat_%28card_game%29&quot;&gt;&lt;em&gt;“Skat”&lt;/em&gt;&lt;/a&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/Doppelkopf&quot;&gt;&lt;em&gt;“Doppelkopf”&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I remember my father and my uncles playing Doppelkopf for countless hours every year when we visited my grandmother (also an avid Doppelkopf player) for Christmas. Later at school, people played Skat or Doppelkopf in their breaks. Going to the pub you could sometimes spot people playing these games as well.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/skat.jpg&quot; alt=&quot;Die Skatpartie by Josef Wagner-Höhenberg&quot; /&gt;
&lt;em&gt;“Die Skatpartie” by Josef Wagner-Höhenberg&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Luckily, I learned the complex rules of Doppelkopf from my parents when I was a child. We played here and there. I was good enough to internalize the basic rules but never good enough that I could challenge more experienced players. Try playing with your grandparents and you’ll learn what losing looks like. After all, these folks have been playing that game all their lives. They’ve seen it all, have played every hand there is to play and recognize every tiny mistake you do. It’s intimidating.&lt;/p&gt;

&lt;p&gt;Earlier this year, some friends asked me if I wanted to join their Doppelkopf group in Hamburg. Knowing the basics of the game I was excited to join. Now we’re meeting once a week at a random pub or down at the harbour, have a beer or two and play Doppelkopf. It’s great fun and a nice breakout from my otherwise overly digitalised daily life. Every now and then a stranger stops by to &lt;a href=&quot;https://en.wiktionary.org/wiki/kibitz&quot;&gt;kibitz&lt;/a&gt;. They always seem fascinated or even nostalgic by the archaic scenery of people playing traditional card games these days.&lt;/p&gt;

&lt;p&gt;Doppelkopf is a complex game. It has a lot of rules, exceptions from these rules and the occasional exception from these exceptions. It’s best played with four players who form two different parties in each game (&lt;em&gt;Re&lt;/em&gt; and &lt;em&gt;Kontra&lt;/em&gt;). It’s all about taking tricks and getting the beter score for your party. To make it even more difficult, every group of players tends to have their very own set of extra rules. The game is full of jargon. For bystanders a conversation about the game simply sounds like a bunch of gibberish. Despite the steep learning curve it’s really rewarding to learn the game. The countless hours of fun and socializing really make up for it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/doppelkopf.jpg&quot; alt=&quot;Playing Doppelkopf in Hamburg&quot; /&gt;
&lt;em&gt;Playing Doppelkopf in a Cafe in Hamburg, not meant to be a shameless plug for Astra&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I have to admit that I kind of suck at Doppelkopf. My friends often kick my ass. I’m not good at memorizing all the special rules that are out there. I don’t dare to play a &lt;em&gt;Solo&lt;/em&gt; because I know I’ll screw up. I’m bad at tactics and I can’t remember which cards have already been played in the current game. Fortunately Doppelkopf is a team effort and you rarely play on your own in a game. So my friends often make up for my lack of skills.&lt;/p&gt;

&lt;p&gt;At one point I thought that I should have some practice to improve my game. As you might imagine, practising multiplayer game on your own is quite challenging. I looked out for Doppelkopf browser games and Android apps and sure enough there are plenty of them. Unfortunately almost none of them lived up to my expectations. They required you to register with your Facebook account, were full of ads or in-app purchases and required you to be online the entire time. I was rather looking for a no-frills, no-bullshit version. Something I could play as much as I’d like without being bugged with ads or having to fear about my personal activity being tracked with every step I take.&lt;/p&gt;

&lt;h2 id=&quot;ill-build-my-own-doppelkopf-game&quot;&gt;I’ll Build My Own Doppelkopf Game&lt;/h2&gt;

&lt;p&gt;Being a software developer I obviously found the best solution for this problem. &lt;em&gt;“I’m gonna build this myself!”&lt;/em&gt; was my proclaimed goal.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/doppelkopf-bender.jpg&quot; alt=&quot;I'll build my own game&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yeah, right, because that always works so well. Having quite a track record for starting side projects that I never finish (who hasn’t?) I know I’m probably lying to myself when I say that I’ll definitely finish that one. Still, I decided to build my own game, mainly for two reasons:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Implementing your own Doppelkopf game will teach you a lot about the game&lt;/li&gt;
  &lt;li&gt;I don’t get to do too much coding these days so a side project is more than welcome&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I also found a niche for my game to live in. Seeing all the ad-infested bells-and-whistles games with social media integration out there, I knew I should build a game that has nothing of that. I thought about the great &lt;a href=&quot;https://gabrielecirulli.github.io/2048/&quot;&gt;2048 game&lt;/a&gt; and how often I used to play it on my daily commute because it was free, simple, didn’t require any installation and allowed me to play even without an internet connection. I knew that my browser game should have similar goals. That’s why I decided that the Doppelkopf game I’m building should be&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;free (as in free beer), forever, no discussion&lt;/li&gt;
  &lt;li&gt;Open Source, available for everyone to see, modify and learn&lt;/li&gt;
  &lt;li&gt;without ads or in-app purchases&lt;/li&gt;
  &lt;li&gt;easy to start, ideally just loading a website&lt;/li&gt;
  &lt;li&gt;available and playable when you’re offline&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s a lot. Especially the offline part is giving me a headache as this means I’d need to build an AI for the other players. I’ve never done that one before so that’s going to be a nice challenge. Still, I’m certain that it’s worth it. I want the game to be as open and respectful of the user as possible. No bullshit, no screwing up the users.&lt;/p&gt;

&lt;h2 id=&quot;implementing-the-game&quot;&gt;Implementing the Game&lt;/h2&gt;

&lt;p&gt;Finding a tech stack was quite straightforward. As it should be an offline-first browser game there isn’t much technology to choose from. Back in the days I could have chosen Flash. Luckily, these days are over. I don’t want the user to install any plugins to play the game. They should just visit a website in their browser and be ready to play. This left JavaScript as the only option. It’s understood by every browser out there and has matured significantly over the recent years.&lt;/p&gt;

&lt;p&gt;I sensed my chance to refresh on my frontend JavaScript skills for this task. I knew I wanted to use the latest JavaScript features available but had to keep in mind that even modern browsers do not support all of these features yet. So I got my hands dirty and set up &lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack&lt;/a&gt; and &lt;a href=&quot;https://webpack.js.org/&quot;&gt;Babel&lt;/a&gt; to allow me to write the latest ECMAScript and to transpile it to JavaScript that today’s browsers can understand.&lt;/p&gt;

&lt;p&gt;Fortunately I had a short-cut to understanding the setup of these tools. Peter Jang has written an excellent &lt;a href=&quot;https://medium.com/@peterxjang/modern-javascript-explained-for-dinosaurs-f695e9747b70&quot;&gt;introduction to modern JavaScript&lt;/a&gt; that got me up and running in a breeze.&lt;/p&gt;

&lt;h2 id=&quot;the-card-game-kata&quot;&gt;The Card Game Kata&lt;/h2&gt;

&lt;p&gt;I quickly noticed that writing a card game as code makes for a fantastic &lt;a href=&quot;https://en.wikipedia.org/wiki/Kata_(programming)&quot;&gt;code kata&lt;/a&gt;. If you think of it as a domain modelling excercise it shapes up quite nicely.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;card&lt;/code&gt; has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;suite&lt;/code&gt; and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rank&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rank&lt;/code&gt; of a card defines it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deck&lt;/code&gt; consists of 40 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cards&lt;/code&gt; &lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;Each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;player&lt;/code&gt; has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hand&lt;/code&gt; of 10 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cards&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hand&lt;/code&gt; can be &lt;em&gt;Re&lt;/em&gt; or &lt;em&gt;Kontra&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trick&lt;/code&gt; goes to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;player&lt;/code&gt; who played the highest &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;card&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And so on.&lt;/p&gt;

&lt;p&gt;So far I’ve been busy capturing the essence of Doppelkopf in a domain model. With the help of &lt;a href=&quot;https://facebook.github.io/jest/&quot;&gt;Jest&lt;/a&gt; I worked on this in a strictly test-driven way. Being test-driven (and having set up a CI server) allowed me to work on my Doppelkopf game whenever I had a few minutes to spare. I could split the complex ruleset of Doppelkopf into hundreds of small-scoped bits and pieces that could be implemented within a couple of minutes. Having tests and a continuous integration server in place allows me to come back to where I left at any time.&lt;/p&gt;

&lt;p&gt;I’m taking some extra care of massaging my domain model into a shape that’s pleasant to use and easy to read. With a domain as tangible as a card game this has worked really well. Take a look at these code snippets to see what I’m talking about:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a hand without queen of clubs is kontra&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cards&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;queen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;suites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hand&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Hand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cards&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isKontra&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeTruthy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isRe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeFalsy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Hand&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cards&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;card&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;card&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;hand has a value&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cards&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;queen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;suites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;ten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;suites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hearts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;ace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;suites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;diamonds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hand&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Hand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cards&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These tests are easy to understand, even if you don’t know the rules of Doppelkopf. They serve as a good documentation, make it easy for me to reason about small portions of the complex game at a time and the sum of these small portions add up to the wonderful game that is Doppelkopf.&lt;/p&gt;

&lt;h2 id=&quot;moving-on&quot;&gt;Moving on&lt;/h2&gt;
&lt;p&gt;Right now my card browser game is only a bunch of domain classes and tests. There’s nothing visible and I’m not even talking about anything that’s remotely playable yet. Still, this excercise has been so much fun for me and allowed me to work in a pace that keeps me motivated to move on, one simple rule at a time. The source code is already &lt;a href=&quot;https://github.com/hamvocke/doppelkopf&quot;&gt;available on GitHub&lt;/a&gt;, feel free to check it out and track the progress.&lt;/p&gt;

&lt;p&gt;There will be huge challenges further down the road. When I told my friends that I’m building a Doppelkopf game, they first raised the question how I wanted to build an AI for singleplayer mode. Actually, I don’t have a clue. I’ve never done this before and don’t know how to approach this. I guess there’ll be some research for me to do and a long way until I have build something that is more clever than a bunch of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if-else&lt;/code&gt; statements.&lt;/p&gt;

&lt;p&gt;My friends also asked if there will ever be a multiplayer option for this game. This, however, is so far further down the road, that I’m not even thinking about it yet. I guess implementing multiplayer should be possible and is probably even easier than building a good enough AI. Still, for building a multiplayer version I’d first have to build a game that’s at least somewhat playable.&lt;/p&gt;

&lt;p&gt;I’m really excited about this side project. I’m in here for the challenge and hope that reasoning deeply about the game makes me a better Doppelkopf player after all. Let’s see how long I can keep this project alive and let’s keep fingers crossed that it doesn’t end up at the side project cemetary like all the other things I’ve successfully abandoned.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;At least in the version my friends and I play. We don’t play with nines. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/doppelkopf/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/doppelkopf/</guid>
				
			</item>
		
			<item>
				<title>E-book Release of Testing Microservices</title>
				        
				<pubDate>Thu, 28 Sep 2017 00:00:00 +0000</pubDate>

				
				<description>&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Ham… I opened that Testing Microservices blog post you bugged me with. It said “37 minutes read”. Then I opened the second post and it said “43 minutes read”. Then I closed my browser. Are you serious?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was the first feedback I received from &lt;a href=&quot;https://twitter.com/ManuelPuetz&quot;&gt;Manuel&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/lplotni&quot;&gt;Lukasz&lt;/a&gt;, two of my lovely coworkers. I guess they had a point.&lt;/p&gt;

&lt;p&gt;Yeah, I know. Things got a little out of hand when I wrote the last &lt;a href=&quot;/blog/testing-microservices&quot;&gt;blog post series&lt;/a&gt;. It’s a &lt;em&gt;little&lt;/em&gt; long and reading long blog posts might not be your thing. After receiving overly positive feedback from the folks who were persistent enough to read through the hughe wall of text online I figured out it makes sense to publish &lt;em&gt;Testing Microservices&lt;/em&gt; for more accessible offline reading.&lt;/p&gt;

&lt;p&gt;With the help of the fantastic &lt;a href=&quot;http://asciidoctor.org/&quot;&gt;Asciidoctor&lt;/a&gt; I published the article as an E-book.&lt;/p&gt;

&lt;p&gt;It’s all open source and &lt;a href=&quot;https://github.com/hamvocke/testing-microservices-ebook&quot;&gt;available on GitHub&lt;/a&gt; ready for you to download. Go ahead and grab the latest &lt;a href=&quot;https://github.com/hamvocke/testing-microservices-ebook/raw/master/testing-microservices.pdf&quot;&gt;PDF&lt;/a&gt;, &lt;a href=&quot;https://github.com/hamvocke/testing-microservices-ebook/raw/master/testing-microservices.epub&quot;&gt;EPUB&lt;/a&gt; or &lt;a href=&quot;https://github.com/hamvocke/testing-microservices-ebook/raw/master/testing-microservices.mobi&quot;&gt;MOBI&lt;/a&gt; version, send it to your e-reader and read the whole thing offline as often and as slow or fast as you like.&lt;/p&gt;

&lt;p&gt;If you spot any typos or mistakes I’d love if you’d send me a pull request.&lt;/p&gt;

&lt;h2 id=&quot;download-the-e-book&quot;&gt;Download the E-book&lt;/h2&gt;

&lt;div class=&quot;centered&quot;&gt;
    &lt;hr /&gt;
    &lt;a class=&quot;btn btn-primary&quot; href=&quot;https://github.com/hamvocke/testing-microservices-ebook/raw/master/testing-microservices.pdf&quot;&gt;PDF&lt;/a&gt;
    &lt;a class=&quot;btn btn-primary&quot; href=&quot;https://github.com/hamvocke/testing-microservices-ebook/raw/master/testing-microservices.epub&quot;&gt;EPUB&lt;/a&gt;
    &lt;a class=&quot;btn btn-primary&quot; href=&quot;https://github.com/hamvocke/testing-microservices-ebook/raw/master/testing-microservices.mobi&quot;&gt;MOBI&lt;/a&gt;
    &lt;hr /&gt;
&lt;/div&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

</description>
				<link>https://www.hamvocke.com/blog/ebook-testing-microservices/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/ebook-testing-microservices/</guid>
				
			</item>
		
			<item>
				<title>Testing Microservices — Java &amp; Spring Boot</title>
				        
				<pubDate>Tue, 19 Sep 2017 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/practical-test-pyramid.html&quot;&gt;&lt;img src=&quot;/assets/img/practicalPyramid.png&quot; alt=&quot;Practical Test Pyramid&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: This article has found a new home on Martin Fowler’s blog. Find a revamped, edited and more streamlined version under the new title &lt;a href=&quot;https://martinfowler.com/articles/practical-test-pyramid.html&quot;&gt;“The Practical Test Pyramid”&lt;/a&gt; on &lt;a href=&quot;https://martinfowler.com/articles/practical-test-pyramid.html&quot;&gt;martinfowler.com&lt;/a&gt;. Have fun!&lt;/p&gt;

&lt;div class=&quot;highlighted&quot;&gt;
  Prefer to read this on your e-reader? An older version of this article series is also available as an &lt;a href=&quot;/blog/ebook-testing-microservices/&quot;&gt;e-book&lt;/a&gt;.
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/testing-java-microservices/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/testing-java-microservices/</guid>
				
			</item>
		
			<item>
				<title>Testing Microservices</title>
				        
				<pubDate>Mon, 18 Sep 2017 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;&lt;a href=&quot;https://martinfowler.com/articles/practical-test-pyramid.html&quot;&gt;&lt;img src=&quot;/assets/img/practicalPyramid.png&quot; alt=&quot;Practical Test Pyramid&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: This article has found a new home on Martin Fowler’s blog. Find a revamped, edited and more streamlined version under the new title &lt;a href=&quot;https://martinfowler.com/articles/practical-test-pyramid.html&quot;&gt;“The Practical Test Pyramid”&lt;/a&gt; on &lt;a href=&quot;https://martinfowler.com/articles/practical-test-pyramid.html&quot;&gt;martinfowler.com&lt;/a&gt;. Have fun!&lt;/p&gt;

&lt;div class=&quot;highlighted&quot;&gt;
  Prefer to read this on your e-reader? An older version of this article series is also available as an &lt;a href=&quot;/blog/ebook-testing-microservices/&quot;&gt;e-book&lt;/a&gt;.
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/testing-microservices/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/testing-microservices/</guid>
				
			</item>
		
			<item>
				<title>Remote Pair Programming Made Easy with SSH and tmux</title>
				        
				<pubDate>Tue, 03 Nov 2015 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Pair_programming&quot;&gt;Pair Programming&lt;/a&gt; has found wide adoption in software development ever since it became popular with the rise of Extreme Programming and other agile development approaches. This practice where two developers are working on the same machine and the same task has some really neat advantages over working all by yourself. Working in pairs results in higher quality, spreads knowledge between your team members and ultimately leads to higher satisfaction. Sounds cool? Well, it is!&lt;/p&gt;

&lt;p&gt;However, pair programming often becomes difficult as soon as the development team is spread accross different locations. People might be working from home. Parts of your team might be located at a different office, maybe even in an entirely different country.&lt;/p&gt;

&lt;p&gt;The idea of pair programming has been around for more than a decade by now. A lot of companies and products have emerged (and vanished!) over time to make remote pair programming easier. Different solutions for different needs. From fully fledged screen sharing and collaboration solutions like &lt;a href=&quot;https://pop.com/home&quot;&gt;Pop&lt;/a&gt; (formerly “Screenhero” which got then acquired by Slack), over shared &lt;a href=&quot;https://en.wikipedia.org/wiki/Virtual_Network_Computing&quot;&gt;VNC&lt;/a&gt; sessions to IDE and editor plugins like &lt;a href=&quot;https://code.visualstudio.com/learn/collaboration/live-share&quot;&gt;VS Code’s Live Share&lt;/a&gt; or &lt;a href=&quot;https://www.jetbrains.com/code-with-me/&quot;&gt;JetBrains’ Code With Me&lt;/a&gt;, there are a lot of solutions for remote collaboration on code.&lt;/p&gt;

&lt;p&gt;If you don’t need all those bells and whistles, if you like to keep control over where your data is going, or if you’re just a weirdo who loves inconvenient things, you can use a much more low-fi and terminal-based solution to collaborate on your code. A simple combination of &lt;strong&gt;SSH&lt;/strong&gt; and &lt;strong&gt;tmux&lt;/strong&gt;&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; is all we need to setup a really effective and lightweight remote pair programming environment. We can use all of our beloved command line tools with finely tuned dotfiles and pat ourselves on the backs for working the way our grandparents intended.&lt;/p&gt;

&lt;h2 id=&quot;what-are-we-going-to-do&quot;&gt;What are we going to do?&lt;/h2&gt;
&lt;p&gt;Let’s imagine we have two developers, &lt;em&gt;Alice&lt;/em&gt; and &lt;em&gt;Bob&lt;/em&gt;. They want to collaborate on a task and since they both are comfortable using the command line they decide to set up a shared terminal environment to work together.&lt;/p&gt;

&lt;p&gt;Alice and Bob connect to the same machine using SSH. They decide to use a dedicated pairing server that both of them &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt; into. Setting up a server with SSH access on &lt;a href=&quot;https://www.digitalocean.com/&quot;&gt;DigitalOcean&lt;/a&gt; or &lt;a href=&quot;https://aws.amazon.com/&quot;&gt;AWS&lt;/a&gt; is a no-brainer nowadays. They simply add their &lt;em&gt;public keys&lt;/em&gt; to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/authorized_keys&lt;/code&gt; file and then can connect securely without needing a password.&lt;/p&gt;

&lt;p&gt;Alternatively they cold also designate Alice’s or Bob’s machine as the pairing host. In this case the respective other person has to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt; into the other dev’s machine and they’re set.&lt;/p&gt;

&lt;p&gt;Once they are connected to the same machine, they can use tmux for a shared environment. tmux’s client-server architecture allows multiple clients to connect to the same sessions on a server (we’ve got all that session handling stuff covered in the &lt;a href=&quot;/blog/a-quick-and-easy-guide-to-tmux/&quot;&gt;intro guide&lt;/a&gt;). That’s perfect for our plans. We can have one session that holds all the windows and panes and can connect one client for each developer.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;space-bottom&quot; src=&quot;/assets/img/uploads/ssh_tmux_simple.png&quot; alt=&quot;synchronized session sharing with tmux&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;sharing-a-tmux-session&quot;&gt;Sharing a tmux session&lt;/h2&gt;
&lt;p&gt;The simplest setup is using the exact same session with multiple tmux client instances. The following steps will get us there:&lt;/p&gt;

&lt;div class=&quot;highlighted&quot;&gt;
&lt;ol&gt;
  &lt;li&gt;Alice and Bob &lt;code&gt;ssh&lt;/code&gt; into the same server&lt;/li&gt;
  &lt;li&gt;Alice creates a new tmux sesssion: &lt;code&gt;tmux new -s shared&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Bob connects to that session: &lt;code&gt;tmux attach -t shared&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

&lt;p&gt;Please note that &lt;em&gt;“shared”&lt;/em&gt; will be the name of the session, feel free to give it any name you like.&lt;/p&gt;

&lt;p&gt;From here Alice and Bob can happily hack away on their terminal and make use of all the fancy features offered by tmux. They can create panes and windows, launch different command line applications and pair happily on their tasks. They can even detach from that session and return at any later point. Both will see the exact same output in their respective terminal window.&lt;/p&gt;

&lt;p&gt;This is what it will look like in action:&lt;/p&gt;

&lt;video src=&quot;/assets/video/ssh_tmux_simple.webm&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; controls=&quot;&quot;&gt;&lt;/video&gt;

&lt;p&gt;But somehow Alice and Bob feel that this is not quite perfect. There are situations where they want to work on different stuff while still being in that session. But as soon as Alice switches to a different window to work on her tasks, Bob’s terminal will also switch along.&lt;/p&gt;

&lt;h2 id=&quot;independent-window-switching&quot;&gt;Independent window switching&lt;/h2&gt;
&lt;p&gt;Instead of sharing the exact same session between multiple tmux clients, we can also create multiple session within the same window group. The result is similar to what we’ve seen above with one difference: Each developer can switch tmux windows independently.&lt;/p&gt;

&lt;p&gt;All contents of the windows will be synchronized between all clients. But each client can decide individually which window’s content should be shown at the moment. This allows Alice and Bob to work independently on different tasks if they feel the need to do so. Whenever they want to go back to normal pairing they can switch back to the same tmux window and will see the same content again.&lt;/p&gt;

&lt;p&gt;This is how independent window switching will look like in action:&lt;/p&gt;
&lt;video src=&quot;/assets/video/ssh_tmux_advanced.webm&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; controls=&quot;&quot;&gt;&lt;/video&gt;

&lt;p&gt;The steps for this setup are a little different:&lt;/p&gt;

&lt;div class=&quot;highlighted&quot;&gt;
&lt;ol&gt;
  &lt;li&gt;Again, Alice and Bob &lt;code&gt;ssh&lt;/code&gt; into the same server&lt;/li&gt;
  &lt;li&gt;Alice, as before, creates a new tmux session: &lt;code&gt;tmux new -s alice&lt;/code&gt;. tmux will implicitly create a new &lt;strong&gt;window group&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Bob does not join that same session. Instead he starts a &lt;strong&gt;new session&lt;/strong&gt; and connects that session to the same &lt;strong&gt;window group&lt;/strong&gt; as Alice’s session: &lt;code&gt;tmux new -s bob -t alice&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;p&gt;That’s it. Now both can move between tmux windows independently. The content (including panes) within those windows will be synchronized between all clients.&lt;/p&gt;

&lt;p&gt;If you want to get a feeling for what’s happening behind the scenes you can simply look up what sessions and window groups have been created after Alice has created her session. A simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux ls&lt;/code&gt; will reveal what’s happening:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bob: 2 windows (created Mon Nov  2 22:51:24 2015) [80x23] (group 0) (attached)
alice: 2 windows (created Mon Nov  2 22:50:36 2015) [80x23] (group 0) (attached)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, there are two sessions with their respective name. Both sessions are in the same group &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(group 0)&lt;/code&gt; and therefore share the same windows.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;space-bottom&quot; src=&quot;/assets/img/uploads/ssh_tmux_advanced.png&quot; alt=&quot;independent shared sessions with tmux&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;benefits-and-drawbacks&quot;&gt;Benefits and drawbacks&lt;/h2&gt;
&lt;p&gt;To me this is a really nice and lightweight solution if you want to collaborate remotely. You can use it for pair programming, to troubleshoot issues on your servers together and much more. However, you need to be aware that this is a solution with a lot of restrictions. You’re completely bound to the command line and its tools, there’s no way around it. You also need to have a separate channel to talk to each other&lt;/p&gt;

&lt;p&gt;If you are looking for a fully-fledged solution that allows you to use tools outside of the command line and also includes audio and video conferencing, one of the previously mentioned tools and services might be better suited for you. But if you need something really lightweight that you can control completely on your own and are not afraid of the command line, this setup might be perfect for you.&lt;/p&gt;

&lt;p&gt;One last honorable mention goes out to &lt;a href=&quot;http://tmate.io/&quot;&gt;tmate.io&lt;/a&gt;. Tmate is a service that creates the setup I’ve just described to you in an ad-hoc fashion. If you want to avoid the (quite small) hassle of setting up your own ssh server, tmate might be interesting for you.&lt;/p&gt;

&lt;p&gt;If you have any further experience or opinions feel free to share them with us in the comments section!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;If you don’t feel familiar with tmux or need a quick refresh take a look at my &lt;a href=&quot;/blog/a-quick-and-easy-guide-to-tmux/&quot;&gt;introductory guide to tmux&lt;/a&gt;. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/remote-pair-programming-with-tmux/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/remote-pair-programming-with-tmux/</guid>
				
			</item>
		
			<item>
				<title>Fun and Useless Tools for Your Command Line</title>
				        
				<pubDate>Sun, 25 Oct 2015 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;Ah, the command line. Home of ancient power tools with text-only interfaces, loved by geeks, avoided by everyone else. Did I already mention, that I love the command line? (Oh yes, &lt;a href=&quot;/blog/a-quick-and-easy-guide-to-tmux/&quot;&gt;most certainly&lt;/a&gt;). Superficially the command line looks plain and boring and I can totally understand why people are reluctant spending any time there while everything else is nice and shiny these days. But behold! There are some really nice gimmicks to make your command line experience more fun. Don’t ask for the value of these, there probably is none. But maybe that’s why it’s so fun. These are some of my favorite useless command line applications that I keep showing to people who actually don’t want to know.&lt;/p&gt;

&lt;h2 id=&quot;cowsay&quot;&gt;Cowsay&lt;/h2&gt;
&lt;p&gt;This is a real classic. &lt;strong&gt;Cowsay&lt;/strong&gt; uses ASCII art to create a nice cow with a speech bubble that’s filled with any text you like. Cowsay is available for Linux and Mac and can easily be installed with your favorite package manager. After that your ASCII cow fun is only a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cowsay yourTextHere&lt;/code&gt; away:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/cowsay.jpg&quot; alt=&quot;Cowsay in action&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you feel extra fancy you can make cowsay display other stuff than just plain cows. Cowsay uses &lt;em&gt;cowfiles&lt;/em&gt; that serve as templates for your cowsay output. Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cowsay -f &amp;lt;cowfile&amp;gt; yourText&lt;/code&gt; you can tell cowsay to use a different template. To see which cowfiles are available simply run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cowsay -l&lt;/code&gt; and see what’s available. You want Tux instead of a cow? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cowsay -f tux&lt;/code&gt; is here to save your day.&lt;/p&gt;

&lt;p&gt;Did you know that &lt;a href=&quot;http://www.ansible.com&quot;&gt;Ansible&lt;/a&gt; automatically detects if you have cowsay installed? If it finds a cowsay installation on your system it will use it by default for all its log messages. &lt;a href=&quot;https://github.com/ansible/ansible/blob/86de1429e57c0ec3c40a6c5bd2c1808ce78b48a4/lib/ansible/utils/display.py#L82-L105&quot;&gt;Here’s how&lt;/a&gt; they’re doing it. Awesome stuff, Ansible!&lt;/p&gt;

&lt;h2 id=&quot;sl--the-command-line-steam-locomotive&quot;&gt;sl – the command line steam locomotive&lt;/h2&gt;
&lt;p&gt;Ever felt like being too productive? Or maybe you want to annoy some of your colleagues? &lt;strong&gt;sl&lt;/strong&gt; is here to save your day. This little command is invoked by typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sl&lt;/code&gt; into your command line. Looks pretty similar to mistyping &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt;, huh? Well, that’s the point. If you have sl installed (again, available through your package manager), mistyping &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sl&lt;/code&gt; will no longer show an error message but present you a slowly moving ASCII art locomotive driving smoothly through your terminal window. Want to interrupt it using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl c&lt;/code&gt;? Nope, not gonna happen, you have to wait until completely passed your terminal.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/sl.gif&quot; alt=&quot;sl&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;lolcat--like-cat-but-with-rainbows&quot;&gt;lolcat – like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat&lt;/code&gt; but with rainbows&lt;/h2&gt;
&lt;p&gt;I know the feeling, sometimes your command line simply lacks color. What could be better to fight this feeling than lovely rainbows? &lt;strong&gt;&lt;a href=&quot;https://github.com/busyloop/lolcat&quot;&gt;lolcat&lt;/a&gt;&lt;/strong&gt; has you covered. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lolcat&lt;/code&gt; acts exactly like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat&lt;/code&gt; which you can use to print text to your command line. The difference: lolcat will make all your text rainbow colored.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/lolcat.jpg&quot; alt=&quot;lolcat&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of course you can also use it in combination with pipes. A simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem install lolcat&lt;/code&gt; will bring this piece of rainbow-awesomeness to your machine.&lt;/p&gt;

&lt;h2 id=&quot;figlet---create-ascii-banners-from-your-command-line&quot;&gt;figlet - create ASCII banners from your command line&lt;/h2&gt;
&lt;p&gt;I have a knack for ASCII art. Seriously. That’s why I love to play around with &lt;strong&gt;figlet&lt;/strong&gt; so much. Figlet creates big ASCII art characters from your input text. You can choose between many different fonts and create something really awesome in no time. Once again available through your favorite package manager, figlet will simply take your desired text as input an create beautiful ASCII art out of it. Just call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;figlet yourText&lt;/code&gt; to get started.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/figlet.jpg&quot; alt=&quot;figlet&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Want to see which other fonts are available? Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;showfigfonts&lt;/code&gt; to get a preview of all the fonts that are installed on your system.&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/commandline-fun/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/commandline-fun/</guid>
				
			</item>
		
			<item>
				<title>Making tmux Pretty and Usable - A Guide to Customizing your tmux.conf</title>
				        
				<pubDate>Mon, 17 Aug 2015 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;In my &lt;a href=&quot;/blog/a-quick-and-easy-guide-to-tmux&quot;&gt;previous blog post&lt;/a&gt; I gave a quick and easy introduction to tmux and explained how to use tmux with a basic configuration.&lt;/p&gt;

&lt;p&gt;If you’ve followed that guide you might have had a feeling that many people have when working with tmux for the first time: “These key combinations are really awkward!”. Rest assured, you’re not alone. Judging from the copious blog posts and dotfiles repos on GitHub there are many people out there who feel the urge to make tmux behave a little different; to make it more comfortable to use.&lt;/p&gt;

&lt;p&gt;And actually it’s quite easy to customize the look and feel of tmux. Let me tell you something about the basics of customizing tmux and share some of the configurations I find most useful.&lt;/p&gt;

&lt;h2 id=&quot;customizing-tmux&quot;&gt;Customizing tmux&lt;/h2&gt;
&lt;p&gt;Customizing tmux is as easy as editing a text file. tmux uses a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux.conf&lt;/code&gt; to store its configuration. If you store that file as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.tmux.conf&lt;/code&gt; (&lt;strong&gt;Note:&lt;/strong&gt; there’s a period as the first character in the file name. It’s a hidden file) tmux will pick this configuration file for your current user. If you want to share a configuration for multiple users (e.g. if you should feel the urge to start tmux as super user (please think about this carefully!)) you can also put your tmux.conf into a system-wide directory. The location of this directory will be different accross different operating systems. The man page (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man tmux&lt;/code&gt;) will tell you the exact location, just have a look at documentation for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-f&lt;/code&gt; parameter.&lt;/p&gt;

&lt;h3 id=&quot;less-awkward-prefix-keys&quot;&gt;Less awkward prefix keys&lt;/h3&gt;
&lt;p&gt;Probably the most common change among tmux users is to change the &lt;strong&gt;prefix&lt;/strong&gt; from the rather awkward &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b&lt;/code&gt; to something that’s a little more accessible. Personally I’m using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-a&lt;/code&gt; instead but note that this might interfere with bash’s “go to beginning of line” command&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. On top of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-a&lt;/code&gt; binding I’ve also remapped my Caps Lock key to act as Ctrl since I’m not using Caps Lock anyways. This allows me to nicely trigger my prefix key combo.&lt;/p&gt;

&lt;p&gt;To change your prefix from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-a&lt;/code&gt;, simply add following lines to your tmux.conf:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# remap prefix from 'C-b' to 'C-a'
unbind C-b
set-option -g prefix C-a
bind-key C-a send-prefix
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;sane-split-commands&quot;&gt;Sane Split Commands&lt;/h3&gt;
&lt;p&gt;Another thing I personally find quite difficult to remember is the pane splitting commands. I mean, seriously? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&lt;/code&gt; to split vertically and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt; to split horizontally? Who’s supposed to memorize that? I find it helpful to have the characters as a visual representation of the split, so I chose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt; for splitting panes:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# split panes using | and -
bind | split-window -h
bind - split-window -v
unbind '&quot;'
unbind %
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;easy-config-reloads&quot;&gt;Easy Config Reloads&lt;/h3&gt;
&lt;p&gt;Since I’m experimenting quite often with my tmux.conf I want to reload the config easily. This is why I have a command to reload my config on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# reload config file (change file location to your the tmux.conf you want to use)
bind r source-file ~/.tmux.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;fast-pane-switching&quot;&gt;Fast Pane-Switching&lt;/h3&gt;
&lt;p&gt;Switching between panes is one of the most frequent tasks when using tmux. Therefore it should be as easy as possible. I’m not quite fond of triggering the prefix key all the time. I want to be able to simply say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M-&amp;lt;direction&amp;gt;&lt;/code&gt; to go where I want to go (remember: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt; is for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Meta&lt;/code&gt;, which is usually your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt&lt;/code&gt; key). With this modification I can simply press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt-left&lt;/code&gt; to go to the left pane (and other directions respectively):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# switch panes using Alt-arrow without prefix
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;mouse-mode&quot;&gt;Mouse mode&lt;/h3&gt;
&lt;p&gt;Although tmux clearly focuses on keyboard-only usage (and this is certainly the most efficient way of interacting with your terminal) it can be helpful to enable mouse interaction with tmux. This is especially helpful if you find yourself in a situation where others have to work with your tmux config and naturally don’t have a clue about your key bindings or tmux in general. Pair Programming might be one of those occasions where this happens quite frequently.&lt;/p&gt;

&lt;p&gt;Enabling mouse mode allows you to select windows and different panes by simply clicking on them. I’ve found that this might mess a little bit with simply selecting text in your terminal using the mouse. You might experience the same, depending on your environment. So you should consider if this configuration is something that’s worth it for your use case:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Enable mouse control (clickable windows, panes, resizable panes)
set -g mouse-select-window on
set -g mouse-select-pane on
set -g mouse-resize-pane on
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Update for tmux 2.1&lt;/strong&gt;:&lt;br /&gt;
As Jon Lillie pointed out in the comments, mouse mode has been &lt;a href=&quot;https://github.com/tmux/tmux/blob/master/CHANGES#L6-L13&quot;&gt;rewritten in tmux 2.1&lt;/a&gt;. Once you are on tmux 2.1 (or later) you can activate the new mouse mode with a single command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Enable mouse mode (tmux 2.1 and above)
set -g mouse on
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The new mode is a combination of all the old mouse options and fixes the text selection issues as well.&lt;/p&gt;

&lt;h3 id=&quot;stop-renaming-windows-automatically&quot;&gt;Stop renaming windows automatically&lt;/h3&gt;
&lt;p&gt;I like to give my tmux windows custom names using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt; key. This helps me naming my windows according to the context they’re focusing on. By default tmux will update the window title automatically depending on the last executed command within that window. In order to prevent tmux from overriding my wisely chosen window names I want to suppress this behavior:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# don't rename windows automatically
set-option -g allow-rename off
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;changing-the-look-of-tmux&quot;&gt;Changing the look of tmux&lt;/h2&gt;
&lt;p&gt;Changing the colors and design of tmux is a little more complex than what I’ve presented so far. You’ll want tmux to give a consistent look which is why you most likely have to change the looks of quite a lot of elements tmux displays. This is why changes to the design often result in plenty of lines in your config. I can only recommend to put these into their own identifiable section within your tmux.conf to be able to change this block of config without accidentaly ripping out some of your precious custom key bindings. I’m using comments, starting with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&lt;/code&gt; character to make it visible where the design changes start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Credit where credit is due:&lt;/strong&gt; I did not create the following design. &lt;a href=&quot;https://www.reddit.com/user/dothebarbwa&quot;&gt;/u/dothebarbwa&lt;/a&gt; was so kind to &lt;a href=&quot;https://www.reddit.com/r/unixporn/comments/3cn5gi/tmux_is_my_wm_on_os_x/&quot;&gt;publish&lt;/a&gt; it on &lt;a href=&quot;https://www.reddit.com/r/unixporn&quot;&gt;/r/unixporn&lt;/a&gt; so it’s his effort and all thanks have to go out to him. Thanks!&lt;/p&gt;

&lt;p&gt;Depending on your color scheme (I’m using &lt;a href=&quot;https://github.com/chriskempson/base16&quot;&gt;base16-ocean-dark&lt;/a&gt;) your resulting tmux will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/tmux_custom.jpg&quot; alt=&quot;themed tmux&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;######################
### DESIGN CHANGES ###
######################

# loud or quiet?
set -g visual-activity off
set -g visual-bell off
set -g visual-silence off
setw -g monitor-activity off
set -g bell-action none

#  modes
setw -g clock-mode-colour colour5
setw -g mode-style 'fg=colour1 bg=colour18 bold'

# panes
set -g pane-border-style 'fg=colour19 bg=colour0'
set -g pane-active-border-style 'bg=colour0 fg=colour9'

# statusbar
set -g status-position bottom
set -g status-justify left
set -g status-style 'bg=colour18 fg=colour137 dim'
set -g status-left ''
set -g status-right '#[fg=colour233,bg=colour19] %d/%m #[fg=colour233,bg=colour8] %H:%M:%S '
set -g status-right-length 50
set -g status-left-length 20

setw -g window-status-current-style 'fg=colour1 bg=colour19 bold'
setw -g window-status-current-format ' #I#[fg=colour249]:#[fg=colour255]#W#[fg=colour249]#F '

setw -g window-status-style 'fg=colour9 bg=colour18'
setw -g window-status-format ' #I#[fg=colour237]:#[fg=colour250]#W#[fg=colour244]#F '

setw -g window-status-bell-style 'fg=colour255 bg=colour1 bold'

# messages
set -g message-style 'fg=colour232 bg=colour16 bold'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;a-word-of-caution&quot;&gt;A Word of Caution&lt;/h2&gt;
&lt;p&gt;I took care of explaining and documenting all suggested changes in this post to make it easy for you to understand what they do and to decide if this is something you want for your tmux.conf as well.&lt;/p&gt;

&lt;p&gt;If you do your amount of research on the web you will find plenty of heavily customized tmux configurations. It’s really tempting to just copy those and call it a day. Please, for your own sake, don’t do that. Trust me, I’ve been there. I can only recommend that you start out with a plain tmux configuration and add modifications one by one. This is the only way to ensure that you are fully conscious of all the changes you have made. And this is the only way you will actually learn something about tmux along the way. That said: go ahead and look up config files others have published. Take these as source of inspiration and choose wisely what you want to take for your own config.&lt;/p&gt;

&lt;p&gt;There is some really interesting stuff out there. I’ve seen people doing pure magic with their status bars, displaying all kinds of system information that might be interesting. To apply those changes you’ll most likely exceed the simple one-liners I’ve presented in this post. Often there are special scripts involved that need to be loaded, accompanied by multiple lines of configuration changes. I don’t want to discourage you from using these. Just be aware that this is a more advanced topic where you can certainly screw some stuff up. Make sure to backup your config accordingly.&lt;/p&gt;

&lt;h2 id=&quot;further-resources&quot;&gt;Further resources&lt;/h2&gt;
&lt;p&gt;As I’ve already told you, there are plenty of resources out there where you can find people presenting their tmux.confs in a similar fashion to what I’ve done here. Feel free to browse and search for inspiration. Personally I love reading other people’s blog posts about their tmux configs.&lt;/p&gt;

&lt;p&gt;GitHub is also a great source. Simply search for &lt;em&gt;“tmux.conf”&lt;/em&gt; or repos called &lt;em&gt;“dotfiles”&lt;/em&gt; to find a vast amount of configurations that are out there.&lt;/p&gt;

&lt;p&gt;If you’re especially looking for theming options, I can also recommend having a look at &lt;a href=&quot;https://reddit.com/r/unixporn&quot;&gt;/r/unixporn&lt;/a&gt; (SFW, in spite of its title). It’s a great place where people showcase their fine-tuned and heavily themed unix environments. Some stuff is really nice, some other stuff is only pretty but mostly dysfunctional. From time to time you find people sharing their tmux.conf as well, you can also deliberately search for the term “tmux.conf” to find what you’re looking for.&lt;/p&gt;

&lt;p&gt;You can also find my complete tmux.conf (along with other configuration files I’m using on my systems) on my personal &lt;a href=&quot;https://github.com/hamvocke/dotfiles&quot;&gt;dotfiles repo&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;although you can still invoke “go to beginning of line” by typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-a C-a&lt;/code&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/a-guide-to-customizing-your-tmux-conf/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/a-guide-to-customizing-your-tmux-conf/</guid>
				
			</item>
		
			<item>
				<title>A Quick and Easy Guide to tmux</title>
				        
				<pubDate>Sun, 16 Aug 2015 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;I love working with the command line. I think there’s hardly any more productive and versatile tool for a software developer than the terminal. The additional hacker/wizard/neckbeard kind of feeling you get when using a terminal comes for free, what’s not to love?&lt;/p&gt;

&lt;p&gt;Over the years I’ve tried to streamline and customize my command line experience to be more convenient, more fun to use or just to look rad. One of the most important tools to drive my daily command line experience is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt;. Check this out:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/tmux.png&quot; alt=&quot;tmux in action&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This screenshot shows nothing less than the best thing since sliced bread. It’s &lt;a href=&quot;https://tmux.github.io/&quot;&gt;tmux&lt;/a&gt;, a so-called &lt;em&gt;terminal multiplexer&lt;/em&gt;. Simply speaking, tmux acts as a window manager within your terminal&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; and allows you to create multiple windows and panes within a single terminal window.&lt;/p&gt;

&lt;p&gt;This post will give you the same quick introduction to tmux and its possibilities, followed by the a 10 minute hands-on guide to set up and get to know tmux yourself. If you’ve got 10 minutes to spare and want to earn street cred with your nerd friends: read on and become proficient with tmux!&lt;/p&gt;

&lt;h2 id=&quot;whats-tmux&quot;&gt;What’s tmux?&lt;/h2&gt;
&lt;p&gt;tmux’s authors describe it as a &lt;em&gt;terminal multiplexer&lt;/em&gt;. Behind this fancy term hides a simple concept: Within one terminal window you can open multiple windows and split-views (called &lt;em&gt;“panes”&lt;/em&gt; in tmux lingo). Each pane will contain its own, independently running shell instance (bash, zsh, whatever you’re using). This allows you to have multiple terminal commands and applications running side by side without the need to open multiple terminal emulator windows.&lt;/p&gt;

&lt;p&gt;On top of that tmux keeps these windows and panes in a &lt;em&gt;session&lt;/em&gt;. You can exit a session at any point. This is called &lt;em&gt;“detaching”&lt;/em&gt;. tmux will keep this session alive until you kill the tmux server (e.g. when you reboot)&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. This is incredibly useful because at any later point in time you can pick that session up exactly from where you left it by simply &lt;em&gt;“attaching”&lt;/em&gt; to that session.&lt;/p&gt;

&lt;p&gt;If you’ve ever worked with remote servers or a Raspberry Pi over ssh you can guess where this will be useful: When you lose your ssh connection the tmux session will simply be detached but will keep running on the server in the background including all the processes that run within your session. To continue your session simply ssh to the server again and attach to the running session.&lt;/p&gt;

&lt;p&gt;tmux is helpful when working on a remote machine but it shines just as much when you’re working locally. Not only for its window management features but also for the session handling. Personally I find myself detaching from sessions when I’m switching context. I’ll just start a new session for my new task and attach to the old session whenever I want to continue with my old task.&lt;/p&gt;

&lt;p&gt;You see that tmux basically offers two big features:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Window management in your terminal&lt;/li&gt;
  &lt;li&gt;and session management&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are familiar with &lt;a href=&quot;https://www.gnu.org/software/screen&quot;&gt;GNU Screen&lt;/a&gt; this might all sound familiar. Think of tmux as an easier-to-use and a little more powerful alternative to Screen (obviously I’m being opinionated here).&lt;/p&gt;

&lt;p&gt;Enough with the concepts. Let’s get our hands dirty!&lt;/p&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;This hands-on guide will get you up and running with tmux pretty quickly. It will only cover the basic features which should be more than enough to get started and be productive with tmux. Simply open your terminal and follow the instructions.&lt;/p&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;

&lt;p&gt;Fortunately installing tmux is pretty straightforward on most operating systems: a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt-get install tmux&lt;/code&gt; (Ubuntu, WSL and derivatives) or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew install tmux&lt;/code&gt; (Mac) should be sufficient.&lt;/p&gt;

&lt;h3 id=&quot;starting-your-first-session&quot;&gt;Starting Your First Session&lt;/h3&gt;
&lt;p&gt;For your first session simply start &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; with a fresh session:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tmux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will create a new tmux session with a nice all-green status bar at the bottom:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/tmux_blank.png&quot; alt=&quot;vanilla tmux on startup&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The status bar is an important part of tmux. Apart from the currently opened windows (on the left) it also shows some system information like date and time (on the right). The status bar can also be customized and I’ve seen some really fancy stuff around (upcoming calendar events, battery status, to name a few) but this is something we’ll leave for later.&lt;/p&gt;

&lt;h3 id=&quot;splitting-panes&quot;&gt;Splitting Panes&lt;/h3&gt;
&lt;p&gt;Now that we’ve created our first session we can get a feeling for panes. When you create a new session, tmux will by default start with one window and a single panel inside. We want a nice split-screen, so let’s split this bad boy.&lt;/p&gt;

&lt;p&gt;All commands in tmux are triggered by a &lt;strong&gt;prefix key&lt;/strong&gt; followed by a &lt;strong&gt;command key&lt;/strong&gt; (all you &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;emacs&lt;/code&gt; weirdos out there will feel right at home). By default, tmux uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b&lt;/code&gt; as prefix key. This notation might read a little weird if you’re not used to it. In “emacs” notation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-&lt;/code&gt; means “press and hold the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl&lt;/code&gt; key”&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. Thus &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b&lt;/code&gt; simply means press the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; keys at the same time.&lt;/p&gt;

&lt;p&gt;The shortcut to split panes into a left and a right pane is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b %&lt;/code&gt;. This means: to split your single pane into a left and a right pane you press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; at the same time, release both, and then type the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt; key. Voilà! You’ve just invoked your first tmux command and split your pane in two.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/tmux_split.png&quot; alt=&quot;tmux with two split panes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Where there’s a split into left and right, there’s also a split into top and bottom pane. To split a pane into top and bottom panes use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b &quot;&lt;/code&gt; shortcut.&lt;/p&gt;

&lt;h3 id=&quot;navigating-panes&quot;&gt;Navigating Panes&lt;/h3&gt;
&lt;p&gt;Right now we’re trapped in the newly created pane. But we really really want to go back to the left one. Easy peasy: Switching to a different pane uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b &amp;lt;arrow key&amp;gt;&lt;/code&gt; shortcut, where &amp;lt;arrow key&amp;gt; is the arrow key pointing to the pane you want to switch to. In our case we want to switch to the panel on the left so it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b left&lt;/code&gt; for us. Just once more, so that we fully understand this: This means you press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; (your prefix) followed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;left&lt;/code&gt; arrow key to get to the pane on the left.&lt;/p&gt;

&lt;p&gt;You can now go ahead and split each of your new panels even further. Feel free to experiment and split your panes like a maniac to get a feeling for it.&lt;/p&gt;

&lt;h3 id=&quot;closing-panes&quot;&gt;Closing Panes&lt;/h3&gt;
&lt;p&gt;Closing a pane is as simple as closing a regular terminal session. Either type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exit&lt;/code&gt; or hit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl-d&lt;/code&gt; and it’s gone.&lt;/p&gt;

&lt;h3 id=&quot;creating-windows&quot;&gt;Creating Windows&lt;/h3&gt;
&lt;p&gt;Windows in tmux can be compared to creating new virtual desktops; if you’ve ever worked with one of the major Linux desktop environments (KDE, Gnome) or a Mac you’ll hopefully find this analogy helpful.&lt;/p&gt;

&lt;p&gt;Creating new windows is as easy as typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b c&lt;/code&gt; (one last time: that’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; at once, then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c&lt;/code&gt;). The new window will then be presented to you in tmux’s status bar.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/tmux_window.png&quot; alt=&quot;tmux with two windows&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can now divide the pane in your new window as you like. Or don’t. That’s up to you.&lt;/p&gt;

&lt;p&gt;To switch to the &lt;em&gt;previous&lt;/em&gt; window (according to the order in your status bar) use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b p&lt;/code&gt;, to switch to the &lt;em&gt;next&lt;/em&gt; window use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b n&lt;/code&gt;. If you’ve created many windows you might find it useful to go to a window directly by typing its number (the status bar will tell you which window has which number), just use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b &amp;lt;number&amp;gt;&lt;/code&gt; where &amp;lt;number&amp;gt; is the number in front of the window’s name in your status bar.&lt;/p&gt;

&lt;h3 id=&quot;session-handling&quot;&gt;Session Handling&lt;/h3&gt;
&lt;p&gt;If you’re done with your session you can either get rid of it by simply exiting all the panes inside or you can keep the session in the background for later reuse.&lt;/p&gt;

&lt;p&gt;To detach your current session use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b d&lt;/code&gt;. You can also use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b D&lt;/code&gt; to let tmux give you a choice which of your sessions you want to detach. Detaching from a session will leave everything you’re doing in that session running in the background. You can come back to this session at a later point in time.&lt;/p&gt;

&lt;p&gt;To re-attach to a session and continue where you left you need to figure out which session you want to attach to first. List the currently running sessions by using&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tmux ls
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will give you a list of all running sessions, which in our example should be something like&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;0: 2 windows (created Sat Aug 15 17:55:34 2015) [199x44] (detached)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To connect to that session you start tmux again but this time tell it which session to attach to:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tmux attach -t 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-t 0&lt;/code&gt; is the parameter that tells tmux which session to attach to. “0” is the first part of your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux ls&lt;/code&gt; output.&lt;/p&gt;

&lt;p&gt;If you prefer to give your sessions a more meaningful name (instead of a numerical one starting with 0) you can create your next session using&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tmux new -s database
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will create a new session with the name “database”.&lt;/p&gt;

&lt;p&gt;You could also rename your existing session:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tmux rename-session -t 0 database
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The next time you attach to that session you simply use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux attach -t database&lt;/code&gt;. If you’re using multiple sessions at once this can become an essential feature.&lt;/p&gt;

&lt;p&gt;And that’s it! Congratulations, you’ve just completed your first tmux session and got your hands dirty with its window and session management. Yes, there’s more stuff tmux can do. But what you’ve just learned should be everything to start using tmux in the future.&lt;/p&gt;

&lt;h2 id=&quot;why-tmux&quot;&gt;Why tmux?&lt;/h2&gt;
&lt;p&gt;A response that I get quite often is: “Great, I get it. But why should I use tmux and its weird key combinations instead of just using iTerm2?”&lt;/p&gt;

&lt;p&gt;And you’re right, when it’s only basic window management, &lt;a href=&quot;http://iterm2.com/&quot;&gt;iTerm&lt;/a&gt; for Mac supports tabs and panes as well. For Linux there’s &lt;a href=&quot;https://gnome-terminator.org&quot;&gt;Terminator&lt;/a&gt;. So why would anyone feel the urge to learn some archaic technology in this day and age?&lt;/p&gt;

&lt;p&gt;Well, obviously there’s the bragging rights. But if that doesn’t convince you, there are a couple of actual reasons why I favor tmux over iTerm et al.:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;session handling: detaching from and attaching to sessions helps me with context switching and remote working&lt;/li&gt;
  &lt;li&gt;platform independence: I can use tmux on my Macbook, my Linux notebook, servers, Raspberry Pis, you name it.&lt;/li&gt;
  &lt;li&gt;customizable: there are many ways I can customize the look and behavior of my tmux environment. And I can sync this across different platforms using a simple dotfile&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;moving-on&quot;&gt;Moving on&lt;/h2&gt;
&lt;p&gt;If you’re curious to learn what else tmux can do that’s a great thing. And luckily most of the stuff is quite simple to discover. Just type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b ?&lt;/code&gt; to see a list of all available commands and start experimenting.&lt;/p&gt;

&lt;p&gt;Some of the commands that I’m using myself quite often are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b z&lt;/code&gt;: make a pane go full screen. Hit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b z&lt;/code&gt; again to shrink it back to its previous size&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b C-&amp;lt;arrow key&amp;gt;&lt;/code&gt;: Resize pane in direction of &amp;lt;arrow key&amp;gt;&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C-b ,&lt;/code&gt;: Rename the current window&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of that there are plenty of resources out there that help you getting further with tmux. People like me are blogging about their tmux experience and share what they’ve discovered. You can find people sharing their tmux configurations in their dotfiles repos on Github. There’s even a &lt;a href=&quot;https://pragprog.com/book/bhtmux/tmux&quot;&gt;book by Brian Hogan&lt;/a&gt; dedicated to tmux.&lt;/p&gt;

&lt;p&gt;For now it’s best to discover some stuff on your own. Experiment, fool around and maybe try to use tmux for your daily work. It takes a while to get used to and you’ll probably feel slow when you start out. I encourage you to keep using it. Get a feeling for its functionality and in no time you’ll find out that your work with the terminal will be pure bliss and refreshingly fast.&lt;/p&gt;

&lt;p&gt;If you’re interested in customizing your tmux experience I recommend that you read my &lt;a href=&quot;/blog/a-guide-to-customizing-your-tmux-conf/&quot;&gt;Guide to Customizing your tmux.conf&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;If you’re coming from a Linux background you’re probably familiar with the concept of window managers like &lt;a href=&quot;http://openbox.org/wiki/Main_Page&quot;&gt;Openbox&lt;/a&gt;, &lt;a href=&quot;http://i3wm.org&quot;&gt;i3&lt;/a&gt; or &lt;a href=&quot;http://awesome.naquadah.org/wiki/FAQ&quot;&gt;awesome&lt;/a&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;tmux is based on a client-server architecture. While this is rarely relevant, it’s helpful to understand how stuff works. The tmux server keeps track of all the running sessions. You will only ever work with the tmux client and create new sessions or connect to existing ones. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;there could also be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M-&lt;/code&gt; which is the same only for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Meta&lt;/code&gt; key (i.e. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt&lt;/code&gt; on most keyboards). &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This is an interesting one. Yes, you need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl&lt;/code&gt; in your prefix and also your command key. I find it easiest to only release the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; key after the prefix key and keep &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl&lt;/code&gt; pressed all the time while I hit the arrow key repeatedly. Experiment a little bit to get a feeling for it. &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/a-quick-and-easy-guide-to-tmux/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/a-quick-and-easy-guide-to-tmux/</guid>
				
			</item>
		
			<item>
				<title>How the metaphor of 'moving apartments' helps with your next Retrospective</title>
				        
				<pubDate>Sat, 20 Jun 2015 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/movingRetroHeader.jpg&quot; alt=&quot;The Moving Retro&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Moving from one place to another is something unique. The pleasant side of it certainly is the refreshing change, the novelty of the new home. On top of that you get the chance to get rid of old stuff; baggage that’s been sitting around in your old home that you no longer need but never decided to throw out.&lt;/p&gt;

&lt;p&gt;Then again moving is also tedious work. Moving means days and weeks full of disassembling and reassembling furniture, packing your stuff in boxes, getting everything from A to B. Along with that there’s this constant stream of stuff that needs to get done, stuff that you must not forget. Call the landlord, get a new internet connection for the new place, pay that preposterous amount of money for the real estate agent… All this has to happen at a certain point of time on top of all the work that you need to do anyway.&lt;/p&gt;

&lt;p&gt;I recently moved to a new place so I experienced first hand what moving was all about. I had volunteered to facilitate the next Retro for our team. Since I was literally busy day and night I had struggled to find what I wanted to do for that Retrospective. When I arrived at the office at the morning of the Retro I had a short chat with our PO where she asked me how I was doing. I told her about how I was moving at the moment and complained about the huge amount of stuff that’s still left to do when it struck me: This is the perfect metaphor for today’s Retro!&lt;/p&gt;

&lt;h2 id=&quot;why-moving-apartments-is-a-perfect-metaphor-for-your-retrospective&quot;&gt;Why ‘moving apartments’ is a perfect metaphor for your Retrospective&lt;/h2&gt;
&lt;p&gt;Moving apartments is a great analogy to set the scene in your Retro. You can be pretty sure that everyone in your team has moved at least once in their life (going to university, moving for a job). In turn everyone is familiar with the process, the work and the feelings that are involved.&lt;/p&gt;

&lt;p&gt;The process of moving has certain characteristics that have shown to be great questions to ask during a retro. I have found the following four topics to be fitting questions for the current state of the project. Setting the scene by introducing the metaphor of moving helped the team to get into the perfect mindset for that.&lt;/p&gt;

&lt;h3 id=&quot;buy-something-new&quot;&gt;Buy something new&lt;/h3&gt;
&lt;p&gt;As you move to a new place you figure out that you suddenly need new stuff. More space at your new home or a different room layout might call for some new piece of furniture that you have to acquire.&lt;/p&gt;

&lt;p&gt;Buying something new usually feels good. You get something pretty or something useful that will make your new place stand out. Acquiring something for your project can have the same effect. It does not mean that you have to literally buy something (although it can if you find out that there’s something missing). Adopting a new process or trying out something new could also be things that fall under the category of &lt;em&gt;“get something new”&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;throw-away-the-old-stuff&quot;&gt;Throw away the old stuff&lt;/h3&gt;
&lt;p&gt;For many, moving to a new place offers a unique opportunity to throw lots of stuff away that you’ve always wanted to get rid of. Stuff that’s just been sitting around because you never got to throw it away. You got used to it but thinking about it there was no real use for it.&lt;/p&gt;

&lt;p&gt;Your project will be full of something similar. Processes that serve no real purpose, technical debt in your code, everything that can generally be called &lt;em&gt;waste&lt;/em&gt; if you want to talk in Lean terms. Everything that you are better off without but never bothered to get rid of can be identified with the help of this analogy.&lt;/p&gt;

&lt;h3 id=&quot;fix-whats-broken&quot;&gt;Fix what’s broken&lt;/h3&gt;
&lt;p&gt;While you’re busy with disassembling and re-assembling all your furniture you often discover that there’s a lot of stuff that needs to be fixed. There are drill holes in your wall that should be sealed, walls that need to be painted, broken hinges that should be replaced.&lt;/p&gt;

&lt;p&gt;With this analogy in mind you can identify the broken stuff in your project and discuss ways to fix it.&lt;/p&gt;

&lt;h3 id=&quot;dont-forget-important-things&quot;&gt;Don’t forget important things&lt;/h3&gt;
&lt;p&gt;When I was moving I always had a huge list of reminders that would pop up during the day to remind me of stuff I must not forget. Paying bills, calling people or quitting old contracts are just some of these. All these are things that need to be done by a certain point in time. They usually are little tasks but each of them is crucial and has to be done at a certain point.&lt;/p&gt;

&lt;p&gt;Every project has similar things that don’t need to be done right now but need to be done before or after a certain point in time. This analogy helps you identifying the stuff that you absolutely must remember. You can then go on and discuss the right point in time where this item needs to be done.&lt;/p&gt;

&lt;h2 id=&quot;our-experience&quot;&gt;Our experience&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/movingRetroWall.jpg&quot; alt=&quot;Moving wall&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We had a really great session with our team using the “moving” metaphor. The team collected lots and lots of ideas that we could discuss about. I got great feedback on how the metaphor of moving really helped the team finding all these ideas. The four given questions offer analogies that everyone can relate to and they translate to project work really well.&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;p&gt;As in &lt;a href=&quot;/blog/tweetrospective-agile-retrospective&quot;&gt;my last Retrospective&lt;/a&gt;, I prepared some print-outs to better visualize the content of the Retro. I could also try to draw these but my drawing skills are pretty limited so I decided to go with printing them. Feel free to download the print-out if you want to try it for yourself. I’d love to hear from you if you’re trying this out!&lt;/p&gt;

&lt;div class=&quot;centered&quot;&gt;
  &lt;a href=&quot;/assets/img/uploads/movingRetroSheet.png&quot;&gt;
    &lt;img src=&quot;/assets/img/uploads/movingRetroSheetThumbnail.png&quot; alt=&quot;The Moving Retro Print Sheet&quot; /&gt;
  &lt;/a&gt;
  &lt;hr /&gt;
  &lt;a class=&quot;btn btn-primary&quot; href=&quot;/assets/img/uploads/movingRetroSheet.png&quot;&gt;Download&lt;/a&gt;
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/retrospective-moving/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/retrospective-moving/</guid>
				
			</item>
		
			<item>
				<title>The Tweetrospective - refresh your next Agile Retrospective</title>
				        
				<pubDate>Sun, 10 May 2015 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/tweetrospectivePhoto.jpg&quot; alt=&quot;Tweetrospective Photo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Retrospectives are an essential tool in Agile software development. Whatever methodology you use,
as long as you develop software in iterations you will have retrospectives after each of those (and
if you don’t: shame on you, my friend).&lt;/p&gt;

&lt;p&gt;Retrospectives help the team to take a step back from the day-to-day business and to reflect on
what’s happened in the past iteration. The team gets to discuss about problems and risks, annoyances
and moments of frustration, but also about success stories and progress. The intention of this is to find a way to eliminate the bad and encourage the good things in the future.&lt;/p&gt;

&lt;p&gt;Every retrospective will be facilitated by one person (the facilitator) who will prepare and setup 
the retro and guide the team. There are different approaches on how to facilitate a good retro and
there are more books than you will want to read about that specific topic so I won’t go into detail
here &lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In our team at ThoughtWorks we take turns on who will facilitate the next retrospectives. This week I
volunteered to facilitate the retro for our team and so it was my turn to prepare the session. I have 
facilitated a couple of retrospectives since I’ve joined ThoughtWorks. My previous approaches to gather 
data for the team to discuss about usually revolved around the classic questions of &lt;em&gt;“what was good?”&lt;/em&gt;, 
&lt;em&gt;“what was bad?”&lt;/em&gt;, and &lt;em&gt;“what puzzles me?”&lt;/em&gt; or some slight variation of these. 
This is a very easy and proven concept. The team is familiar with it and it gets the job done. On the
other hand the terms “proven” and “familiar” indicate that it tends to be pretty boring for the team. And
boredom is nothing you’d want if you want to push the team to get creative and open before starting
a discussion.&lt;/p&gt;

&lt;p&gt;In order to make the next retro more interesting again and to get the creativity flowing, I wanted 
to try something new instead of following the well-known and easy path. But where to start? I am far 
from being an experienced facilitator. I’ve read &lt;a href=&quot;https://leanpub.com/the-retrospective-handbook&quot;&gt;The Retrospective
Handbook&lt;/a&gt; by &lt;a href=&quot;https://www.thekua.com/atwork/&quot;&gt;Pat
Kua&lt;/a&gt; (which I can totally recommend, it’s a quick and enjoyable read 
and really helps you keeping everything in mind for preparing retrospectives) and facilitated a handful 
of retros that got the job done but that’s about it. There’s no vast pool of experience that I could
rely on.&lt;/p&gt;

&lt;p&gt;Luckily enough there’s a nice place for inspiration online that a colleague showed me a
couple of weeks ago: the &lt;a href=&quot;http://plans-for-retrospectives.com/&quot;&gt;Retr-o-mat&lt;/a&gt; has a very nice
collection of ideas and approaches for the individual phases for a retrospective. And on top of it
it will automatically generate a fully fledged plan for your next retro by randomly picking one of the concepts
for five typical steps in a retro’s agenda.&lt;/p&gt;

&lt;p&gt;Introducing five new concepts for our team in the upcoming retro was more than I wanted to do. For
once we only have limited time and I want to get the most out of it instead of spending most of it
explaining new games and approaches to the team. Secondly we are not that strict when it comes to
the agenda of a retro. So instead of picking a completely generated plan I started browsing through
the individual suggestions for the &lt;em&gt;“Gather Data”&lt;/em&gt; and &lt;em&gt;“Generate Insights”&lt;/em&gt; sections.&lt;/p&gt;

&lt;p&gt;Eventually I stumbled across the &lt;a href=&quot;http://plans-for-retrospectives.com/?id=97&quot;&gt;“#tweetmysprint”&lt;/a&gt; idea
by &lt;a href=&quot;http://wordaligned.org/&quot;&gt;Thomas Guest&lt;/a&gt; and found it to be really interesting. It suggests using
Twitter’s Tweet format to let the team write their thoughts about the past iteration and ordering it
in a timeline. I decided to let my retro revolve around exactly this concept. As it turns out it was
a great idea. Our team had lots of fun and we got some really interesting results out of it.&lt;/p&gt;

&lt;h2 id=&quot;the-concept-in-a-nutshell&quot;&gt;The concept in a nutshell&lt;/h2&gt;
&lt;p&gt;You start off describing the concept to the team. The team gets to write a couple of Tweets about
the last iteration on sticky notes. &lt;strong&gt;#hashtags&lt;/strong&gt;, &lt;strong&gt;@mentions&lt;/strong&gt; and &lt;strong&gt;emojis&lt;/strong&gt; are highly encouraged. 
Next you organize all these Tweets into a timeline and
read it out loud. Every teammember gets to vote on the Tweets he or she wants to discuss about using
&lt;strong&gt;Retweets&lt;/strong&gt; and &lt;strong&gt;Favourites&lt;/strong&gt;. You organize the highest voted Tweets into &lt;strong&gt;Trending Topics&lt;/strong&gt; and give
the team time to discuss about these in more detail.&lt;/p&gt;

&lt;p&gt;It turns out that the Twitter universe offers everything you need for a retro. Restricting the opinions
on the sticky notes to Twitter’s 140 characters limit is a good lesson on brevity and conciseness.
It is challenging to stick to this format and therefore will result in some really creative answers. 
Hashtags, Mentions and Emojis offer some unique opportunities. Mentioning someone in a Tweet
can be used to appreciate a specific person or to celebrate success. Hashtags are a great
concept to put additional information, emotion or funny references into the short Tweet format.&lt;/p&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;
&lt;p&gt;As usual make sure to have a room where the whole team fits and can talk and discuss in an undisturbed way. 
Get enough sticky notes and pens for everyone. Make sure to pick the right format for the sticky notes. I’ve found a
wide rectangular shape to be fitting (obviously resembling the format of one single Tweet).&lt;/p&gt;

&lt;p&gt;Print enough of the &lt;a href=&quot;#resources&quot;&gt;Tweetrospective Sheets&lt;/a&gt; at the end of this post for your team and
cut out the Retweet and Favourite icons. Prepare a bunch of these icons for each team member and
hand them out together with the sticky notes and pens.&lt;/p&gt;

&lt;h2 id=&quot;facilitating-the-retro&quot;&gt;Facilitating the Retro&lt;/h2&gt;
&lt;p&gt;Facilitating your Tweetrospective won’t be any different from other retros. Try your best to set a scene
where everyone feels secure and comfortable. Writing Tweets allows to get creative and share short
thoughts in an entertaining way with others. This could be a good opportunity to break the ice in a team.&lt;/p&gt;

&lt;h3 id=&quot;presenting-the-concept&quot;&gt;Presenting the Concept&lt;/h3&gt;
&lt;p&gt;There might be people in your team who don’t know the concept of Twitter. Even if you think everyone
is aware, it’s a good idea to recap what Twitter is and how it works to set the scene for all
participants. Make sure to explain the concept of Twitter and to describe the whole vocabulary around it. 
Tell the team what type of content gets published on Twitter. Mention the
140 characters limit of Tweets, Hashtags, mentioning other users and Emojis.&lt;/p&gt;

&lt;p&gt;Give the team around 10 minutes (feel free to vary) to write as many Tweets as you consider
suitable (personally, I gave no limit)&lt;/p&gt;

&lt;p&gt;In my Tweetrospective I prepared one example Tweet on a sticky note that included
hashtags, mentions and emojis to show off what was possible. The content of this example Tweet was just 
a reference to one of our team’s inside jokes which laid out the foundation for a lighthearted
atmosphere and got the idea across easily.&lt;/p&gt;

&lt;h3 id=&quot;writing-tweets&quot;&gt;Writing Tweets&lt;/h3&gt;
&lt;p&gt;It might be helpful to give your team a couple of examples of what they can write about. Possible
Tweets are success stories of the last iteration, stories of failures, lessons learned, rants,
appreciations of others or shameless plugs of something a teammate has been up to.&lt;/p&gt;

&lt;p&gt;Usually, Tweets always contain the author’s name. To stick to the concept of
Twitter as close as possible, your Tweetrospective’s Tweets could also contain the name of the
individual authors. However, this might influence the safety levels of your teammates. I decided to
encourage the team to write their name on top of each Tweet if they think it’s suitable for the
content. However, if they prefer to stay anonymous they could simply write “anonymous” instead.&lt;/p&gt;

&lt;h3 id=&quot;organising-the-timeline&quot;&gt;Organising the Timeline&lt;/h3&gt;
&lt;p&gt;After the time is up, collect the individual Tweets and arrange them in a timeline. Read out the
timeline to the team. This is probably the funniest part since reading out hashtags and emojis
is something unusual and offers a great potential where people can get creative.&lt;/p&gt;

&lt;h3 id=&quot;retweets--favourites&quot;&gt;Retweets &amp;amp; Favourites&lt;/h3&gt;
&lt;p&gt;You’ll want to find out which topics are most important for the team to discuss. Instead of relying
on dot-votes or something similar, you can - once again - use Twitter’s mechanisms for that. Let
everyone put &lt;strong&gt;Retweets&lt;/strong&gt; and &lt;strong&gt;Favourites&lt;/strong&gt; next to the Tweets they are most interested in for the upcoming
discussion. Everyone can use the cut-out icons you have prepared previously. 
In our Tweetrospective I made no difference between the semantics of Retweets and Favourites. However,
you could also consider applying different semantics to Retweets and Favourites respectively. A
possible way would be to say that Retweets are considered as votes for the upcoming discussion while
Favourites indicate that you want to put emphasis on a Tweet’s content (e.g. underline the
appreciation of a teammate).&lt;/p&gt;

&lt;p&gt;After everyone has gone wild with their Retweets and Favourites you can identify the most voted-on
Tweets and re-arrange them to the &lt;strong&gt;Trending Topics&lt;/strong&gt;. Go through these trending topics from most to
fewest-voted and let the team discuss the individual contents.&lt;/p&gt;

&lt;p&gt;From here on it’s all discussion for the team. Just make sure to moderate and guide the discussion as you would usually do 
and extract action items out of it.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;resources&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;p&gt;A Tweetrospective can be done easily and without much preparation. Just make sure you have enough
sticky notes, pens and a whiteboard for everyone. You can simply let everyone draw Retweet and
Favourite icons on the whiteboard right next to the sticky note Tweets.&lt;/p&gt;

&lt;p&gt;If you want to step up your Tweetrospective game and save some time during the voting phase
(drawing Retweet and Favourite icons seems to take quite some time) you can also print out the
following Tweetrospective Sheets and cut out the icons for your teammembers before the retro.&lt;/p&gt;

&lt;div class=&quot;centered&quot;&gt;
	&lt;a href=&quot;/assets/img/uploads/tweetrospective.pdf&quot;&gt;
		&lt;img src=&quot;/assets/img/uploads/printSheet.png&quot; alt=&quot;The Tweetrospective Print Sheet&quot; /&gt;
	&lt;/a&gt;
	&lt;hr /&gt;
	&lt;p&gt;
		&lt;a class=&quot;btn btn-primary&quot; href=&quot;/assets/img/uploads/tweetrospective.pdf&quot;&gt;Download as PDF&lt;/a&gt; |
		&lt;a class=&quot;btn btn-primary&quot; href=&quot;/assets/img/uploads/tweetrospective.png&quot;&gt;Download as PNG&lt;/a&gt; |
		&lt;a class=&quot;btn btn-primary&quot; href=&quot;/assets/img/uploads/tweetrospective.svg&quot;&gt;Download as SVG&lt;/a&gt;
	&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h2&gt;
&lt;p&gt;The Tweetrospective we had was a really fun and insightful session for our team. I plan to repeat it again some time 
in the future. Perhaps I could get the idea across and inspire someone to try it out themselves. If you give it a try 
feel free to share your experience. If you find something to improve or criticise just leave a comment in the comments section.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;If you’re interested in this topic you can find a comprehensive guide in Derby’s and Larsen’s &lt;a href=&quot;https://pragprog.com/book/dlret/agile-retrospectives&quot;&gt;Agile Retrospectives: Making Good Teams Great&lt;/a&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
				<link>https://www.hamvocke.com/blog/tweetrospective-agile-retrospective/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/tweetrospective-agile-retrospective/</guid>
				
			</item>
		
			<item>
				<title>Import your DKB account into Homebank</title>
				        
				<pubDate>Tue, 07 Apr 2015 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;Recently I started using &lt;a href=&quot;http://homebank.free.fr/&quot;&gt;Homebank&lt;/a&gt;, a great and free personal finance
tool, to keep track of my budget and spending habits. It takes a little effort to set up but is
really intuitive and straightforward from there.&lt;/p&gt;

&lt;p&gt;I started tracking all my spendings and transactions in Homebank a couple of months ago which helped
me getting started with Homebank. Tracking all transactions manually, however, felt really
cumbersome; especially when tracking a fair amount of transactions if you haven’t updated
Homebank in a while.&lt;/p&gt;

&lt;p&gt;Sensing that there must be a better way to track your spendings and earnings in Homebank I decided
to investigate a little bit. And as it turns out, there is a better way. My findings might be
helpful for others so I thought I might share.&lt;/p&gt;

&lt;h2 id=&quot;step-1-export-your-account-data-as-csv&quot;&gt;Step 1: Export your account data as CSV&lt;/h2&gt;
&lt;p&gt;To get your transactions from your DKB account into Homebank you need to export your account data as
a CSV file. This can easily be done using the DKB’s online banking interface. Just go to
“Kontoumsätze” (for a DKB Cash account) or “Kreditkartenumsätze” (for a Visa account), enter the
desired time frame for your report and then hit the little arrow icon in the top right corner (just 
beneath the printer icon). This will download a CSV file that we can convert and then import into
Homebank.&lt;/p&gt;

&lt;h2 id=&quot;step-2-download-the-dkb2homebank-converter&quot;&gt;Step 2: Download the dkb2homebank converter&lt;/h2&gt;
&lt;p&gt;Unfortunately the downloaded files are not compatible with Homebank’s CSV import interface. If you
try to import the DKB generated CSV files right away, Homebank will simply refuse to do so as it
does not recognize the file as a proper transactions file.&lt;/p&gt;

&lt;p&gt;Luckily the Homebank developer has written a &lt;a href=&quot;http://homebank.free.fr/help/misc-csvformat.html#txn&quot;&gt;specification of the CSV import
interface&lt;/a&gt;. It seems
fairly complete and allowed me to write a little converter script that converts the DKB’s CSV file
into a Homebank ready CSV file.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://raw.githubusercontent.com/hamvocke/dkb2homebank/master/dkb2homebank.py&quot;&gt;Download the latest version&lt;/a&gt; 
(&lt;em&gt;right click&lt;/em&gt; -&amp;gt; &lt;em&gt;Save Link as…&lt;/em&gt;) of the converter script and save it on your computer.
It’s written in Python and requires you to have Python &amp;gt;= 2.7.4 installed. I’ve tested it with
Homebank 5.0.0 on a Linux machine but expect it to work on other operating systems with a similar
Homebank version as well.&lt;/p&gt;

&lt;h2 id=&quot;step-3-convert-the-csv-file&quot;&gt;Step 3: Convert the CSV file&lt;/h2&gt;
&lt;p&gt;Now that you’ve downloaded the &lt;em&gt;dkb2homebank&lt;/em&gt; script, you can use it to convert the DKB’s CSV file
to a Homebank readable one. To run the script, call it as described in the &lt;a href=&quot;https://github.com/hamvocke/dkb2homebank&quot;&gt;readme file on
github&lt;/a&gt;. You need to provide the type of the CSV file
(currently DKB cash account exports and Visa account exports are supported) and the filename of the
respective CSV file:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./dkb2homebank.py --cash yourCashFile.csv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;or for Visa account exports:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./dkb2homebank.py --visa yourVisaFile.csv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Each of these commands will create a output file called either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cashHomebank.csv&lt;/code&gt; for DKB Cash
accounts or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;visaHomebank.csv&lt;/code&gt; for Visa accounts.&lt;/p&gt;

&lt;h2 id=&quot;step-4-import-the-converted-csv-file-into-homebank&quot;&gt;Step 4: Import the converted CSV file into Homebank&lt;/h2&gt;
&lt;p&gt;You can import the newly created CSV files into Homebank using its import dialog (&lt;em&gt;File&lt;/em&gt; -&amp;gt;
&lt;em&gt;Import&lt;/em&gt; -&amp;gt; &lt;em&gt;CSV file…&lt;/em&gt;). This dialog will guide you through the import process. Make sure that
you select the correct account to which the imported data should be added.&lt;/p&gt;

&lt;p&gt;After that all your transactions are imported into your Homebank file. You can now start tagging
them as you like to help you get an overview of all your spendings and earnings.&lt;/p&gt;

&lt;h2 id=&quot;what-else&quot;&gt;What else?&lt;/h2&gt;
&lt;p&gt;If you discover any problems, just contact me or file a bug report on the
&lt;a href=&quot;https://github.com/hamvocke/dkb2homebank&quot;&gt;dkb2homebank GitHub repo&lt;/a&gt;. You can also try to fix or
improve stuff yourself and send me a pull request.&lt;/p&gt;

&lt;p&gt;Was this helpful? Feel free to drop me a line!&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/import-dkb-accounts-into-homebank/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/import-dkb-accounts-into-homebank/</guid>
				
			</item>
		
			<item>
				<title>Add Color to Chrome's Header Bar on Android Lollipop</title>
				        
				<pubDate>Sat, 28 Feb 2015 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;If you’re a Chrome user on Android Lollipop you might already have noticed. As someone who just
recently updated to Android Lollipop I discovered this this week: Chrome on Lollipop (from Chrome 39 onwards) allows your website to
change the color of Chrome’s title bar.&lt;/p&gt;

&lt;p&gt;The first time I noticed this was when I was browsing the &lt;a href=&quot;http://forum.xda-developers.com/&quot;&gt;XDA Developers
Forums&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/xda-colored-titlebar.jpg&quot; alt=&quot;XDA Developers using a colored titlebar in Chrome for
Lollipop&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A couple of days later I saw Ars Technica using it for their dark theme (which really adds to the
whole reading experience on mobile in my opinion):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/uploads/ars-colored-titlebar.jpg&quot; alt=&quot;Ars Technica showing off a colored titlebar to match their website's
theme&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I wanted to add this effect to a little website I wrote this week, too. After short research I
figured out that this could easily be achieved by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theme-color&lt;/code&gt; meta
tag on your website. Just define the meta tag in your header section, define the desired color and Chrome will take care to colorize the header.
The tag will take any hexadecimal or named color as its value:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;meta name=&quot;theme-color&quot; content=&quot;#663399&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;meta name=&quot;theme-color&quot; content=&quot;RebeccaPurple&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you use this tag on your website, Android also uses the color in the app overview:
&lt;img src=&quot;/assets/img/uploads/app-overview-titlebar-colors.jpg&quot; alt=&quot;Titlebar Colors in the App Overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is a very simple way to make your website stand out on Android devices and even increase the
whole User Experience of your website. So this little trick might come in handy for you in the
future.&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/colorful-header-bar-chrome-android/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/colorful-header-bar-chrome-android/</guid>
				
			</item>
		
			<item>
				<title>Working at ThoughtWorks, a three month retrospective</title>
				        
				<pubDate>Sat, 22 Nov 2014 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;More than three months ago I took the first step of a fascinating journey: It was my first day at
&lt;a href=&quot;http://www.thoughtworks.com/&quot;&gt;ThoughtWorks&lt;/a&gt; in Hamburg. The prospect of a new job in a new city
had made me curious and nervous for the past couple of weeks. As it turned out, the anxiety should
only last until my very first hours at work. After that everything immediately felt like home.&lt;/p&gt;

&lt;h1 id=&quot;my-first-day&quot;&gt;My first day&lt;/h1&gt;
&lt;p&gt;My first day at ThoughtWorks started after a night of fairly restless sleep. I woke up way too early
that Monday morning and everything felt unfamiliar. A different apartment to
wake up in, an unknown way to work, being a complete stranger in a big city. &lt;em&gt;“This will take ages to
get used to”&lt;/em&gt;, was the thought that constantly accompanied me.&lt;/p&gt;

&lt;h2 id=&quot;breakfast-and-handshakes&quot;&gt;Breakfast and Handshakes&lt;/h2&gt;
&lt;p&gt;I took public transport to the office that morning which worked way better than I
expected, considering I am a complete public transport dilettante. So there I was, outside of the new
office, way ahead of my time and hesitant to enter. I grabbed a coffee from a shop at the corner and
decided to wait outside since I did not want to be the first on the scene.&lt;/p&gt;

&lt;p&gt;When I finally entered the office I was greeted by a sweet breakfast with
&lt;a href=&quot;https://en.wikipedia.org/wiki/Franzbr%C3%B6tchen&quot;&gt;Franzbrötchen&lt;/a&gt;, Croissants
and more people than I could ever remember in such a short time. Everyone was keen to introduce themselves
and curious to hear who I was and what I had to tell.&lt;/p&gt;

&lt;h2 id=&quot;polyglot-projects-and-the-best-tools-for-the-job&quot;&gt;Polyglot projects and the best tools for the job&lt;/h2&gt;
&lt;p&gt;Right during our breakfast I was told which project I’d be assigned to. I only got to know the project’s name
so I was eager to get to know more about what would keep me occupied for the next months. After
a short time of fiddling around with my new notebook I had a session in which I was introduced to
the project, the business model and the technologies we chose to work with. Hearing about the technology
stack and realizing how polyglot this project would be put a big grin on my face. It was obvious
that these people really love technology. Leveraging the latest and greatest languages,
frameworks and tools available is the way to go for the company and I was more than happy to be
part of that. It is a great feeling to know that I could use many of the technologies I would fiddle
around with in my spare time anyways.&lt;/p&gt;

&lt;p&gt;I was used to work with self-written Java frameworks that were thought to be a one-size-fits-all
solution to each and every project presented to us. There’s nothing wrong with using Java, not at
all. However, I never liked the approach of shoehorning every single requirement into something that could be solved
with the few given tools we had at hand instead of using the best tools for the job. Seeing that my
team would share that opinion and was eager to try something new was obviously something I was
absolutely happy with. Working on a project and getting the chance to learn new languages and
frameworks at the same time was obviously something I was more than pleased to do.&lt;/p&gt;

&lt;h2 id=&quot;trains-on-strike-a-pub--an-expensive-taxi&quot;&gt;Trains on strike, a pub &amp;amp; an expensive taxi&lt;/h2&gt;
&lt;p&gt;My first day ended quite spectacular. The train drivers were on strike so I had no way to get home
to my apartment after work. A colleague suggested to join him for a beer at the pub which sounded like a
solid plan to me. After some more than the announced &lt;em&gt;“one beer”&lt;/em&gt; I ended up being stranded somewhere
in Hamburg (thanks to my awesome orientation skills) with a dead phone and this random guy
from Leeds I simply decided to call “Dave” even though that was certainly not his real name. Dave and I
managed to snatch a Taxi and get to the Hauptbahnhof. I took the Taxi to get further home to my apartment
and managed to end my oddysey. After all it was a great – albeit expensive, thanks to the Taxi – night and a great ending of my
first day. The spontaneous pub night helped breaking the ice. On top of that I had a decent story to share on the next day.&lt;/p&gt;

&lt;h1 id=&quot;thoughtworks-whats-it-like&quot;&gt;ThoughtWorks, what’s it like?&lt;/h1&gt;
&lt;p&gt;It’s only been a little more than three months and I am far away from having seen it all. But I
think I have seen enough for a first roundup. So here are a couple of things that I consider to be
the most remarkable for working with ThoughtWorks:&lt;/p&gt;

&lt;h2 id=&quot;tdd-all-the-way&quot;&gt;TDD, all the way&lt;/h2&gt;
&lt;p&gt;One thing I really got to appreciate is the clear focus on &lt;a href=&quot;http://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;Test-driven
development&lt;/a&gt; (TDD). Of course I was familiar with
writing automated tests of all kinds before. I read Kent Beck’s &lt;em&gt;TDD by Example&lt;/em&gt; and was aware of the benefits
you get from test automation. I thought I knew what TDD meant until I got to work
with the people at TW.&lt;/p&gt;

&lt;p&gt;Seeing the focus on TDD and how it helped shaping the software we
created made clear that my previous understanding of TDD could at best be described with a
‘test-first’ approach. Sure, it worked and I produced results. I delivered software at my previous
job as well, after all. However, it was far from what I encountered at TW and it didn’t take long to really
convince me of the benefits of having a pretty strict focus on Test-driven development.&lt;/p&gt;

&lt;h2 id=&quot;pair-programming&quot;&gt;Pair Programming&lt;/h2&gt;
&lt;p&gt;The one thing that was completely new to me was the practice of Pair Programming. The entire
development at TW is done in pairs. I have to admit that I had to get used to that in the first
days. My fellow Devs made it very easy to get used to it, though, and turned out to be very
supportive.&lt;/p&gt;

&lt;p&gt;Pair Programming was the one thing I couldn’t decide on whether it made sense for me or not.
I knew it would be practised at TW in advance so it came as no surprise. I just
couldn’t imagine that having two people working on the same task all the time would really be
worth the investment. It turns out that all my skepticism was unjustified. Working with a Pair
turned out to be great, especially for new team members:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You get up and running very fast. Your pair can introduce you to the tools and techniques you
  might not know yet.&lt;/li&gt;
  &lt;li&gt;The bad conscience sits right next to you. No more &lt;em&gt;“that’s good enough”&lt;/em&gt; solutions, no more &lt;em&gt;“I
will fix that later”&lt;/em&gt;. Everyone gets tempted to deliver a quick and dirty hack instead of cleaning
up. We all know better but tend to ignore that. Good luck trying to ignore your pair!&lt;/li&gt;
  &lt;li&gt;There’s always something interesting to learn. You always take away that one fancy shortcut you
can’t believe you didn’t know or that new plugin for your favorite editor. You will be surprised
how much of those little tricks you can gather in a short time.&lt;/li&gt;
  &lt;li&gt;“Hitting the wall”: Your pair can help you. Everyone gets stuck from time to time. This is what
we get from working with not completely understood technology and domains. Working with a pair
will help you with that.&lt;/li&gt;
  &lt;li&gt;Spread the knowledge. You reduce the &lt;a href=&quot;http://en.wikipedia.org/wiki/Bus_factor&quot;&gt;Bus Factor&lt;/a&gt; if at
least two people know about each topic and therefore reduce the risk for the entire project.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;keep-it-simple-stupid&quot;&gt;Keep it simple, stupid&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/KISS_principle&quot;&gt;KISS principle&lt;/a&gt; is applied everywhere and I
love it. Keep it as simple as possible, avoid
over-engineering, don’t try to make things unnecessarily complex. This mentality is applied to
technological and business decisions and really helps us moving fast and getting stuff done.&lt;/p&gt;

&lt;h2 id=&quot;contribute-to-the-community&quot;&gt;Contribute to the community&lt;/h2&gt;
&lt;p&gt;One thing you can clearly feel while being around at ThoughtWorks is the strong community focus.
Internally as well as externally ThoughtWorkers try to contribute as much to their communities as
they can. There are talks on a widespread range of topics every friday over lunchtime, free for
every ThoughtWorker to join. Externally, people organize and participate in meetups, hackathons,
even conferences for the local communities. Its something that everyone in the company values.
Giving and contributing instead of just taking is something people strive for. And rightly so. You
get to learn so much more as soon as you start contributing instead of just consuming.&lt;/p&gt;

&lt;h1 id=&quot;moving-forward&quot;&gt;Moving forward&lt;/h1&gt;
&lt;p&gt;It’s been a great three months so far. I’ve met amazingly knowledgeable, genuinely friendly and helpful people and
I’m looking forward to working with these people in the future. I’m excited to be able to keep on
learning new stuff every day and to contribute to the community. As it turns out it’s been a great
decision to go to Hamburg!&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/three-months-tw/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/three-months-tw/</guid>
				
			</item>
		
			<item>
				<title>Goodbye Gütersloh, Hello Hamburg!</title>
				        
				<pubDate>Tue, 19 Aug 2014 00:00:00 +0000</pubDate>

				
				<description>&lt;p&gt;Today marks my last day in Gütersloh. My bags are packed, my stuff is sitting neatly packed in boxes in my apartment, waiting to be hauled into a big van. I’m sitting in my office near the Autobahn in Gütersloh, on the same floor I’ve been working for the past five years. I’m sitting here, cleaning up my stuff, waiting for my colleagues to show up for the cake my girlfriend baked for my farewell. Sitting here on my last day and waiting in my office led me to think about the whole journey that brought me here in the first place.&lt;/p&gt;

&lt;p&gt;My journey as a software developer started mid-2008 after finishing school. I’ve always had a hand for ‘computer stuff’ and healthy interest in exploring the possibilities I had using computers, operating systems and programming languages.&lt;/p&gt;

&lt;p&gt;My parents got their first computer when I was about five or six years old. I vividly remember how my Dad showed us kids this magical device with which you could do all kinds awesome stuff (his demonstration of Prince of Persia completely blew my mind). The following years my brother and I tinkered around with every single computer our family got. Our main goal always was to get our computer games running which often required a massive amount of messing with the operating system. Our early efforts mostly didn’t work out as expected and we ended up with a broken system and annoyed parents. But it was worth it. Both of us had fun tinkering around and the incentive of getting a computer game started was enough for us to spend hours finding out a way run it. I loved the spirit of tinkering around, even though neither of us truly understood what we were doing (we were about 8 or 9 at that time after all).&lt;/p&gt;

&lt;p&gt;In my teenager years (I must have been around 13) I got my first personal computer. I remember spending a great amount of time in a couple of IRC channels, having a great time with several other guys I met through some forums on the www. These were the days that got me hooked on programming. Inspired by my IRC mates I wanted to write my own website without having a clue how to do so. It was the time of hosting services like Beepworld and Geocities that were notorious for hosting furiously blinking, seizure-provoking websites assembled with WYSIWYG editors. But that was not what I wanted. I wanted to create a website professionally. I wanted to learn how to do this by hand. WYSIWYG editors were out of question. I figured out I had to learn HTML first. So I studied everything, I could find on &lt;a href=&quot;http://de.selfhtml.org/&quot;&gt;SELFHTML&lt;/a&gt;, a very popular German resource about HTML at that time (and apparently it’s still going strong). My first attempts using HTML and CSS were obviously crude and not really successful, but after a couple of weeks of intensive learning and writing, I launched my first website: &lt;em&gt;stultus.org&lt;/em&gt;. Without relevant content and no concept beyond “that’s my website!” I quickly came to the conclusion, that I needed to do something more with my website. One of my IRC mates told me about PHP and that this was the way to go, if I wanted to create “real” and “dynamic” websites. I bought my first book on PHP at age 14 and with extensive coaching of the same guy in IRC I finally had my first website running using PHP and a crudely written CMS with very basic features and a MySQL database as backend. To this day I own this domain and I feel quite nostalgic about it. There’s nothing left on there, however.&lt;/p&gt;

&lt;p&gt;I kept my curiosity and learned more and more about programming languages, especially Java and object oriented programming as well as computer graphics and web design in the following years. I voluntarily took an extra computer science course in school where we would learn object oriented programming and the Java language from scratch. During that time I did several web design tasks and consistently hacked away on my personal homepage (&lt;em&gt;stultus.org&lt;/em&gt;, unfortunately I did never release anything of it though).&lt;/p&gt;

&lt;p&gt;After finishing school in 2008 I stumbled upon a job ad from Bertelsmann in Gütersloh. They were looking for people to work at Bertelsmann, do a training as IT specialist (&lt;em&gt;Fachinformatiker&lt;/em&gt;) and make a Bachelor’s degree in Business Information Systems (&lt;em&gt;Wirtschaftsinformatik&lt;/em&gt; which is a quite popular German major combining Computer Science, Information Systems and Economics, to name a few). The opportunity to study at university (i.e. university of applied sciences) and work on a rotating basis seemed a great idea to me, so I applied. After an assessment as you would expect from a big enterprise such as Bertelsmann I got a letter offering me a job for the Bachelor of Science program. I was overjoyed and agreed on the offer. This was an opportunity to get a solid professional foundation for all my amateurish hacking efforts the years before. I would be taught a broad spectrum of knowledge at university and have the opportunity to work on real projects with real people and real customers. How cool was that?&lt;/p&gt;

&lt;p&gt;And so it happened. I learned tons of stuff about programming languages, databases, networks, operating systems but also project management, economics, marketing, logistics, statistics and much much more. During my time at work I would work as a software developer using the Java platform. In my department we developed Customer Relationship Management software, broadly speaking. Our customers were well-known companies from different backgrounds and every project was a great challenge for itself. In my first years as a developer I would rather work on internal Java frameworks, providing bug fixes and implementing new minor features. But I soon made progress and was glad that I could help my colleagues working on the real projects providing direct business value for our customers. It was a nice feeling. And on top of that: I would get a fair amount of salary at the end of each month, regardless of whether I was studying or working.&lt;/p&gt;

&lt;p&gt;After finishing my Bachelor’s degree, I got a new employment contract with the department I worked at the whole time. I was no longer a corporate student but finally a regular, internal employed software developer. My tasks would remain roughly the same but the salary was no longer that of a corporate student. For my accomplishments in my Bachelor’s degree, Bertelsmann decided to give me a scholarship to finance a subsequent Master’s degree of my choice. Given this opportunity I decided not to waste my time and started looking for a Master’s degree that I could do simultaneously to my work. I found out that the University of Münster was offering a major that fit to my expectations, called &lt;em&gt;Information Management&lt;/em&gt; (which is close to their regular &lt;em&gt;Information Systems&lt;/em&gt; major). I enrolled and was very busy working on my Master’s degree while coping with the increasingly complex tasks and the extra responsibility at work. In the end everything worked out and I got my degree.&lt;/p&gt;

&lt;p&gt;The last 10 months have been very exciting, to say the least. I finished my Master’s degree, wrote my Master’s thesis about &lt;em&gt;Continuous Delivery&lt;/em&gt; and how we could use it in our department and also implemented a working prototype for a deployment pipeline. Focusing on the topic of Continuous Delivery intensively for half a year was fascinating. I’ve read Jez Humble’s and Dave Farley’s &lt;a href=&quot;http://www.amazon.com/gp/product/0321601912&quot;&gt;Continuous Delivery&lt;/a&gt; and was hooked after a few pages. I read it from cover to cover in a couple of days. It got me excited to work on a concept for using Continuous Delivery at work so that we could deliver our software more frequently and more securely. The results of my Master’s thesis got some of my colleagues interested in this topic as well and you could feel a certain momentum build up in our department.&lt;/p&gt;

&lt;p&gt;Nevertheless, I felt that there was something lacking in my current position. I had seen quite a few projects and worked with talented people. But I had the feeling that even though there was still a lot I could learn, I had no real perspective left at Bertelsmann. Our projects were basically the same, I missed real innovation, technology-wise as well as from a business perspective (besides that, there were several other factors as well but this was my major gripe). In January 2014, at the last day of my winter vacation, I discovered that ThoughtWorks, the company that basically brought up the idea of Continuous Delivery, was looking for someone with experience in Java development and Continuous Delivery for their office in Hamburg. Being quite a northerner myself and having no roots in Gütersloh, I decided to apply for this job. I had written a fair amount of Java code and spent the past six months studying the topic of Continuous Delivery intensively after all. I got lucky. Only a few hours after sending in my application I got a call from a lady of ThoughtWorks’ HR department. They told me they were interested and we chatted nicely for about 45 minutes. I managed to pass the rest of their application process and got an offer for a position in Hamburg sometime late February. I handed in my notice of termination at Bertelsmann directly afterwards.&lt;/p&gt;

&lt;p&gt;And here I am now. Six months after I handed in my notice my cancellation period is over and my last day at Bertelsmann has come. It was a great experience, I had the chance to learn a lot, was paid a fair salary, got the chance to work with smart and talented colleagues and got to know many nice people. Nevertheless, six years into my career I felt it was time to move on. I am excited to start at ThoughtWorks next month and I’m sure that this is the right company to offer me what I’ve missed before: Learning even more, working on exciting and diverse projects and experiencing a great work culture.&lt;/p&gt;

&lt;p&gt;Let’s hope for the best!&lt;/p&gt;
</description>
				<link>https://www.hamvocke.com/blog/goodbye-gutersloh/</link>
				<guid isPermaLink="true">https://www.hamvocke.com/blog/goodbye-gutersloh/</guid>
				
			</item>
		
	</channel>
</rss>
