<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Steffen Ronalter</title>
    <description>The latest articles on DEV Community by Steffen Ronalter (@ronalterde).</description>
    <link>https://dev.to/ronalterde</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F38262%2Fb3152690-08b7-4a98-b279-4021729da4e9.jpg</url>
      <title>DEV Community: Steffen Ronalter</title>
      <link>https://dev.to/ronalterde</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ronalterde"/>
    <language>en</language>
    <item>
      <title>Embedded Programming: Loose Coupling Best Practices</title>
      <dc:creator>Steffen Ronalter</dc:creator>
      <pubDate>Wed, 20 Mar 2019 08:19:34 +0000</pubDate>
      <link>https://dev.to/ronalterde/embedded-programming-loose-coupling-best-practices-20n7</link>
      <guid>https://dev.to/ronalterde/embedded-programming-loose-coupling-best-practices-20n7</guid>
      <description>&lt;p&gt;When creating Embedded Software, system complexity that grows over lifetime makes it increasingly harder to reason about certain behaviors of the program.&lt;br&gt;
As always in engineering, it helps to divide &lt;strong&gt;one big problem&lt;/strong&gt; into &lt;strong&gt;several smaller problems&lt;/strong&gt; in order to be able to eventually solve it. This is what this article is all about.&lt;/p&gt;

&lt;p&gt;Note: This post has originally been published on &lt;a href="https://deardevices.com" rel="noopener noreferrer"&gt;deardevices.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In his book &lt;a href="https://www.oreilly.com/library/view/working-effectively-with/0131177052/" rel="noopener noreferrer"&gt;Working Effectively with Legacy Code&lt;/a&gt;, Michael Feathers introduces the idea of a &lt;strong&gt;seam&lt;/strong&gt; as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a place where you can alter behavior in your program without editing in that place.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Although originally intended as a means for getting legacy code under test, we will use this idea as a guide for designing software in the first place. This is a key aspect of &lt;a href="https://en.wikipedia.org/wiki/Loose_coupling" rel="noopener noreferrer"&gt;loose coupling&lt;/a&gt;, after all: the ability to make changes in units of production code &lt;strong&gt;without changing the units themselves&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before diving into the details, let's talk about &lt;em&gt;units&lt;/em&gt; first.&lt;/p&gt;
&lt;h1&gt;
  
  
  Units and their Dependencies
&lt;/h1&gt;

&lt;p&gt;Let's say you are about to start a new embedded project.&lt;/p&gt;

&lt;p&gt;You may not even think about designing a system separated into different units at all -- and that's perfectly fine. When building prototypes, we want to see whether something is working, especially whether our software plays well together with the hardware.&lt;/p&gt;

&lt;p&gt;In that phase of a project, it's probably not that important to make a distinction between different units at all. Everything may be &lt;em&gt;coupled very tightly&lt;/em&gt;, maybe even within just a single unit or module (Forgive me that I use the terms &lt;em&gt;unit&lt;/em&gt; and &lt;em&gt;module&lt;/em&gt; interchangeably in here).&lt;/p&gt;

&lt;p&gt;As the project grows, it becomes more and more complex, and we usually want to do something about that to &lt;em&gt;stay in control&lt;/em&gt;. What we can do is split up the code and put it into different compilation units (i.e. &lt;code&gt;.c&lt;/code&gt;/&lt;code&gt;.cpp&lt;/code&gt; files) to reach some kind of logical separation.&lt;/p&gt;

&lt;p&gt;These logically separated pieces of code we will call &lt;strong&gt;unit&lt;/strong&gt; for the rest of this article.&lt;/p&gt;

&lt;p&gt;Let's imagine a project about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Measuring a voltage level using an ADC,&lt;/li&gt;
&lt;li&gt;Averaging that number over time and&lt;/li&gt;
&lt;li&gt;Showing the result on an LCD.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, via the serial port, the user should be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;See the averaged number every few seconds and&lt;/li&gt;
&lt;li&gt;Start and stop the sampling process by issuing a command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From that description, we can divide the system into four units: &lt;code&gt;ADC&lt;/code&gt;, &lt;code&gt;AverageFilter&lt;/code&gt;, &lt;code&gt;Display&lt;/code&gt;, and &lt;code&gt;Serial&lt;/code&gt;. The following diagram shows some dependencies between these units based on how they would probably communicate with each other. Does this make sense?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fho77y2r42koqwczrih58.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fho77y2r42koqwczrih58.png" alt="objects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see from the diagram that all of these units are coupled somehow. An arrow here reads as &lt;em&gt;depends on&lt;/em&gt; or &lt;em&gt;includes a header file&lt;/em&gt;. &lt;code&gt;AverageFilter&lt;/code&gt; depends on &lt;code&gt;Serial&lt;/code&gt; because it calls its &lt;code&gt;print()&lt;/code&gt; function.&lt;/p&gt;
&lt;h1&gt;
  
  
  Loosen the Coupling
&lt;/h1&gt;

&lt;p&gt;At some point, we might want to replace one or more units by a different implementation -- without any impact on the rest of the system.&lt;br&gt;
And &lt;em&gt;without any impact&lt;/em&gt; here even means: &lt;strong&gt;without changing any of the other unit's code&lt;/strong&gt;. There are various reasons you might want to do that. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Switch averaging filters at runtime, depending on user configuration&lt;/li&gt;
&lt;li&gt;Swap the serial interface between RS232 and USB, depending on build parameters&lt;/li&gt;
&lt;li&gt;Replace the display unit by some stub in the test build&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here comes the tricky part: you cannot simply remove or replace units that are &lt;em&gt;pointed to by a dependency&lt;/em&gt;. To make this possible, we need to &lt;strong&gt;decouple&lt;/strong&gt; units from each other.&lt;/p&gt;

&lt;p&gt;As the post title suggests, there are (at least) three ways to realize this in C and C++. We are going to take a look at each of them in the sections below.&lt;/p&gt;
&lt;h1&gt;
  
  
  Best Practice #1: Decoupling At the Object Level
&lt;/h1&gt;

&lt;p&gt;This method is the most flexible one. At runtime, you pass a dependency into a unit. In C++, you would create an interface (an abstract base class) and let the unit implement it. Something similar can be done in C, by letting the unit depend on a set of function pointers.&lt;/p&gt;

&lt;p&gt;The following snippet shows a C++ example for breaking up the tight coupling of the &lt;code&gt;AverageFilter&lt;/code&gt; to the &lt;code&gt;ADC&lt;/code&gt; unit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FilterInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
  &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;FilterInterface&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AverageFilter&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;FilterInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ADC&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
  &lt;span class="n"&gt;ADC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FilterInterface&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;FilterInterface&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;[...]&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;AverageFilter&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ADC&lt;/span&gt; &lt;span class="n"&gt;adc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;adc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The class &lt;code&gt;ADC&lt;/code&gt; depends on the interface of type &lt;code&gt;FilterInterface&lt;/code&gt; and stores a reference to it. Thereby it is &lt;strong&gt;agnostic to the concrete implementation&lt;/strong&gt; passed in.&lt;/p&gt;

&lt;p&gt;In C, we don't have the concept of polymorphism (which is the mechanism that makes it possible to use concrete implementations transparently through base class pointers). You can always emulate it using function pointers, though:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;FilterInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;FilterInterface&lt;/span&gt; &lt;span class="n"&gt;interface_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ADC_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FilterInterface&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;interface_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ADC_process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;interface_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tends to be a bit less explicit and more error-prone than the C++ implementation. It might still be worth it (and people actually do it: &lt;a href="https://en.wikipedia.org/wiki/Systemd" rel="noopener noreferrer"&gt;systemd&lt;/a&gt;, &lt;a href="https://www.kernel.org/" rel="noopener noreferrer"&gt;Linux drivers&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This solution, no matter if implemented in C or C++, comes with a runtime cost while giving you the freedom of modifying dependencies at runtime as well.&lt;/p&gt;

&lt;h1&gt;
  
  
  Best Practice #2: Decoupling At the Link Level
&lt;/h1&gt;

&lt;p&gt;In the next step we are going to explore another method. This will be based on yet another stage of the software build process -- &lt;em&gt;the linking&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let's see what Michael Feathers has to say about &lt;em&gt;Link&lt;/em&gt; seams:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In many language systems, compilation isn’t the last step of the build process. The compiler produces an intermediate representation of the code, and that representation contains calls to code in other files. Linkers combine these representations. They resolve each of the calls so that you can have a complete program at runtime.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Linking Overview
&lt;/h2&gt;

&lt;p&gt;Here, Feathers does a great job describing how the linking works. For C and C++, this is enough to know for now.&lt;/p&gt;

&lt;p&gt;You can see a flowchart of the process below. Each &lt;code&gt;.c&lt;/code&gt; file is compiled individually as a &lt;em&gt;compilation unit&lt;/em&gt;. This means the compiler outputs a &lt;code&gt;.o&lt;/code&gt; object file for each of them:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofuwxq8xfan5h7od7ifz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofuwxq8xfan5h7od7ifz.png" alt="objects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All object files are then passed on to the linker whose job is to put everything together -- in order to get an executable program:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60yj62bowme4egpampvl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60yj62bowme4egpampvl.png" alt="objects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One important part of linking is to &lt;strong&gt;look for unresolved symbols&lt;/strong&gt; needed by objects (function names, for example) and to try to satisfy those using symbols exported by other objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploiting the Linking Process
&lt;/h2&gt;

&lt;p&gt;As described by Feathers, we may exploit this process by offering &lt;em&gt;different&lt;/em&gt; sets of symbols, based on what our &lt;em&gt;build configuration&lt;/em&gt; looks like.&lt;/p&gt;

&lt;p&gt;Let's take a look at this Makefile snippet to get the idea:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;release.elf:
  gcc driver_release.o production.o -o release.elf

test.elf
  gcc driver_test.o production.o -o test.elf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two different targets, one for each build configuration we wish to maintain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;release&lt;/code&gt;: results in a shippable executable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test&lt;/code&gt;: contains debug code for testing that should never go out to the customer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As shown in the diagram below, to build each of the two &lt;a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format" rel="noopener noreferrer"&gt;ELF&lt;/a&gt; executables we pass the exact same object file &lt;code&gt;production.o&lt;/code&gt; to the linker in either case.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrpvgbct2qs5gmllw0d1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrpvgbct2qs5gmllw0d1.png" alt="objects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The linker now strives to find matches for symbols demanded by &lt;code&gt;production.o&lt;/code&gt;. For that, it happily considers &lt;em&gt;any&lt;/em&gt; object file it is offered. Assuming &lt;code&gt;driver_release.o&lt;/code&gt; and &lt;code&gt;driver_test.o&lt;/code&gt; adhere to the same API convention, the linker doesn't see the difference and builds two different configurations for us.&lt;/p&gt;

&lt;p&gt;The fact that we were able to switch implementations, depending on the build configuration suggests some level of decoupling between the units used in the example above.&lt;/p&gt;

&lt;p&gt;This decoupling method has no runtime cost at all, which comes at the price of decreased flexibility compared to the previous approach. To switch over to a different configuration, you will at least need to re-run the linker. You do not need to recompile your objects though -- This may improve build time significantly, depending on the size of your project.&lt;/p&gt;

&lt;p&gt;Speaking about runtime cost: there might be some kind of indirect runtime cost for this solution. Because functions are implemented within different compile units, the compiler doesn't have the big picture that would be useful for optimization. This might be compensated by &lt;a href="https://gcc.gnu.org/wiki/LinkTimeOptimization" rel="noopener noreferrer"&gt;Link Time Optimization (LTO)&lt;/a&gt; though.&lt;/p&gt;
&lt;h1&gt;
  
  
  Best Practice #3: Decoupling At the Preprocessing Level
&lt;/h1&gt;

&lt;p&gt;After talking about decoupling units at the linker level, this section is going to be about achieving the same goal, but at the &lt;strong&gt;preprocessing stage&lt;/strong&gt; of the build process. At the end of the article, you will find a comparison of all three methods.&lt;/p&gt;

&lt;p&gt;Let's start with another quote from Michael Feathers. In &lt;a href="https://www.oreilly.com/library/view/working-effectively-with/0131177052/" rel="noopener noreferrer"&gt;Working Effectively with Legacy Code&lt;/a&gt;, he tells us about yet another type of seams:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Only a couple of languages have a build stage before compilation. C and C++ are the most common of them. [...] I’m actually glad that C and C++ have a preprocessor because the preprocessor gives us more seams.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That stage before compilation, the &lt;strong&gt;preprocessing&lt;/strong&gt;, is what we interested in during the course of this article.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to get from &lt;code&gt;.c&lt;/code&gt; to &lt;code&gt;.o&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;So, before passing source code on to the compiler, C and C++ employ a preprocessing stage. During this phase, the preprocessor fulfills some basic tasks -- with its output still being valid C or C++ code. This output is called &lt;em&gt;preprocessed source code&lt;/em&gt;, according to the &lt;a href="https://gcc.gnu.org/onlinedocs/cpp/" rel="noopener noreferrer"&gt;preprocessor docs&lt;/a&gt; of the GNU project.&lt;/p&gt;

&lt;p&gt;The diagram below shows the two steps involved in converting a C source file into an object file: preprocessing and compiling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbklhagn8ydju5p6xjoy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbklhagn8ydju5p6xjoy0.png" alt="objects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tip: To inspect the preprocessed source file, you can use &lt;code&gt;gcc -E foo.c&lt;/code&gt;. This will skip the compile step and print the preprocessor result right to the terminal.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Preprocessor Produces Units
&lt;/h2&gt;

&lt;p&gt;For the matter of decoupling units, we may utilize the preprocessed source file.&lt;/p&gt;

&lt;p&gt;In fact, there's another way to look at it: The preprocessor generates different &lt;em&gt;instances&lt;/em&gt; of the same source file for each configuration we wish to have, before they are passed on to the compiler:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fha8im31rjd2ucr1qfvfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fha8im31rjd2ucr1qfvfe.png" alt="objects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having several instances is a great achievement already. To make each instance somewhat unique, we will now introduce parameters.&lt;br&gt;
We may even, in Object-Oriented terms, think of &lt;strong&gt;source files as classes&lt;/strong&gt;. &lt;br&gt;
Each preprocessed file can then be modeled as an instance of that class, i.e. as an object.&lt;/p&gt;

&lt;p&gt;Let's say we define a class &lt;code&gt;SourceFile&lt;/code&gt; that has a &lt;code&gt;config&lt;/code&gt; attribute. Then, the preprocessed files can be modeled as objects of that type, parameterized by the specific value of the &lt;code&gt;config&lt;/code&gt; attribute:&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Object&lt;/strong&gt; | &lt;strong&gt;Type&lt;/strong&gt; | &lt;strong&gt;Value of &lt;code&gt;config&lt;/code&gt;&lt;/strong&gt; |&lt;br&gt;
| Preprocessed Production File | SourceFile | PRODUCTION |&lt;br&gt;
| Preprocessed Test File | SourceFile | TEST |&lt;/p&gt;
&lt;h2&gt;
  
  
  A Practical Example
&lt;/h2&gt;

&lt;p&gt;In practice, there are no such classes of course. So let's see how you would do that in a Makefile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONFIG_PRODUCTION = 0
CONFIG_TEST = 1

driver.o: driver.c driver.h
  gcc -c driver.c -o driver.o

foo_production: foo.c driver.o
  gcc -DCONFIG=$(CONFIG_PRODUCTION) foo.c driver.o -o foo_production

foo_test: foo.c driver.o
  gcc -DCONFIG=$(CONFIG_TEST) foo.c driver.o -o foo_test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first thing being built is the &lt;code&gt;driver&lt;/code&gt;. It is the same for both configurations. For each of the build configurations, there is a corresponding &lt;code&gt;foo_&lt;/code&gt; target. You will notice that the same source file (&lt;code&gt;foo.c&lt;/code&gt;) is used for both of these. This is intentional, as we&lt;br&gt;
want the preprocessor to modify them right before compilation.&lt;/p&gt;

&lt;p&gt;Here, the value of the &lt;code&gt;config&lt;/code&gt; attribute (now the &lt;code&gt;CONFIG&lt;/code&gt; macro) is determined by the &lt;code&gt;-D&lt;/code&gt; flag passed to the compiler. You would then put some extra preprocessor statements into the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// foo.c

#include "driver.h"

#define CONFIG_PRODUCTION 0
#define CONFIG_TEST 1

int main(void) {
#if CONFIG == CONFIG_PRODUCTION
  driver_doA();
#elif CONFIG == CONFIG_TEST
  driver_doB();
#else
#error "Invalid CONFIG!"
#endif
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That way, the preprocessor effectively switches between two code blocks, depending on how it is called by the Makefile.&lt;/p&gt;

&lt;p&gt;Tip: Inspect the preprocessed files to watch how the code is actually swapped!&lt;/p&gt;

&lt;p&gt;That's probably all we need in order to accomplish our goal: software units, decoupled from each other using the preprocessor.&lt;/p&gt;

&lt;p&gt;This approach has the obvious drawback that your code gets cluttered with &lt;code&gt;ifdef&lt;/code&gt;s. Compared to link time decoupling though, the compiler can probably do a better job optimizing, as you don't need to separate code into different compile units (c files) for this to work.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tool Support
&lt;/h1&gt;

&lt;p&gt;In my experience, tool support for both the link and preprocessor approach is somewhat better than for decoupling on the object level. Jumping to function definition as well as single stepping in the debugger works seamlessly without an indirection through function pointers. Also, code sections disabled by preprocessor macros are usually highlighted accordingly by IDEs.&lt;/p&gt;

&lt;p&gt;Now that I'm thinking about it: &lt;em&gt;Do you know of an IDE that supports following function pointers the way you want it?&lt;/em&gt; Do not hesitate to get in touch with me via Twitter!&lt;/p&gt;

&lt;h1&gt;
  
  
  No need to Re-build
&lt;/h1&gt;

&lt;p&gt;Before doing a comparison of all three approaches, I would like to highlight one aspect of the link level method I think is really important:&lt;br&gt;
This is the only approach that allows you to leave your object files untouched. That's really a great feature if you think about it: no need to re-compile anything when switching from &lt;code&gt;testing&lt;/code&gt; to &lt;code&gt;production&lt;/code&gt;. There is a perfectly clear separation of internal debugging code and code that's going to be shipped with the actual product.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;To sum it up, here's a table of all pros and cons, at a glance.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Object&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;th&gt;Preprocessor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Runtime Performance&lt;/td&gt;
&lt;td&gt;- -&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool Support&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;++&lt;/td&gt;
&lt;td&gt;++&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime Flexibility&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UML Modelling&lt;/td&gt;
&lt;td&gt;++&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testability&lt;/td&gt;
&lt;td&gt;++&lt;/td&gt;
&lt;td&gt;++&lt;/td&gt;
&lt;td&gt;++&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compile-Time Checking&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;++&lt;/td&gt;
&lt;td&gt;++&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Readability&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;++&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are mostly subjective metrics, of course. It depends on your project's requirements which method suits you best -- it may even be a combination of all three of them.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sourceware.org/binutils/docs/ld/" rel="noopener noreferrer"&gt;GNU Linker Manual&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>embedded</category>
      <category>c</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Fixing Typos while Writing -- Two Ideas</title>
      <dc:creator>Steffen Ronalter</dc:creator>
      <pubDate>Sun, 23 Sep 2018 09:31:57 +0000</pubDate>
      <link>https://dev.to/ronalterde/fixing-typos-while-writing----two-ideas-242</link>
      <guid>https://dev.to/ronalterde/fixing-typos-while-writing----two-ideas-242</guid>
      <description>

&lt;p&gt;Here are some thoughts on text editing. No matter what kind of text you write -- source code, articles, to-do lists, books -- there's always a chance you get a single letter wrong at one point. Depending on your touch typing skills, this might not happen very often. But &lt;em&gt;when&lt;/em&gt; it happens, &lt;strong&gt;what do you do?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do you press and hold the backspace key until you get back to the typo?&lt;/li&gt;
&lt;li&gt;Do you jump back to the bad letter, fix it like a surgeon&lt;sup id="fnref1"&gt;1&lt;/sup&gt; and continue writing?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My experience
&lt;/h2&gt;

&lt;p&gt;Personally, I used to (rather unconsciously) adhere to the second approach. One day, however, I found out that even the Vim editor has support for &lt;a href="http://vimhelp.appspot.com/insert.txt.html"&gt;deleting the last word before the cursor&lt;/a&gt; while typing in &lt;em&gt;insert&lt;/em&gt; mode. This is not typical though. Usually, there are two steps involved: first, you use movement commands to get to the desired text position and then enter &lt;em&gt;insert&lt;/em&gt; mode.&lt;/p&gt;

&lt;p&gt;Although I'm a big fan of Vim's fantastic movement commands, this made me change my view to another perspective. What kind of habit would you develop if every typo was really &lt;strong&gt;easy to fix?&lt;/strong&gt; Your brain may think something like: "It's not critical to get it right the first time -- it's not a big deal anyway". So there's &lt;strong&gt;no motivation&lt;/strong&gt; for typing words correctly on the first attempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better use the first approach?
&lt;/h2&gt;

&lt;p&gt;To me, deleting the entire last word sounds a bit drastic at first. You did put some effort into writing it in the first place, did you? Nevertheless, I think the training effect might be worth it. So I will try it for some time and see whether there's a positive effect on my typing.&lt;/p&gt;

&lt;p&gt;What do you think? Are there any scientific studies about this? I would love to know your opinion and personal experience.&lt;/p&gt;

&lt;p&gt;To be complete: the Vim editor is by far not the only one to implement the &lt;em&gt;delete last word&lt;/em&gt; feature.&lt;br&gt;
You can use &lt;code&gt;Ctrl-w&lt;/code&gt; on the terminal and inside Emacs. Many GUI applications support &lt;code&gt;Ctrl-Backspace&lt;/code&gt; for doing the same.&lt;/p&gt;

&lt;p&gt;This post has originally been published on &lt;a href="http://steffen.ronalter.de"&gt;steffen.ronalter.de&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Example for Vim: Let's say you wrote 'house' instead of 'horse', you can do 'Furr' to fix that. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;


</description>
      <category>touchtyping</category>
      <category>vim</category>
      <category>emacs</category>
    </item>
    <item>
      <title>From Subversion to Git: Snapshots</title>
      <dc:creator>Steffen Ronalter</dc:creator>
      <pubDate>Sat, 23 Jun 2018 19:45:07 +0000</pubDate>
      <link>https://dev.to/ronalterde/from-subversion-to-git-snapshots-1hej</link>
      <guid>https://dev.to/ronalterde/from-subversion-to-git-snapshots-1hej</guid>
      <description>&lt;p&gt;What does it mean that we talk about snapshots of our Git repository, while in Subversion we think in terms of file changes? For me at least, the key to understanding Git is that every commit is, in fact, a snapshot of the entire project. Not a list of patches. Not a difference to the previous commit. Just &lt;strong&gt;a snapshot of the whole thing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Git snapshots everything&lt;/em&gt;, they said. Coming from Subversion, this is hard to believe. How would a version control system scale if it stored the entire project state again and again, with each and every commit?&lt;/p&gt;

&lt;p&gt;First, let's do a little experiment on how one might approach version control &lt;strong&gt;intuitively&lt;/strong&gt;, without considering neither Git nor Subversion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Poor Man's Version Control
&lt;/h2&gt;

&lt;p&gt;Let's say we have a project called &lt;code&gt;myapp&lt;/code&gt; stored in a directory of that name. All it contains is a main.c file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myapp
  main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without version control, how would you track changes in order to be able to restore a particular state later? Easy enough, you might say: Just create a copy of the entire &lt;code&gt;myapp&lt;/code&gt; directory and call it something like &lt;code&gt;myapp-&amp;lt;version&amp;gt;&lt;/code&gt;. After a while, you would end up with a bunch of &lt;em&gt;backup&lt;/em&gt; directories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myapp-01
  main.c
myapp-&amp;lt;...&amp;gt;
  main.c
myapp-&amp;lt;N&amp;gt;
  main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To step back to a previous state in history, you might go and replace the entire &lt;code&gt;myapp&lt;/code&gt; directory by one of these &lt;em&gt;snapshots&lt;/em&gt; created previously.&lt;/p&gt;

&lt;p&gt;In order to avoid wasting space by keeping so much redundant information, you might consider putting everything into a gzipp'ed archive and deleting all the backup directories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tar -cvzf myapp.tgz myapp-*
rm -r myapp-*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interestingly, this naive approach is not completely different from the way Git actually works.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Git does it
&lt;/h2&gt;

&lt;p&gt;Every time you create a commit, Git takes the content of each added or modified file, compresses it and stores it in an internal &lt;em&gt;object database&lt;/em&gt; together with a &lt;em&gt;commit&lt;/em&gt; object that holds some meta information&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. This approach makes it easy to reason about, as it's no more difficult than what we've done in the simple attempt mentioned above.&lt;/p&gt;

&lt;p&gt;You may realize a big drawback here though: Although individual file contents are compressed -- which is fine--, even small changes &lt;em&gt;between commits&lt;/em&gt; will cause massive duplication inside the object database.&lt;/p&gt;

&lt;p&gt;In Git, this scalability problem is simply ignored at the first stage and solved later on. In a process called &lt;em&gt;packing&lt;/em&gt;, all the objects are delta compressed and moved into one or more &lt;em&gt;packfiles&lt;/em&gt;. This is done on several occasions; you can enforce it using &lt;code&gt;git gc --aggressive&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The drawing below shows a simplified illustration of the storage of compressed file content into blob objects as well as the packfile generation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fsteffen.ronalter.de%2Fassets%2Fobjects.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fsteffen.ronalter.de%2Fassets%2Fobjects.png" alt="objects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Even for everyday Git usage it is vitally important to understand a bit of its inner workings; it's good to see that the basic idea is not inherently complex but more or less identical with what we might come up with anyway.&lt;/p&gt;

&lt;p&gt;This understanding gives us the power to get a grasp of all the more advanced features like branching, merging and rebasing.&lt;/p&gt;

&lt;p&gt;This post has originally been published on &lt;a href="http://steffen.ronalter.de" rel="noopener noreferrer"&gt;steffen.ronalter.de&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Packfiles" rel="noopener noreferrer"&gt;Git Packfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/docs/git-repack" rel="noopener noreferrer"&gt;git repack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;For all the details please refer to the section &lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Git-Objects" rel="noopener noreferrer"&gt;Git Objects&lt;/a&gt; of the excellent Pro Git book. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>git</category>
      <category>subversion</category>
      <category>snapshots</category>
    </item>
  </channel>
</rss>
