<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>testing &amp;mdash; musicmatzes blog</title>
    <link>https://beyermatthias.de/tag:testing</link>
    <description></description>
    <pubDate>Thu, 07 May 2026 03:21:50 +0200</pubDate>
    <item>
      <title>Setup for linux kernel dev using qemu</title>
      <link>https://beyermatthias.de/setup-for-linux-kernel-dev-using-qemu</link>
      <description>&lt;![CDATA[I could not think of a better title, I&#39;m sorry.&#xA;&#xA;These are notes how to create a kernel which can be booted in qemu and pass a&#xA;drive to it which has loadable kernel modules.&#xA;&#xA;!-- more --&#xA;&#xA;The idea&#xA;&#xA;I wanted to play around with the linux kernel and write a minimal filesystem&#xA;inside the kernel tree. I wanted to boot the kernel in a QEMU, as I do not&#xA;want to mess with my running kernel.&#xA;&#xA;Here are the steps I did (on a debian VM I run on my universitys&#xA;infrastructure).&#xA;&#xA;Setup&#xA;&#xA;sudo apt-get install build-essential bc git gcc&#xA;git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git&#xA;cd linux&#xA;make x8664defconfig&#xA;make kvmconfig&#xA;make menuconfig&#xA;&#xA;The last step brings up the kernel configuration interface, which I used to&#xA;enable SATA&#xA;(Device Drivers -  Serial ATA and Parallel ATA drivers (libata) -  Generic ATA support)&#xA;support which is needed to be able to mount a device into the qemu instance,&#xA;where we can put things to play around with in the VM.&#xA;&#xA;I then did a make -j 16 (if you have not 8 cores, use a lower number).&#xA;&#xA;While the kernel compiled, I created a busybox initramfs. I used&#xA;this blog article for how to do it.&#xA;I&#39;ll dump in the commands from the blog article, for detailed information, go&#xA;and read it, it&#39;s a really good article. I didn&#39;t do the speed-optimizing&#xA;things, as the QEMU boots fast enough for me (~3 seconds).&#xA;&#xA;(I used the latest busybox, but I don&#39;t see why it should work with the one&#xA;from the article, which is about two versions old)&#xA;&#xA;curl http://busybox.net/downloads/busybox-1.23.2.tar.bz2 | tar xjf -&#xA;cd busybox-1.23.2&#xA;mkdir -pv /tmp/obj/busybox-x86&#xA;make O=/tmp/obj/busybox-x86 defconfig&#xA;make O=/tmp/obj/busybox-x86 menuconfig # See below why&#xA;cd /tmp/obj/busybox-x86&#xA;make -j 16&#xA;&#xA;it does not install in your system, so you can execute this without fear&#xA;make install&#xA;&#xA;mkdir -p /tmp/initramfs/x86-busybox&#xA;cd /tmp/initramfs/x86-busybox&#xA;mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}&#xA;cp -av /tmp/obj/busybox-x86/install/* .&#xA;&#xA;now edit the init script&#xA;vim init&#xA;&#xA;You have to enable busybox build as static binary (with the menuconfig&#xA;part).&#xA;&#xA;The init script I use:&#xA;&#xA;!/bin/sh&#xA;&#xA;echo &#34;INIT SCRIPT&#34;&#xA;&#xA;mount -t proc none /proc&#xA;mount -t sysfs none /sys&#xA;mount -t debugfs none /sys/kernel/debug&#xA;&#xA;mkdir /tmp&#xA;mount -t tmpfs none /tmp&#xA;&#xA;mdev -s # We need this to find /dev/sda later&#xA;&#xA;echo -e &#34;\nBoot took $(cut -d&#39; &#39; -f1 /proc/uptime) seconds\n&#34;&#xA;&#xA;exec /bin/sh&#xA;&#xA;The init script boots into a /bin/sh. We can now build the initramfs with&#xA;it:&#xA;&#xA;chmod +x init&#xA;find . -print0 \&#xA;    | cpio --null -ov --format=newc \&#xA;    | gzip -9   /tmp/initramfs-busybox-x86.cpio.gz&#xA;&#xA;Try it out (1)&#xA;&#xA;Now we can try it out, whether the kernel boots and we get out shell:&#xA;&#xA;In the kernel tree:&#xA;qemu-system-x8664 \&#xA;    -kernel arch/x8664/boot/bzImage \&#xA;    -initrd /tmp/initramfs-busybox-x86.cpio.gz \&#xA;    -nographic -append &#34;console=ttyS0&#34;&#xA;&#xA;We should see some output like this:&#xA;&#xA;[...]&#xA;[    7.170702] Freeing unused kernel memory: 1200K (ffffffff81f55000 - ffffffff82081000)&#xA;[    7.171539] Write protecting the kernel read-only data: 14336k&#xA;[    7.177328] Freeing unused kernel memory: 816K (ffff880001934000 - ffff880001a00000)&#xA;[    7.219360] Freeing unused kernel memory: 1116K (ffff880001ce9000 - ffff880001e00000)&#xA;INIT SCRIPT&#xA;mount: mounting none on /sys/kernel/config failed: No such file or directory&#xA;mount: mounting none on /tmp failed: No such file or directory&#xA;&#xA;Boot took 7.33 seconds&#xA;&#xA;/bin/sh: can&#39;t access tty; job control turned off&#xA;/ # [    7.630681] input: ImExPS/2 BYD TouchPad as /devices/platform/i8042/serio1/input/input3&#xA;&#xA;/ #&#xA;&#xA;(Yes, the output is slightly messed up... but hey! We just booted a linux&#xA;kernel in a QEMU!&#xA;&#xA;Load the kernel module&#xA;&#xA;We can now create a kernel module in the linux kernel tree:&#xA;&#xA;In the kernel tree&#xA;git checkout -b my-module&#xA;mkdir fs/iamcoolfs/ # because I like filesystems&#xA;cat &lt;EOS  ./fs/iamcoolfs/Kconfig&#xA;config COOLFS&#xA;        tristate &#34;COOLFS support&#34;&#xA;        help&#xA;          Private FS for playing and learning FS programming&#xA;&#xA;          This will definitively eat everything you put into it.&#xA;&#xA;EOS&#xA;cat &lt;EOS  ./fs/iamcoolfs/Makefile&#xA;#&#xA;Makefile for the linux mb-filesystem routines.&#xA;&#xA;obj-$(CONFIGMBFS) += coolfs.o&#xA;EOS&#xA;cat &lt;EOS  ./fs/iamcoolfs/coolfs.c&#xA;include linux/init.h&#xA;include linux/module.h&#xA;&#xA;static int _init coolfsinit(void)&#xA;{&#xA;        prdebug(&#34;cool module loaded\n&#34;);&#xA;        return 0;&#xA;}&#xA;&#xA;static void exit coolfsfini(void)&#xA;{&#xA;        prdebug(&#34;cool module unloaded\n&#34;);&#xA;}&#xA;&#xA;moduleinit(coolfsinit);&#xA;moduleexit(coolfsfini);&#xA;&#xA;MODULELICENSE(&#34;GPL&#34;);&#xA;MODULEAUTHOR(&#34;YOUR NAME GOES HERE&#34;);&#xA;&#xA;EOS&#xA;&#xA;This creates all the files we need for a minimal module. Because I like&#xA;filesystems and I really want to implement a minimal filesystem, I chose to&#xA;create the files in ./fs, but I guess_ it shouldn&#39;t matter.&#xA;&#xA;Make sure you adapt the fs/Kconfig file to find your new module! Put&#xA;&#xA;source &#34;fs/coolfs/Kconfig&#34;&#xA;&#xA;into it.&#xA;&#xA;Now you can execute make menuconfig and find the configuration option for&#xA;your new module.&#xA;We can also simply make M=fs/coolfs to build the module.&#xA;Now we create a (ext2) disk where we can cp the module to, so we can mount&#xA;that disk into our QEMU and use the module there:&#xA;&#xA;dd if=/dev/zero of=/tmp/disk bs=4M count=100&#xA;sudo mkfs.ext2 /tmp/disk # you could also try ext4, for example&#xA;mkdir /tmp/disk-mount&#xA;sudo mount /tmp/disk /tmp/disk-mount&#xA;cp fs/coolfs/coolfs.ko /tmp/disk-mount/&#xA;sudo umount /tmp/disk-mount&#xA;&#xA;Try it out (2)&#xA;&#xA;And when we boot our QEMU now with -hda /tmp/disk, we can find /dev/sda in&#xA;the booted instance and mount that:&#xA;&#xA;In the booted VM&#xA;mkdir sda&#xA;mount /dev/sda ./sda&#xA;ls sda&#xA;&#xA;Happy FS dev!&#xA;&#xA;tags:  #c #linux #open source #programming #software #testing #kernel&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>I could not think of a better title, I&#39;m sorry.</p>

<p>These are notes how to create a kernel which can be booted in qemu and pass a
drive to it which has loadable kernel modules.</p>



<h1 id="the-idea" id="the-idea">The idea</h1>

<p>I wanted to play around with the linux kernel and write a minimal filesystem
inside the kernel tree. I wanted to boot the kernel in a QEMU, as I do not
want to mess with my running kernel.</p>

<p>Here are the steps I did (on a debian VM I run on my universitys
infrastructure).</p>

<h1 id="setup" id="setup">Setup</h1>

<pre><code class="language-bash">sudo apt-get install build-essential bc git gcc
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
make x86_64_defconfig
make kvmconfig
make menuconfig
</code></pre>

<p>The last step brings up the kernel configuration interface, which I used to
enable SATA
(<code>Device Drivers -&gt; Serial ATA and Parallel ATA drivers (libata) -&gt; Generic ATA support</code>)
support which is needed to be able to mount a device into the qemu instance,
where we can put things to play around with in the VM.</p>

<p>I then did a <code>make -j 16</code> (if you have not 8 cores, use a lower number).</p>

<p>While the kernel compiled, I created a busybox initramfs. I used
<a href="https://mgalgs.github.io/2015/05/16/how-to-build-a-custom-linux-kernel-for-qemu-2015-edition.html">this blog article for how to do it</a>.
I&#39;ll dump in the commands from the blog article, for detailed information, go
and read it, it&#39;s a really good article. I didn&#39;t do the speed-optimizing
things, as the QEMU boots fast enough for me (~3 seconds).</p>

<p>(I used the latest busybox, but I don&#39;t see why it should work with the one
from the article, which is about two versions old)</p>

<pre><code class="language-bash">curl http://busybox.net/downloads/busybox-1.23.2.tar.bz2 | tar xjf -
cd busybox-1.23.2
mkdir -pv /tmp/obj/busybox-x86
make O=/tmp/obj/busybox-x86 defconfig
make O=/tmp/obj/busybox-x86 menuconfig # See below why
cd /tmp/obj/busybox-x86
make -j 16

# it does not install in your system, so you can execute this without fear
make install

mkdir -p /tmp/initramfs/x86-busybox
cd /tmp/initramfs/x86-busybox
mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}
cp -av /tmp/obj/busybox-x86/_install/* .

# now edit the init script
vim init
</code></pre>

<p>You have to enable busybox build as static binary (with the <code>menuconfig</code>
part).</p>

<p>The <code>init</code> script I use:</p>

<pre><code class="language-bash">#!/bin/sh

echo &#34;INIT SCRIPT&#34;

mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug

mkdir /tmp
mount -t tmpfs none /tmp

mdev -s # We need this to find /dev/sda later

echo -e &#34;\nBoot took $(cut -d&#39; &#39; -f1 /proc/uptime) seconds\n&#34;

exec /bin/sh
</code></pre>

<p>The <code>init</code> script boots into a <code>/bin/sh</code>. We can now build the initramfs with
it:</p>

<pre><code class="language-bash">chmod +x init
find . -print0 \
    | cpio --null -ov --format=newc \
    | gzip -9 &gt; /tmp/initramfs-busybox-x86.cpio.gz
</code></pre>

<h1 id="try-it-out-1" id="try-it-out-1">Try it out (1)</h1>

<p>Now we can try it out, whether the kernel boots and we get out shell:</p>

<pre><code class="language-bash"># In the kernel tree:
qemu-system-x86_64 \
    -kernel arch/x86_64/boot/bzImage \
    -initrd /tmp/initramfs-busybox-x86.cpio.gz \
    -nographic -append &#34;console=ttyS0&#34;
</code></pre>

<p>We should see some output like this:</p>

<pre><code>[...]
[    7.170702] Freeing unused kernel memory: 1200K (ffffffff81f55000 - ffffffff82081000)
[    7.171539] Write protecting the kernel read-only data: 14336k
[    7.177328] Freeing unused kernel memory: 816K (ffff880001934000 - ffff880001a00000)
[    7.219360] Freeing unused kernel memory: 1116K (ffff880001ce9000 - ffff880001e00000)
INIT SCRIPT
mount: mounting none on /sys/kernel/config failed: No such file or directory
mount: mounting none on /tmp failed: No such file or directory

Boot took 7.33 seconds

/bin/sh: can&#39;t access tty; job control turned off
/ # [    7.630681] input: ImExPS/2 BYD TouchPad as /devices/platform/i8042/serio1/input/input3

/ #
</code></pre>

<p>(Yes, the output is slightly messed up... but hey! We just booted a linux
kernel in a QEMU!</p>

<h1 id="load-the-kernel-module" id="load-the-kernel-module">Load the kernel module</h1>

<p>We can now create a kernel module in the linux kernel tree:</p>

<pre><code class="language-bash"># In the kernel tree
git checkout -b my-module
mkdir fs/iamcoolfs/ # because I like filesystems
cat &lt;&lt;EOS &gt; ./fs/iamcoolfs/Kconfig
config COOL_FS
        tristate &#34;COOLFS support&#34;
        help
          Private FS for playing and learning FS programming

          This will definitively eat everything you put into it.

EOS
cat &lt;&lt;EOS &gt; ./fs/iamcoolfs/Makefile
#
# Makefile for the linux mb-filesystem routines.
#

obj-$(CONFIG_MB_FS) += coolfs.o
EOS
cat &lt;&lt;EOS &gt; ./fs/iamcoolfs/coolfs.c
#include &lt;linux/init.h&gt;
#include &lt;linux/module.h&gt;

static int __init coolfs_init(void)
{
        pr_debug(&#34;cool module loaded\n&#34;);
        return 0;
}

static void __exit coolfs_fini(void)
{
        pr_debug(&#34;cool module unloaded\n&#34;);
}

module_init(coolfs_init);
module_exit(coolfs_fini);

MODULE_LICENSE(&#34;GPL&#34;);
MODULE_AUTHOR(&#34;&lt;YOUR NAME GOES HERE&gt;&#34;);

EOS
</code></pre>

<p>This creates all the files we need for a minimal module. Because I like
filesystems and I really want to implement a minimal filesystem, I chose to
create the files in <code>./fs</code>, but I <em>guess</em> it shouldn&#39;t matter.</p>

<p>Make sure you adapt the <code>fs/Kconfig</code> file to find your new module! Put</p>

<pre><code>source &#34;fs/coolfs/Kconfig&#34;
</code></pre>

<p>into it.</p>

<p>Now you can execute <code>make menuconfig</code> and find the configuration option for
your new module.
We can also simply <code>make M=fs/coolfs</code> to build the module.
Now we create a (ext2) disk where we can <code>cp</code> the module to, so we can mount
that disk into our QEMU and use the module there:</p>

<pre><code class="language-bash">dd if=/dev/zero of=/tmp/disk bs=4M count=100
sudo mkfs.ext2 /tmp/disk # you could also try ext4, for example
mkdir /tmp/disk-mount
sudo mount /tmp/disk /tmp/disk-mount
cp fs/coolfs/coolfs.ko /tmp/disk-mount/
sudo umount /tmp/disk-mount
</code></pre>

<h1 id="try-it-out-2" id="try-it-out-2">Try it out (2)</h1>

<p>And when we boot our QEMU now with <code>-hda /tmp/disk</code>, we can find <code>/dev/sda</code> in
the booted instance and mount that:</p>

<pre><code class="language-bash"># In the booted VM
mkdir sda
mount /dev/sda ./sda
ls sda
</code></pre>

<p>Happy FS dev!</p>

<p>tags:  <a href="https://beyermatthias.de/tag:c" class="hashtag"><span>#</span><span class="p-category">c</span></a> <a href="https://beyermatthias.de/tag:linux" class="hashtag"><span>#</span><span class="p-category">linux</span></a> <a href="https://beyermatthias.de/tag:open" class="hashtag"><span>#</span><span class="p-category">open</span></a> source <a href="https://beyermatthias.de/tag:programming" class="hashtag"><span>#</span><span class="p-category">programming</span></a> <a href="https://beyermatthias.de/tag:software" class="hashtag"><span>#</span><span class="p-category">software</span></a> <a href="https://beyermatthias.de/tag:testing" class="hashtag"><span>#</span><span class="p-category">testing</span></a> <a href="https://beyermatthias.de/tag:kernel" class="hashtag"><span>#</span><span class="p-category">kernel</span></a></p>
]]></content:encoded>
      <guid>https://beyermatthias.de/setup-for-linux-kernel-dev-using-qemu</guid>
      <pubDate>Tue, 01 Nov 2016 16:37:55 +0100</pubDate>
    </item>
    <item>
      <title>Breaking the code (without touching)</title>
      <link>https://beyermatthias.de/breaking-the-code-without-touching</link>
      <description>&lt;![CDATA[I managed to break one of my codebase (the master branch) without even&#xA;touching it.&#xA;&#xA;!-- more --&#xA;&#xA;If you think about, the &#34;issue&#34; I ran into is trivial.&#xA;It really is.&#xA;Though, I want to write about it because often, these things get too little&#xA;attention in my opinion.&#xA;&#xA;So what did I do?&#xA;&#xA;I maintain this project [task-hookrs].&#xA;The project itself depends on a few other crates. I updated these dependencies&#xA;and then released a new version of my crate.&#xA;&#xA;The rewrite included some lines which I had to change, not a big deal&#xA;actually.&#xA;One of my dependencies, namingly serde had&#xA;a breaking change from 0.7.* to 0.8.0 which resulted in a small rewrite of a&#xA;portion of my code.&#xA;No functionality was changed, though.&#xA;&#xA;I released 0.2.2 after the dependencies were upgraded. The last version&#xA;before that version was 0.2.1.&#xA;And despite me not changing any functionality, the micro-release was a&#xA;mistake.&#xA;Not because API changes (which I didn&#39;t have) but because of link-time&#xA;dependencies.&#xA;&#xA;My other project, [imag] dependes on [task-hookrs], but&#xA;the dependency specification states task-hookrs = &#34;0.2&#34; (note the missing&#xA;.1 at the end).&#xA;When the master of [imag] got rebuild, it failed because [imag] itself depends&#xA;on uuid = &#34;0.2&#34;, whereas [task-hookrs] now depended on uuid = &#34;0.3&#34; - the&#xA;linker failed because the types I passed from [imag] to [task-hookrs] were&#xA;different.&#xA;&#xA;Fuck.&#xA;&#xA;What did I do? Well, I updated uuid in [imag] as well, everything solved.&#xA;But that really got me thinking.&#xA;What I should have done: Updating the minor version (0.2.1 -  0.3.0).&#xA;&#xA;We talk a lot about breaking changes in APIs and such, in fact this is why we&#xA;introduced [semantic versioning] in the Rust community.&#xA;What we do not talk about is that dependencies are also relevant when&#xA;updating.&#xA;Even the [semantic versioning] website states:&#xA;&#xA;  Given a version number MAJOR.MINOR.PATCH, increment the:&#xA;    1. MAJOR version when you make incompatible API changes,&#xA;  2. MINOR version when you add functionality in a backwards-compatible manner, and&#xA;  3. PATCH version when you make backwards-compatible bug fixes.&#xA;    Additional labels for pre-release and build metadata are available as&#xA;  extensions to the MAJOR.MINOR.PATCH format.&#xA;&#xA;Which clearly states that `MAJOR version when you make incompatible API&#xA;changes` - though nobody tells you that updating a dependency of your library&#xA;might also be a incompatible API change!&#xA;&#xA;---&#xA;&#xA;After all I&#39;m (kinda) safe here, because the [semantic versioning] spec also&#xA;contains the following:&#xA;&#xA;  Major version zero (0.y.z) is for initial development.&#xA;  Anything may change at any time.&#xA;  The public API should not be considered stable.&#xA;&#xA;So nobody can blame me.&#xA;Although this really bugs me and it really shouldn&#39;t have happened.&#xA;&#xA;[semantic versioning]: http://semver.org/&#xA;[imag]: http://imag-pim.org&#xA;[task-hookrs]: https://crates.io/crates/task-hookrs&#xA;&#xA;tags:  #programming #open source #software #testing&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>I managed to break one of my codebase (the <code>master</code> branch) without even
touching it.</p>



<p>If you think about, the “issue” I ran into is trivial.
It really is.
Though, I want to write about it because often, these things get too little
attention in my opinion.</p>

<p>So what did I do?</p>

<p>I maintain this project <a href="https://crates.io/crates/task-hookrs">task-hookrs</a>.
The project itself depends on a few other crates. I updated these dependencies
and then released a new version of my crate.</p>

<p>The rewrite included some lines which I had to change, not a big deal
actually.
One of <em>my</em> dependencies, namingly <a href="https://crates.io/crates/serde">serde</a> had
a breaking change from <code>0.7.*</code> to <code>0.8.0</code> which resulted in a small rewrite of a
portion of my code.
No functionality was changed, though.</p>

<p>I released <code>0.2.2</code> after the dependencies were upgraded. The last version
before that version was <code>0.2.1</code>.
And despite me not changing any functionality, the micro-release was a
mistake.
Not because API changes (which I didn&#39;t have) but because of link-time
dependencies.</p>

<p>My other project, <a href="http://imag-pim.org">imag</a> dependes on <a href="https://crates.io/crates/task-hookrs">task-hookrs</a>, but
the dependency specification states <code>task-hookrs = &#34;0.2&#34;</code> (note the missing
<code>.1</code> at the end).
When the <code>master</code> of <a href="http://imag-pim.org">imag</a> got rebuild, it failed because <a href="http://imag-pim.org">imag</a> itself depends
on <code>uuid = &#34;0.2&#34;</code>, whereas <a href="https://crates.io/crates/task-hookrs">task-hookrs</a> now depended on <code>uuid = &#34;0.3&#34;</code> – the
linker failed because the types I passed from <a href="http://imag-pim.org">imag</a> to <a href="https://crates.io/crates/task-hookrs">task-hookrs</a> were
different.</p>

<p>Fuck.</p>

<p>What did I do? Well, I updated <code>uuid</code> in <a href="http://imag-pim.org">imag</a> as well, everything solved.
But that really got me thinking.
What I should have done: Updating the <code>minor</code> version (<code>0.2.1 -&gt; 0.3.0</code>).</p>

<p>We talk a lot about breaking changes in APIs and such, in fact this is why we
introduced <a href="http://semver.org/">semantic versioning</a> in the Rust community.
What we do not talk about is that dependencies are also relevant when
updating.
Even the <a href="http://semver.org/">semantic versioning</a> website states:</p>

<blockquote><p>Given a version number MAJOR.MINOR.PATCH, increment the:</p>
<ol><li>MAJOR version when you make incompatible API changes,</li>
<li>MINOR version when you add functionality in a backwards-compatible manner, and</li>
<li>PATCH version when you make backwards-compatible bug fixes.</li></ol>

<p>Additional labels for pre-release and build metadata are available as
extensions to the MAJOR.MINOR.PATCH format.</p></blockquote>

<p>Which clearly states that <code>MAJOR version when you make incompatible API
changes</code> – though nobody tells you that updating a dependency of your library
might also be a incompatible API change!</p>

<hr>

<p>After all I&#39;m (kinda) safe here, because the <a href="http://semver.org/">semantic versioning</a> spec also
contains the following:</p>

<blockquote><p>Major version zero (0.y.z) is for initial development.
Anything may change at any time.
The public API should not be considered stable.</p></blockquote>

<p>So nobody can blame me.
Although this really bugs me and it really shouldn&#39;t have happened.</p>

<p>tags:  <a href="https://beyermatthias.de/tag:programming" class="hashtag"><span>#</span><span class="p-category">programming</span></a> <a href="https://beyermatthias.de/tag:open" class="hashtag"><span>#</span><span class="p-category">open</span></a> source <a href="https://beyermatthias.de/tag:software" class="hashtag"><span>#</span><span class="p-category">software</span></a> <a href="https://beyermatthias.de/tag:testing" class="hashtag"><span>#</span><span class="p-category">testing</span></a></p>
]]></content:encoded>
      <guid>https://beyermatthias.de/breaking-the-code-without-touching</guid>
      <pubDate>Tue, 25 Oct 2016 16:37:55 +0200</pubDate>
    </item>
    <item>
      <title>Test-Driven Project Initialization</title>
      <link>https://beyermatthias.de/test-driven-project-initialization</link>
      <description>&lt;![CDATA[Imagine you have an idea for an awesome web application. Or an desktop program&#xA;or even a library in your favourite programming language do make complicated&#xA;things easy. You really want to implement it, maybe you already know that it&#xA;will work really well, maybe you don&#39;t and you want to try whether you can&#xA;make it work or not.&#xA;&#xA;But how to start?&#xA;&#xA;!-- more --&#xA;&#xA;The first steps are easy. You make a new directory, maybe a directory&#xA;structure. You create some files, such as a README.md or a LICENSE file.&#xA;You create a MyGreatSoftware.MyFavouriteLanguage file and you open it in&#xA;your favourite text editor or IDE.&#xA;&#xA;But then you struggle and you don&#39;t know what to do first. Let&#39;s imagine you&#xA;want to write a commandline application - do you start with the argument&#xA;parsing part or do you add some backend abstraction in the first step? Do you&#xA;build up a great framework around some functionality so you can use it more&#xA;easily later on or do you implement functionality directly?&#xA;&#xA;I had such problems, too. I started a project for a rather simple commandline&#xA;application and I really didn&#39;t know where to start. It was a ruby project, so&#xA;Imy initial steps where rather clear: I installed some dependencies I wanted&#xA;to use, such as an option parsing library and a commandline output helper for&#xA;pretty formatted output (colored things and so on). I created the directories&#xA;lib and bin - and then the file lib/app.rb (where &#34;app&#34; is the name of&#xA;the program.&#xA;&#xA;And then I failed to continue because I didn&#39;t know what to implement first.&#xA;So I ended up implementing the commandline parsing part and the backend&#xA;abstractions at the same time (on different branches, of course) and it&#xA;resulted in me deleting the project because things got complicated.&#xA;&#xA;Then, I restarted the project and did something I&#39;ve never done before: I&#xA;started to do TDD and I started with the very first line of code.&#xA;&#xA;Disclaimer: I&#39;m not a TDD professionalist. I never had any training in TDD&#xA;and I don&#39;t even know whether I did it right. But it&#39;s not the point whether&#xA;you do TDD right or not here. The point is, you think about simple, neat&#xA;pieces of code with a lot more focus. You try to imaging what explicit feature&#xA;you want to have. For example your test says something like this:&#xA;&#xA;  If I pass an argument --update  a File ~/.apptimestamp gets the current&#xA;  time is appended.&#xA;&#xA;That&#39;s a really really compact thing and you can implement this in one single&#xA;line of Ruby. And that&#39;s exactly my point. You start implementing things&#xA;without building layers and layers of abstraction and losing yourself in the&#xA;codebase you created yourself for not losing track of things.&#xA;&#xA;I learned that writing tests and implementing just the very functionality&#xA;that makes the test succeed helps me a damn lot to focus on the functionality&#xA;I want to build rather than building layers and layers and afterwards having a&#xA;kind of framework which does nothing (and is mostly even too complicated to&#xA;use).&#xA;&#xA;Of course, after implementing things you can clean up your codebase and&#xA;refactor things, so the abstraction layers will be created at some point. But&#xA;that&#39;s after_ the features have been implemented. And a damn great bonus: You&#xA;have tests which are there to ensure you don&#39;t break your functionality by&#xA;refactoring and making yourself happier with the codebase.&#xA;&#xA;So that&#39;s what I call Test-Driven Project Initialization. You don&#39;t need to&#xA;perform perfect TDD and stick to it all the time. You don&#39;t need to test every&#xA;aspect of your functionality. The tests are there to keep you focused on the&#xA;functionality, not to ensure there are no bugs. Of course, that&#39;s a neat side&#xA;effect and you can continue and extend your test cases later on to find bugs.&#xA;But for Test-Driven Project Initialization it is not the point to find bugs.&#xA;&#xA;tags:  #programming #software #testing&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>Imagine you have an idea for an awesome web application. Or an desktop program
or even a library in your favourite programming language do make complicated
things easy. You really want to implement it, maybe you already know that it
will work really well, maybe you don&#39;t and you want to try whether you can
make it work or not.</p>

<p>But how to start?</p>



<p>The first steps are easy. You make a new directory, maybe a directory
structure. You create some files, such as a <code>README.md</code> or a <code>LICENSE</code> file.
You create a <code>MyGreatSoftware.MyFavouriteLanguage</code> file and you open it in
your favourite text editor or IDE.</p>

<p>But then you struggle and you don&#39;t know what to do first. Let&#39;s imagine you
want to write a commandline application – do you start with the argument
parsing part or do you add some backend abstraction in the first step? Do you
build up a great framework around some functionality so you can use it more
easily later on or do you implement functionality directly?</p>

<p>I had such problems, too. I started a project for a rather simple commandline
application and I really didn&#39;t know where to start. It was a ruby project, so
Imy initial steps where rather clear: I installed some dependencies I wanted
to use, such as an option parsing library and a commandline output helper for
pretty formatted output (colored things and so on). I created the directories
<code>lib</code> and <code>bin</code> – and then the file <code>lib/app.rb</code> (where “app” is the name of
the program.</p>

<p>And then I failed to continue because I didn&#39;t know what to implement first.
So I ended up implementing the commandline parsing part and the backend
abstractions at the same time (on different branches, of course) and it
resulted in me deleting the project because things got complicated.</p>

<p>Then, I restarted the project and did something I&#39;ve never done before: I
started to do TDD and I started with the very first line of code.</p>

<p>Disclaimer: I&#39;m not a TDD professionalist. I never had <em>any</em> training in TDD
and I don&#39;t even know whether I did it right. But it&#39;s not the point whether
you do TDD right or not here. The point is, you think about simple, neat
pieces of code with a lot more focus. You try to imaging what explicit feature
you want to have. For example your test says something like this:</p>

<blockquote><p>If I pass an argument <code>--update</code>  a File <code>~/.app_timestamp</code> gets the current
time is appended.</p></blockquote>

<p>That&#39;s a really really compact thing and you can implement this in one single
line of Ruby. And that&#39;s exactly my point. You start implementing things
without building layers and layers of abstraction and losing yourself in the
codebase you created yourself for not losing track of things.</p>

<p>I learned that writing tests and implementing <em>just the very functionality
that makes the test succeed</em> helps me a damn lot to focus on the functionality
I want to build rather than building layers and layers and afterwards having a
kind of framework which does nothing (and is mostly even too complicated to
use).</p>

<p>Of course, after implementing things you can clean up your codebase and
refactor things, so the abstraction layers will be created at some point. But
that&#39;s <em>after</em> the features have been implemented. And a damn great bonus: You
have tests which are there to ensure you don&#39;t break your functionality by
refactoring and making yourself happier with the codebase.</p>

<p>So that&#39;s what I call <em>Test-Driven Project Initialization</em>. You don&#39;t need to
perform perfect TDD and stick to it all the time. You don&#39;t need to test every
aspect of your functionality. The tests are there to keep you focused on the
functionality, not to ensure there are no bugs. Of course, that&#39;s a neat side
effect and you can continue and extend your test cases later on to find bugs.
But for Test-Driven Project Initialization it is not the point to find bugs.</p>

<p>tags:  <a href="https://beyermatthias.de/tag:programming" class="hashtag"><span>#</span><span class="p-category">programming</span></a> <a href="https://beyermatthias.de/tag:software" class="hashtag"><span>#</span><span class="p-category">software</span></a> <a href="https://beyermatthias.de/tag:testing" class="hashtag"><span>#</span><span class="p-category">testing</span></a></p>
]]></content:encoded>
      <guid>https://beyermatthias.de/test-driven-project-initialization</guid>
      <pubDate>Mon, 28 Sep 2015 16:37:42 +0200</pubDate>
    </item>
  </channel>
</rss>