Quantcast
Channel: Sander van der Burg's blog
Viewing all 159 articles
Browse latest View live

Deploying .NET applications with the Nix package manager (part 2)

$
0
0
In my previous blog post, I have explained how the Nix package manager can be used to deploy .NET applications. One of the open issues was that run-time dependencies can't be resolved in a convenient way. I have explained three possible solutions, each having its pros and cons and none of them was ideal.

After writing that blog post, I have received a number of suggestions and reactions from people from the #nixos freenode channel. Moreover, during the dinner of the SEAMS symposium in Hawaii, I have heard similar suggestions. It seems that blogging about certain issues pays off after all!

The last two days I have decided to look at these suggestions and to do some experiments at Philips. I'm happy to report that I have a follow up story now, in which I have a new solution for resolving run-time dependencies of .NET executables. This solution is also the best option (in my opinion).

Implementing a wrapper for .NET applications


Apparently .NET has a reflection API. With this reflection API you can dynamically load classes and dynamically invoke methods. You can also load assemblies dynamically from any location whether they have a strong name or not.

The .NET runtime also seems to fire an AssemblyResolve event, in case a library assembly can't be found. Apparently you can create your own event handler, dealing with such an event and use it to load a missing assembly through the reflection API.

So by taking these features into account, it is possible to create a wrapper executable capable of resolving the run-time dependencies that we need. This is what the wrapper I have developed for Nix looks like (I actually had to write some C# code for this):

using System;
using System.Reflection;
using System.IO;

namespace HelloWorldWrapper
{
class HelloWorldWrapper
{
private String[] AssemblySearchPaths = {
@"C:\cygwin\nix\store\23ga...-ALibrary",
@"C:\cygwin\nix\store\833p...-BLibrary"
};

private String ExePath =
@"C:\cygwin\nix\store\27f2...-Executable\Executable.exe";

private String MainClassName =
"SomeExecutable.Executable";

public HelloWorldWrapper(string[] args)
{
// Attach the resolve event handler to the AppDomain
// so that missing library assemblies will be searched
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve +=
new ResolveEventHandler(MyResolveEventHandler);

// Dynamically load the executable assembly
Assembly exeAssembly = Assembly.LoadFrom(ExePath);

// Lookup the main class
Type mainClass = exeAssembly.GetType(MainClassName);

// Lookup the main method
MethodInfo mainMethod = mainClass.GetMethod("Main");

// Invoke the main method
mainMethod.Invoke(this, new Object[] {args});
}

static void Main(string[] args)
{
new HelloWorldWrapper(args);
}

private Assembly MyResolveEventHandler(object sender,
ResolveEventArgs args)
{
// This handler is called only when the common language
// runtime tries to bind to the assembly and fails.

Assembly MyAssembly;
String assemblyPath = "";
String requestedAssemblyName =
args.Name.Substring(0, args.Name.IndexOf(","));

// Search for the right path of the library assembly
foreach (String curAssemblyPath in AssemblySearchPaths)
{
assemblyPath = curAssemblyPath + "/" +
requestedAssemblyName + ".dll";

if (File.Exists(assemblyPath))
break;
}

// Load the assembly from the specified path.
MyAssembly = Assembly.LoadFrom(assemblyPath);

// Return the loaded assembly.
return MyAssembly;
}

}
}

The wrapper class defined above has a number of fields. The AssemblySearchPaths field defines a String array containing all the Nix store paths of the runtime dependencies. The exePath field defines a String referring to the path of the executable in the Nix store which we want to run. The MainClassName field defines the full name of the class containing the Main method we want to run.

In the Main method of this class, we create an instance of the wrapper. In the constructor, we attach our own custom resolve event handler to the app domain controller. Then we use the reflection API to dynamically load the actual executable and to invoke the main method in the specified main class.

When we load the executable assembly, the resolve event handler is triggered a number of times. Our custom MyResolveEvent handler, tries to load to given assembly in all the search paths defined in the AssemblySearchPaths string array, which should succeed if all runtime dependencies are present.

There is a small caveat, however, with dynamically invoking the Main method of another executable. By default, the Main method in C# programs is defined like this:

namespace SomeNamespace
{
class SomeClass
{
static void Main(string[] args)
{
}
}
}

Apparently, it has no access modifier, which means the internal access modifier is used by default. The internal access modifier restricts access to this method to all members of the same assembly. This means that we cannot invoke an external Main method from a different assembly like the wrapper. To counter this, we need to make the access modifier of the actual executable public (or make the wrapper class a friend, but nonetheless we need to make a small modification anyway).

Usage


I have implemented a convenience function in Nixpkgs: dotnetenv.buildWrapper that automatically builds a .NET executable and generates a wrapper for the given executable. The function can be invoked like this:

{dotnetenv, MyAssembly1, MyAssembly2}:

dotnetenv.buildWrapper {
name = "My.Test.Assembly";
src = /path/to/source/code;
slnFile = "Assembly.sln";
assemblyInputs = [
dotnetenv.assembly20Path
MyAssembly1
MyAssembly2
];
namespace = "TestNamespace";
mainClassName = "MyTestApplication";
mainClassFile = "MyTestApplication.cs";
}

As you may see, the structure of the dotnetenv.buildWrapper is similar to the dotnetenv.buildSolution function, except that it requires several additional parameters for the wrapper, such as the namespace, class name and file location of the class containing the Main method of the actual executable. The function automatically makes the given Main method in the given main class file public and it creates a wrapper class containing the right properties to run the actual executable, such as the location of the actual executable and the paths of the run-time dependencies.

By using this wrapper function, it is possible to run a .NET executable assembly from the Nix store without much trouble.

Conclusion


In this blog post, I have implemented a wrapper executable that deals with resolving run-time dependencies of a .NET application. The wrapper uses a resolve event handler which loads all the required library assemblies through the .NET reflection API. This wrapper can be automatically generated from a convenience function, which makes it possible to run .NET applications from the Nix store, without much trouble.

References



Software deployment complexity

$
0
0
In this blog post, I'd like to talk about the software deployment discipline in general. In my career as PhD student and while visiting academic conferences, I have noticed that software deployment is (and has never been) a very popular research subject within the software engineering community.

Furthermore, I have encountered many misconceptions about what software deployment is and even some people are surprised that people do research in this field. I have also received some complaints of some reviewers that things that we do aren't novel. I have also received some vague complaints, such as: "hmm, what can the software engineering community learn from this? I don't see the point..." and "this is not a research paper".

What is software deployment?


So what is actually software deployment? One of the first software deployment papers in academic research by Carzaniga et al [1], describes this discipline as follows:

Software deployment refers to all the activities that make a software system
available for use

Some of the activities that may be required to make a software system available for use are:

  • Building software components from source code
  • Packaging software
  • Transferring the software from the producer site to consumer site
  • Installation of the software system
  • Activation of the software system
  • Software upgrades


An important thing to point out is that the activities described above are all steps to make a software system available for use. I have noticed that many people mistakenly think that software deployment is just the installation of a system, which is not true.

Essentially, the point of software deployment is that a particular software system is developed with certain goals, features and behaviour in mind by the developers. Once this software system is to be used by end-users, it typically has to be made available for use in the consumer environment. Important is that the software system behaves exactly the way the developers have intended. It turns out that, for many reasons, this process has become very complicated nowadays and it is also very difficult to give any guarantees that a software system operates as intended. In some cases, systems may not work at all.

Relationship to software engineering


So what has software deployment to do with software engineering? According to [2] software engineering can be defined as:

Software Engineering (SE) is the application of a systematic, disciplined, quantifiable approach to the development, operation, and maintenance of software, and the study of these approaches; that is, the application of engineering to software.

Within the software engineering research community, we investigate techniques to improve and/or study software development processes. Typically, the deployment step is usually the last phase in a software development project, when the development process of a software system is completed and ready to be made available to end-users.

In old traditional waterfall-style software development projects, the deployment phase is not performed so frequently. Nowadays most software development projects are iterative in which features of the software are extended and improved, so for each cycle the system has to be deployed. Especially in Agile software projects, which have short iterations (of about 2 weeks) it is crucial to be able to deploy a system easily.

Because of the way we develop software nowadays, the deployment process has become much more of a burden and that's why it is also important to have systematic, disciplined, quantifiable approaches for software deployment.

Apart from delivering systems to end-users, we also need to deploy a system to test it. In order to run a test suite, all necessary environmental dependencies must be present and correct. Without a reliable and reproducible deployment process, it becomes a burden and difficult to guarantee that tests succeed in all circumstances.

Why is software deployment complicated?



Back in the old days, software was developed for a specific machine (or hardware architecture), stored on a disk/tape and delivered to the customer. Then the customer loaded the program from the tape/disk into memory and was able to run the program. Apart from the operating system, all the required parts of the program were stored on the disk. Basically, my good old Commodore 64/128 worked like this. All software was made available on either cassette tapes or 5.25 inch floppy disks. Apart from the operating system and BASIC interpreter (which were stored in the ROM of the Commodore) everything that was required to run a program was available on the disk.

Some time later, component based software engineering (CBSE) was introduced and received wide acceptance. The advantages of CBSE were that software components can be obtained from third parties without having to develop those yourself and that components with the same or similar functionality can be shared and reused across multiple programs. CBSE greatly improved the quality of software and the productivity of developers. As a consequence, software products were no longer delivered as self-contained products, but became dependent on the components already residing on the target systems.


Although CBSE provides a number of advantages, it also introduced additional complexity and challenges. In order to be able to run a software program all dependencies must be present and correct and the program must be able to find them. There are all kinds of things that could go wrong while deploying a system. A dependency may be missing, or a program requires a newer version of a specific component. Also newer components may be incompatible with a program (sometimes this intentional, but also accidentally due to a bug on which a program may rely).


For example, in Microsoft Windows (but also on other platforms) this lead to a phenomenon called the DLL hell. Except for Windows DLLs, this phenomenon occurs in many different contexts as well, such as the JAR hell for Java programs. Even the good old AmigaOS, suffered from the same weakness although they were not that severe as they are now, because the versions of libraries didn't change that frequently.

In UNIX-like systems, such as Linux, you will notice that the degree of sharing of components through libraries is raised to almost a maximum. For these kind of systems, it is crucial to have deployment tooling to properly manage the packages installed on a system. In Linux distributions the package manager is a key aspect and also a distinct feature that sets a particular distribution apart from another. There are many package mangers around such as RPM, dpkg, portage, pacman, and Nix (which we use in our research as a basis for NixOS).


Apart from the challenges of deploying a system from scratch, many system are also upgraded because (in most cases) it's too costly and time consuming to deploy them over and over again, for each change. In most cases upgrading is a risky process, because files get modified and overwritten. An interruption or crash during an upgrade phase may have disastrous results. Also an upgrade may not always give the same results as a fresh installation of a system.

Importance of software deployment


So why is research in software deployment important?


  • First of all, (not surprisingly) software systems become bigger and increasingly more complex. Nowadays, some software systems are not only composed of many components, but these components are also distributed and deployed on various machines in a network working together to achieve a common goal. For example, service-oriented systems are composed this way. Deploying such systems manually is a very time consuming, complex, error prone and tedious process. The bigger the system gets, the more likely it becomes that an error occurs.
  • We have to be more flexible in reacting to events. For example, in a cloud infrastructure, if a machine breaks, we must be able to redeploy the system in such a way that services are still available to end-users, limiting the impact as much as possible.
  • We want to push changes to a system in production environment faster. Because systems become increasingly more complex, an automated deployment solution is essential. In Agile software development projects, a team wants to generate value as quickly as possible, for which it is essential to have a working system in a production environment as soon as possible. To achieve this goal, it is crucial that the deployment process can be performed without much trouble. A colleague of mine (Rini van Solingen), who is also a Scrum consultant, has covered this importance in a video blog interview.

Research


What are software deployment research subjects?

  • Mechanics. This field concerns the execution of the deployment activities. How can we make these steps reproducible, reliable, efficient? Most of the research that I do covers deployment mechanics.
  • Deployment planning. Where to place a component in a network of machines? How to compose components together?
  • Empirical research covering various aspects of deployment activities, such as: How to quantify build maintenance effort? How much maintenance is needed to keep deployment specifications (such as build specifications) up to date?

Where are software deployment papers published? Currently, there is no subfield conference about software deployment. In the past (a few years before I started my research), there were three editions of the Working Conference on Component Deployment, which is no longer held since 2005.

Most of the deployment papers are published in various conferences, such as the top general ones, subfield conferences about software maintenance, testing, cloud computing. The challenging part of this is that (depending on the subject) I have to adapt my story to the conference where I want my paper to be published. This requires me to explain the same problems over and over again and integrate these problems with the given problem domain, such as cloud computing or testing. This is not always trivial to do, nor will every reviewer understand what the point is.

Conclusion


In this blog post, I have explained what software deployment is about and why research in this field is important. Systems are becoming much bigger and more complicated and we want to respond to changes faster. In order to manage this complexity, we need research in providing automated deployment solutions.

References


Deploying .NET services with Disnix

$
0
0
In two earlier blog posts, I have explained how the the Nix package manager can be used to deploy .NET software. I'm happy to report that I have extended these possibilities to Disnix.

With these new features it is possible to develop databases for Microsoft SQL server, implement WCF web services and ASP.NET web applications (which may be inter-connected to each other) and to automatically and reliably deploy them in a network of machines using Disnix.

Modifications to Disnix


The modifications I had to make to Disnix were relatively minor. Disnix can already be compiled on Cygwin, just as the Nix package manager. Since Disnix is built on top of Nix, it reuses the Nix functions I have developed in earlier blog posts to build Visual Studio projects.

The only missing piece in the deployment process, is the activation and deactivation of Microsoft SQL server databases and ASP.NET web applications on Internet Information Services (IIS) for which activation scripts must be developed. Luckily, Microsoft SQL server and IIS have command-line tools which can be scripted, to do this job.

To support these new types of services, I have developed the following activation scripts:

  • mssql-database. This activation script loads a schema on initial startup if the database does not exists. It uses the OSQL.EXE tool included with Microsoft SQL server, to automatically execute the SQL instructions from shell scripts to check whether the database exists and to create the tables if needed.
  • iis-webapplication. This activation script activates or deactivates a web application on Microsoft Internet Information Services. It uses the MSDeploy.exe tool to automatically activate a web application or deactivate a web application.

These activation scripts are automatically used by assigning a mssql-database or iis-webapplication type to a service in the Disnix services model.

Installing Disnix on Windows


Important is to know how to get Disnix working on Windows and how to enable support for .NET applications. Most of the installation steps on Windows/Cygwin are the same as UNIX systems. Details of the Disnix installation process can be found in the Disnix documentation.

However, there are a number of details that must be taken care of, which are not described in the manual (yet). Furthermore, the best way to get Disnix working is by compiling it from source so that all the required optional features are enabled.

In order to enable the mssql-database and iis-webapplication activation types, you must first manually install SQL server and IIS on your Windows system:



Moreover, the configure script of the disnix-activation-scripts package must be able to find OSQL.EXE and MSDeploy command-line tools, which must be in your PATH. Otherwise the activation types that we need are disabled and we cannot deploy .NET applications.

On my Windows 7 machine, OSQL can be found in: C:\Program Files\Microsoft SQL Server\100\Tools\Binn and MSDeploy in: C:\Program Files\IIS\Microsoft Web Deploy. I have included a screenshot above, which shows you what the output should of the configure script should look like. As you can see, the configure script was able to detect the locations of the command line tools, because I have adapted the PATH environment variable.

Running the Disnix daemon


We also need to run the Disnix daemon on every machine in the network, so that we can remotely deploy the services we want. Probably the best way to get Cygwin services running is by using the cygrunsrv command, which runs Cygwin programs as Windows services.

Since the core Disnix daemon is a D-Bus service, we need to run the D-Bus system daemon, which can be configured by typing:

$ cygrunsrv -I dbus -p /usr/sbin/dbus-daemon.exe -a \
'--system --nofork'

The Disnix service can be configured by typing:

$ cygrunsrv -I disnix -p /usr/local/bin/disnix-service.exe -a \
'--activation-modules-dir /usr/local/libexec/disnix/activation-scripts' \
-e 'PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin' \
-y dbus

Disnix also needs to be remotely connectible. Disnix can use various interfaces, but the recommended interface is SSH. In order to connect through SSH, you also need to configure a SSH server. This can be done by executing the following script on Cygwin:

$ ssh-host-config

And you probably need to configure some SSH keys as well, to prevent Disnix asking for passwords for each operation. Check the OpenSSH documentation for more information.


After configuring the services, you probably need to activate them for the fist time, which can be done by the Windows service manager (Control Panel -> System and Security -> Administrative Tools -> Services). You need to pick the Disnix service and select the start option. If you want to use the SSH server, you need to pick and start the 'CYGWIN sshd' service as well. A screenshot is included above.

Example case


Now that I have explained how Disnix can be installed and configured on Windows, we probably also like to see what it's capabilities are. As an example case, I have ported the StaffTracker, a motivating example in our WASDeTT paper, from Java to .NET technology, using C# as an implementation language, ADO.NET as database manager, WCF to implement web services, and ASP.NET to create the web application front-end.


It was a nice opportunity to learn some of these technologies. I have to admit that Visual Studio 2010 was a very convenient development environment and it didn't take much time for me to port the example case. Although I was impressed by this, I currently have no plans to write any software using .NET technology except for this example case. (Perhaps I will port it to Mono as an experiment some day).

Distributed deployment


In order to make our example deployable through Disnix, I had to write Disnix expressions for each service component and I had to write a services, infrastructure and distribution model. A Disnix expression for a WCF web service looks like this:

{dotnetenv}:
{zipcodes}:

dotnetenv.buildSolution {
name = "ZipcodeService";
src = ../../../../services/webservices/ZipcodeService;
baseDir = "ZipcodeService";
slnFile = "ZipcodeService.csproj";
targets = "Package";
preBuild = ''
sed -e 's|.\SQLEXPRESS|${zipcodes.target.hostname}\SQLEXPRESS|' \
-e 's|Initial Catalog=zipcodes|Initial catalog=${zipcodes.name}|' \
-e 's|User ID=sa|User ID=${zipcodes.target.msSqlUsername}|' \
-e 's|Password=admin123$|Password=${zipcodes.target.msSqlPassword}|' \
Web.config
'';
}

As you may notice, the expression above looks similar to an ordinary Nix expression building a Visual Studio project, except that it uses the inter-dependency parameter (zipcodes) to configure a database connection string defined in the Web.config file, so that the web service can connect to its database back-end. More information about setting a connection string through this configuration file, can be found here: http://weblogs.asp.net/owscott/archive/2005/08/26/Using-connection-strings-from-web.config-in-ASP.NET-v2.0.aspx.

By using the Disnix expressions in conjunction with the services, infrastructure and distribution models, the .NET example can be deployed in a network of machines with a single command line instruction:

$ disnix-env -s services.nix -i infrastructure.nix -d distribution.nix

Below, I have a included a screenshot showing a Disnix deployment scenario with our .NET Staff Tracker example. In this screenshot, you can see a console showing Disnix output, a web browser displaying the entry page of the web application front-end, the IIS manager showing various deployed WCF web services, and the ASP.NET web front-end and the SQL server management studio showing a number of deployed databases. The complete system is deployed using a single command-line instruction.


Limitations


In this blog post I have shown how service-oriented .NET applications can be automatically deployed with Disnix. There are several slight inconveniences however:

  • Disnix is used to manage the service components of a system. Disnix does not deploy infrastructure components, such as web server or database server. DisnixOS is a NixOS based extension that takes care of this. However, DisnixOS cannot be used on Windows, because SQL server and IIS are tightly integrated into the Windows operating system and registry. We cannot use the Nix store to safely isolate them. You need to either install these infrastructure components manually or use other deployment solutions.
  • As mentioned in our previous blog post about .NET deployment, the .NET framework needs to be installed manually in order to be able to build Visual Studio projects. On most Windows installations, however, the .NET framework is already included.
  • The .NET build functions and activation scripts are quite new and not very well tested. Moreover, they could also break, because we currently have no way to automatically test them like we do with Linux software.
  • Also not all desired deployment features may be supported. I'd like to have feedback on this :-)

References

On Nix, NixOS and the Filesystem Hierarchy Standard (FHS)

$
0
0
Our work on NixOS has been topic of discussion within various free software/open source projects and websites. For example, we have been discussed on the Debian mailing list and on Linux Weekly News.

One of the criticisms I often receive is that we don't comply with the Filesystem Hierarchy Standard (FHS). In this blog post, I'd like to give a response on the FHS and why NixOS deviates from it.

What is the Filesystem Hierarchy Standard?


The purpose of the Filesystem Hierarchy Standard (FHS) is to define the main directories and their contents in Linux operating systems. More specifically:

  • It defines directory names and their purposes. For example, the bin directory is for storing executable binaries, sbin is for storing executable binaries only accessible by the super-user, lib is for storing libraries.
  • It defines several hierarchies within the filesystem, which have separate purposes:

    The primary / hierarchy contains essential components for the boot process and system recovery. The secondary hierarchy: /usr contains components not relevant for booting and recovery. Moreover, files in this directory should be shareable across multiple machines, e.g. through a network filesystem. The tertiary hierarchy: /usr/local is for the system administrator to install software locally.

    Hierarchies and special purpose directories are usually combined. For example, the /bin directory contains executable binaries relevant for booting and recovery which can be used by anyone. The /usr/bin directory contains executable binaries not relevant for booting or recovery, such as a web browser, which can be shared across multiple machines. The /usr/local/bin directory contains local executables installed by the system administrator.

    The FHS also defines the /opt directory for installing add-on application software packages. This directory can also be considered a separate hierarchy, although it is not defined as such in the standard. This directory also contains the same special purpose directories, such as bin and lib like the primary, secondary and tertiary hierarchies. Furthermore, also the /opt/<package name> convention may be used, which stores files specific to a particular application in a single folder.
  • It also makes a distinction between static and variable parts of a system. For example, the contents of the secondary hierarchy /usr are static and could be stored on a read-only mounted partition. However, many programs need to modify their state at runtime and store files on disks, such as cache and log files. These files are stored in variable storage directories, such as /var and /tmp.
  • It defines what the contents of some folders should look like. For example, a list of binaries which should reside in /bin, such as a Bourne compatible shell.
  • The standard has some practical problems. Some aspects of the filesystem are undefined and need clarification, such as a convention to store cross compiling libraries. Furthermore, the standard is quite old and newer Linux features such as the /sys directory are not defined in the standard. To cope with these issues, many distributions have additional clarifications and policies, such as the Debian FHS policy.

Linux Standard Base


The Filesystem Hierarchy Standard (FHS) is part of another standard: The Linux Standard Base (LSB), which incorporates and extends several other standards, such as POSIX and the Single UNIX specification.

The LSB standard has been developed, because there are many Linux based systems out there. What they all have in common is that they run the Linux kernel, and quite often a set of GNU utilities (that's why the free software foundation advocates GNU/Linux as the official name for these kind of systems).

Except some similarities, there are many ways in which these systems differ from each other, such as the package manager which is being used, the way the file system is organized, the software which is supported etc.

Because there are many Linux systems available, the Linux Standards Base is designed to increase compatibility among these Linux distributions, so that it becomes easier for software vendors to ship and run Linux software, even in binary form. Many of the common Linux distributions such as Debian, SuSE and Fedora try to implement this standard, although it has several issues and criticisms.

NixOS and the FHS



In NixOS, we have an informal policy to follow the FHS as closely as possible, but to deviate from it where necessary. An important aspect is that we can't follow the structure of the primary /, secondary /usr and tertiary hierarchies: /usr/local.

The main reason to refrain from using these hierarchies is that they don't provide isolation. For example the /usr/lib directory contains a wide collection of shared libraries belonging to many packages. To determine to which package a particular library belongs, you need to have a look in the database of the package manager. Because most libraries can be found in the same location, e.g. /usr/lib, it is very tempting to forget specifying a dependency, because they can still be implicitly found.

The purpose of the Nix package manager is to achieve purity, which means that the build result of a package should exclusively depends on the source code and input parameters. Purity ensures that the build of a package can be reproduced anywhere and that a package can be transferred to any machine we want, with the guarantee that the dependencies are present and correct.

Nix achieves purity by using the filesystem as a database and to store packages in isolation in a special directory called the Nix store. For example:

/nix/store/r8vvq9kq18pz08v249h8my6r9vs7s0n3-firefox-8.0.1

The path above refers to the Mozilla Firefox web browser. The first part of the directory name: r8vvq9kq18pz08v249h8my6r9vs7s0n3 is a hash-code derived from all build time dependencies. By using this naming convention, components can be stored safely in isolation from each other, because no component shares the same name. If Firefox is compiled with a different version of GCC or linked to a different version of the GTK+ library, the hash code will differ and thus not interfere with another variant.

Because of the naming scheme of the Nix store and the fact that we don't use global directories to store binaries and libraries, the build of a Nix package will typically fail if a required build time dependency is omitted. Furthermore, it also restricts undeclared dependencies which may allow a build to accidentally succeed (and therefore also prevents incomplete dependency specifications).

Another deviation of the FHS, is not following the list of required binaries and libraries in the /bin, /lib etc. directories. For example, the FHS requires a Bourne compatible shell in /bin/sh, some mkfs.* utilities in /sbin and for historic reasons, a sendmail executable in /usr/lib.

In NixOS, apart from the /bin/sh executable (which is a symlink to the bash shell in the Nix store), we don't store any binaries in these mandatory locations because it is not necessary and it also makes builds impure.

Discussion


Now that I have explained why we deviate from the FHS on some points, you probably may wonder, how we achieve certain properties defined in the FHS in NixOS:

  • How to determine files for the boot process and recovery? Because we don't use hierarchies, files relevant for the boot process can't be found in /bin and /lib. In NixOS, we basically generate a small base system as a Nix component serving this purpose, which is stored as a single component in the Nix store.
  • How to share components? Because we have no secondary hierarchy, you can't share components by storing the /usr directory on a network file system. In Nix, however, the entire Nix store is static and shareable. Furthermore, it's even more powerful, because the hash codes inside the component names prevent different variants of NixOS to use the incorrect versions of a component. For example, you can safely share the same Nix store across 32-bit and 64-bit machines, because this parameter is reflected in the hash.

    In fact, we already use sharing extensively in our build farm, to generate virtual machines to perform testcases. Apart from a Linux kernel image and an initial RAM disk, the components of the entire virtual network are shared through the host system's Nix store, which is mounted as a network file system.
  • How to find dependencies? Because we store all software packages in the Nix store, it is harder to address components in e.g. scripts and configuration files, because all these components are stored in separate directories, and aren't necessarily in the user's PATH.

    I have to admit that this is inconvenient in some cases, however in NixOS we usually don't manually edit configuration files and write scripts.
    NixOS is a distribution that is unconventional in this sense, because its goal is to make the entire deployment process model-driven. Instead of manually installing packages and adapting configuration files in e.g. /etc. In NixOS, we generate all the static parts of a system from Nix expressions, including all configuration files and scripts. The Nix expression language provides the paths to the components.

Improvements


Although we have to deviate from the FHS for a number of reasons, there are also a few improvements we could make in the organization of the filesystem:

  • The directory names and purposes within the hierarchies can be more consistently used within Nix packages. Essentially, you could say that every component in the Nix store is a separate hierarchy.

    For example, I think it's a good thing to use /nix/store/<package>/bin for storing binaries, and /nix/store/<package>/lib for libraries. Sometimes installation scripts of packages do not completely adhere to the FHS and need some fixing. For example, some packages install libraries in the libexec directory, which is not defined by the FHS.

    We could make an additional check in the generic builder of Nixpkgs, checking the structure of a package and to report inconsistencies.
  • For the variable parts of the system, we can adhere better to the FHS. For example, the current version of the FHS defines the /srv directory used for serving files to end-users, through a service (e.g. a web server). In NixOS, this directory is not used.
  • Because the FHS standard has some gaps, we could also define some additional clarification, like other Linux distributions do.

Conclusion


In this blog post I've explained the idea behind the Filesystem Hierarchy Standard (FHS) and I have explained why we deviate from it in NixOS. The main reason is that the organization of specific parts of the file system, conflict with important aspects of the Nix package manager, such as the ability to store components isolation and to guarantee correct and complete dependencies.

Furthermore, apart from the FHS, NixOS cannot completely implement other parts of the LSB either. For example, in the LSB a subset of the RPM package manager is defined as default package manager, which imperatively modifies the state of a system.

If we would implement this in NixOS, we can no longer ensure that the deployment of a system is pure and reproducible. Therefore, we sometimes have to break from the traditional organization and management of Linux systems. However, sometimes I get the impression that the FHS is considered a holy book and by breaking from it, we are considered heretics.

Related work


  • GoboLinux is also a Linux distribution not obeying the FHS, with a custom filesystem organization. They also have the vision that the filesystem can act as a database for organizing packages.
  • The Mancoosi project is also a research project investigating package management related problems, like we do. Their research differs from us, because they don't break away from the traditional filesystem organization and management of Linux systems. For example, a lot of their research deals with maintainer scripts of packages, which goal is to "glue" files from a package to files on the system, e.g. by imperatively modifying configuration files.

    By keeping the traditional management intact, this introduces a whole bunch of challenges to make deployment efficient, reliable and reproducible. For example, they have investigated modeling techniques for maintainer scripts and system configurations, to simulate whether an upgrade succeed and to determine inverse operations to perform rollbacks.

    In our research, we achieve more reliable deployment by breaking from the traditional model.

An evaluation and comparison of GoboLinux

$
0
0

In this blog post, I'm going to evaluate deployment properties of GoboLinux and compare it with NixOS. Both Linux distributions are unconventional because they deviate from the Filesystem Hierarchy Standard (FHS). Apart from this, GoboLinux shares the same idea that the filesystem can be used to organize the management of packages and other system components, instead of relying on databases.

The purpose of this blog post is not to argue which distribution is better, but to see how this distribution achieves certain deployment properties, what some differences are compared to NixOS and what we can learn from it.

Filesystem organization


Unlike NixOS, which only deviates from the FHS where necessary, GoboLinux has a filesystem tree which completely deviates from the FHS, as shown below:


GoboLinux stores static parts of programs in isolation in the /Programs folder. The /System folder is used to compose the system, to store system configuration settings and variable data. /Files is used for storing data not belonging to any program. /Mount is used for accessing external devices such as DVD-ROM drives. The /Users folder contains home directories. /Depot is a directory without a predefined structure, which can be organized by the user.

GoboLinux also provides compatibility with the FHS. For example, the /usr and /bin directories are actually also present, but not visible. These directories are in fact symlinks trees referring to files in the /System directory (as you may see in the picture above). They are made invisible to end-users by a special kernel module called GoboHide.

Package organization


Like NixOS, GoboLinux stores each package in a seperate directories, which do not change after they have been built. However, GoboLinux uses a different naming convention compared to NixOS. In GoboLinux every package uses the /Program/<Name>/<Version> naming convention, such as: /Programs/Bzip2/1.0.4 or /Programs/LibOGG/1.1.3. Furthermore, each program directory contains a Current symlink which points to the version of the component, that is actually in use. Some program directories also have a Settings/ directory containing system configuration files for the given package.

The use of isolated directories offers a number of benefits like NixOS:

  • Because every version is stored in its own directory, we can safely store multiple versions next to each other, without having to worry that a file of another version gets overwritten.
  • By using a symlink, pointing to the current version, we can atomically switch between versions by flipping the symlink (also used by Nix to switch Nix profiles), which ensures that there is no situation in which a package contains both files of the old version and new version.

In contrary to NixOS, GoboLinux uses a nominal naming convention and dependency specifications, which are based on the name of the package and version number. With a nominal naming convention, it cannot make a distinction between several variants of components, for example:

  • It does not reflect which optional features are enabled in a package. For example, many libraries and programs have optional dependencies on other libraries. Some programs may require a particular variant of a library with a specific option enabled.
  • It does not take the build-time dependencies, such as build tools or library versions into account, such as the version of GCC or glibc. Older versions may have ABI incompatibilities with newer versions.
  • It does not take the architecture of the binaries into account. Using this naming scheme, it is harder to store 32-bit and 64-bit binaries safely next to each other.

In NixOS, however, every package name is an exact specification, because the component name contains an hash-code derived from all build-time dependencies to build the package, such as the compiler version, libraries and build scripts.

For example, in NixOS bzip2 may be stored under the following path: /nix/store/6iyhp953ay3c0f9mmvw2xwvrxzr0kap5-bzip2-1.0.5. If bzip2 is compiled with a different version of GCC or linked to a different version of glibc, it gets a different hash-code and thus another filename. Because no component shares the same name, it can be safely stored next to other variants.

Another advantage of the Nix naming convention is that unprivileged users can also build and install software without interfering with other users. If for example, a user injects a trojan horse in a particular package, the resulting component is stored in a different Nix store path and will not affect other users.

However, because of these exact dependency specifications, upgrades in NixOS may be more expensive. In order to link a particular program to a new version of a library, it must be rebuild, while in GoboLinux the library dependency can be replaced without rebuilding (although it may not guarantee that the upgraded version will work).

System composition


Of course, storing packages in separate directories does not immediately result in a working system. In GoboLinux, the system configuration and structure is composed in the /System directory.

The /System directory contains the following directories:

  • Kernel/, contains everything related to the Linux kernel, such as Boot/ storing kernel images, Modules/ storing kernel modules and Objects/ storing device files.
  • Links/, is a big symlink tree composing the contents of all packages that are currently in use. This symlink tree makes it possible to refer to executables in Executables/, libraries in Libraries/ and other files from a single location. The Environment/ directory is used to set essential environment variables for the installed programs.
  • Settings/ contains configuration files, which in other distributions are commonly found in /etc. Almost all files are symlinks to the Settings/ folder included in each program directory.
  • Variable/ contains all non-static (variable) data, such as cache and log files. In conventional distributions these files are stored in /var.

Like NixOS, GoboLinux uses symlink trees to compose a system and to make the contents of packages accessible to end users.

Recipes


Like NixOS, GoboLinux uses declarative specifications to build packages. GoboLinux calls these specifications recipes. Each recipe directory contains a file called Recipe which describes how to build a package from source code and a folder Resources/ defining various other package properties, such as a description and a specification of build-time and run-time dependencies.

compile_version=1.8.2
url="$httpSourceforge/lesstif/lesstif-0.95.2.tar.bz2"
file_size=2481073
file_md5=754187dbac09fcf5d18296437e72a32f
recipe_type=configure
make_variables=(
"ACLOCALDIR=$target/Shared/aclocal"
"aclocaldir=$target/Shared/aclocal"
)

An example of a recipe, describing how to build Lesstif, is shown above. Basically, for autotools based projects, you only need to specify the location where the source code tarball can be obtained, and some optional parameters. From this recipe, the tarball is download from the sourceforge web server and the standard autotools build procedure is performed (i.e. ./configure; make; make install) with the given parameters.

In the Resources/Dependencies run-time dependencies can be specified and in Resource/BuildDependencies build-time dependencies can be specified. The dependencies are specified by giving a name and an optional version number or version number range.

GoboLinux recipes and Nix expressions both offer abstractions to declaratively specify build actions. A big difference between those specifications, is the way dependencies are specified. In GoboLinux only nominal dependency specifications are used, which may not be complete enough, as explained earlier. In Nix expressions, you refer to build functions that build these dependencies from source-code and their build-time dependencies, which are stored in isolation in the Nix store using hash codes.

Furthermore, in Nix expressions run-time and build-time dependencies are not separately specified. In Nix, every run-time dependency is specified as build-time dependency. After a build has been performed, Nix conservatively scans for hash occurrences of build-time dependencies inside a realized component to identify them as run-time dependencies. Although this sounds risky, it works extremely well, because chances are very slim that an exact occurrence of a hash code represents something else.

Building packages


In GoboLinux, the Compile tool can be used to build a package from a recipe. Builds performed by this tool are not entirely pure, because it looks for dependencies in the /System/Links directory. Because this directory contains all the installed packages on the system, it may be possible that the build of a recipe may accidentally succeed when a dependency is not specified, because it can be implicitly found.

In order to make builds pure, GoboLinux provides the ChrootCompile extension, which performs builds in a chroot environment. ChrootCompile tool bind mounts the /Program directory in the chroot environment and creates a small /System only containing symlinks to the dependencies that are specified in the recipe. Because only the specified dependencies can be found in /System/Links directory, a build cannot accidentally succeed if a dependency has been omitted.

Both Nix and ChrootCompile have the ability to prevent undeclared dependencies to accidentally succeed a build, which improves reproducibility. In Nix, this goal is achieved differently. In Nix, the environment variables in which a build is performed are completely cleared (well not completely, but almost :-) ), and dependencies which are specified are added to the PATH and other environment variables, which allow build tools to find the dependencies.

Nix builds can be optionally performed in a chroot environment, but this is not mandatory. In NixOS, the traditional FHS directories, such as /usr don't exist and cannot make a build impure. Furthermore, common utilities such as GCC have been patched so that they ignore standard directories, such as /usr/include, removing many impurities.

Furthermore, Nix also binds dependency relationships statically to the executables (e.g. by modifying the RPATH header in an ELF binary), instead of allowing binaries to look in global directories like: /System/Links, which GoboLinux executables do. Although, GoboLinux builds are pure inside a chroot environment, their run-time behaviour may be different when a user decides to upgrade a version of its dependency.

Conclusion


In this blog post I did an evaluation of GoboLinux and I compared some features with NixOS. In my opinion, evaluating GoboLinux shows a number of interesting lessons:

  • There are many deployment related aspects (and perhaps other aspects as well) that can be solved and improved by just using the filesystem. I often see that people write additional utilities, abstraction layers and databases to perform similar things, while you can also use symlink trees and bind mounts to provide abstractions and compositions. Additionally, this also shows that the filesystem, which is an essential key component for UNIX-like systems, is still important and very powerful.
  • Storing packages in separate directories is a simple way to manage their contents, store multiple versions safely next to each other and to make upgrades more reliable.

GoboLinux and NixOS have a number of similar deployment properties, because of their unorthodox filesystem organization, but also some differences and limitations. The following table summarizes the differences covered in this blog post:

GoboLinuxNixOS
FHS compatibilityYes (through hidden symlink trees)No (deviates on some FHS aspects)
Component namingNominal (name-version)Exact (hash-name-version)
Component bindingDynamic (dependency can be replaced without rebuild)Static (rebuild required if a dependency changes)
Granularity of component isolationOnly between versionsBetween all build-time dependencies (including version)
Unprivileged user installationsNoYes
Build specificationsStand-alone recipesNix expressions which need to refer to all dependency expressions
Build-time dependency addressing/System/Links symlink tree in chroot environmentSetting environment variables + modified tools + optional chroot environment
Run-time dependenciesSpecified manuallyExtracted by scanning for hash occurrences
Run-time dependency resolvingDynamic, by looking in /System/LinksStatic (e.g. encoded in RPATH)

The general conclusion of this blog post is that both distributions achieve better deployment properties compared to conventional Linux distributions, by their unorthodox filesystem organisation. Because of the purely functional deployment model of the Nix package manager, NixOS is more powerful (and strict) than GoboLinux when it comes to reliability, although this comes at the expense of extra rebuild times and additional disk space.

The only bad thing I can say about GoboLinux is that the latest 014.01 release is outdated (2008) and it looks like 015 is in progress for almost three years... I'm not sure if there will be a new release soon, which is a pity.

And of course, apart from these deployment properties, there are many other differences I haven't covered here, but that's up to the reader to make a decision.

I'm planning to use these lessons for a future blog post, which elaborates more on techniques for making software deployment processes more reliable.

Techniques and lessons for improvement of deployment processes

$
0
0
So far, all my software deployment related blog posts were mostly about techniques implemented in Nix, NixOS and Disnix and some general deployment information.
In my career as a Masters student and PhD student, I have written quite a number of Nix expressions for many packages and I have also "Nixified" several large code bases of commercial companies to make it possible to use the distinct features of Nix to make software deployment processes reproducible and reliable.

However, for many systems it turns out that implementing Nix support (for instance, to allow it to be deployed by our Nix-based deployment tools) is more difficult, tedious and laborious than expected. In this blog post, I'm going to describe a number of interesting techniques and lessons that could improve the deployment process of a system, based on my experience with Nix and Disnix. Second, by taking these lessons into account, it also becomes easier to adopt Nix as underlying deployment system.

  1. Deal with the deployment complexity from the beginning in your development process. Although this lesson isn't technical and may sound very obvious to you, I can ensure you that if you have a codebase which grows rapidly, without properly thinking about deployment, it becomes a big burden to implement the techniques described in this blog post later in the development process. In some cases, you may even have to re-engineer specific parts of your system, which can be very expensive to do, especially if your codebase consists of millions of lines of code.

  2. Make your deployment process scriptable. This lesson is also an obvious one, especially if you have adopted an agile software development process, in which you want to create value as soon as possible (without a deployed system there is no value).

    Although it's obvious, I have seen many cases where developers still build and package components of a software system by manually performing build and package tasks in the IDE and by doing all the installation steps by hand (with some deployment documentation). Such deployment processes typically take a lot of time and are subject to errors (because they are performed manually and humans make mistakes).

    Quite often these developers, who perform these manual/ad-hoc deployment processes, tell me that it's much too complicated to learn how a build system works (such as GNU Make or Apache Ant) and to maintain these build specifications.

    The only thing I can recommend to them is that it really is worth the effort, because it significantly reduces the time to make a new release of the product and also allows you test your software sooner and more frequently.

  3. Decompose your system and their build processes. Although I have seen many software projects using some kind of automation, I have also encountered a lot of build tools which treat the the complete system as a single monolithic blob, which must be built and deployed as a whole.

    In my opinion it's better to decompose your system in parts which can be built separately, for the following reasons:

    • It may significantly reduce build times, because only components that have been changed have to be rebuilt. There is no need to reexamine the complete codebase for each change.
    • It increases flexibility, because it becomes easier to replace specific parts of a system with other variants.
    • It allows a better means of sharing components across systems and better integration in different environments. As I have stressed out in an earlier blog post, software nowadays is rarely self-contained and run in many types of environments.
    • It allows you to perform builds faster, because they can be performed in parallel.

    In order to decompose a system properly, you have to think early about a good architecture of your system and keep reflecting about it. As a general rule, the build process of a sub component should only depend on the source code, build script and the build results of the dependencies. It should not be necessary to have cross references between source files among components.

    Typically, a bad architecture for a system also implies a very complex and inefficient build process.

    I have encountered some extreme cases, in which the source code system is one big directory of files, containing hundreds of dependencies including third-party libraries in binary form, infrastructure components (such as the database and web servers) containing many tweaks and custom configuration files.

    Although such code bases can be automatically deployed, it offers almost no flexibility, because it is a big burden to replace a specific part (such as a third party library) and still ensure that the system works as expected. Also it requires the system to be deployed in a clean environment because it offers no integration. Typically these kind of systems aren't updated that frequently either.

  4. Make build-time and run-time properties of components configurable. Another obvious lession, but I quite frequently encounter build processes which make implicit assumptions about the locations where specific dependencies can be found.

    For example, in some Linux packages, I have seen a number of Makefiles which have hardcoded references to the /usr/bin directory to find specific build tools, which I have to replace myself. Although most Linux systems have these build-time dependencies stored in this folder, there are some exceptions such as NixOS and GoboLinux.

    In my opinion it's better to make all locations and settings configurable, either by allowing it to be specified as a build parameter, environment variable (e.g. PATH) or stored in a configuration file, which can be easily edited.

  5. Isolate your build artifacts. I have noticed that some development environments store the output of a build in separate folders (for example Eclipse Java projects) whereas others store all the build artifacts of all projects in a single folder (such as Visual Studio C# projects). Similarly, with end user installations in production environments, libraries are also stored in global directories, such as /usr/lib on Linux environments, or C:\Windows\System32 on Windows.

    Based on my experience with Nix, I think it's better to store the build output of every component in isolation, by storing them in separate folders. Although this makes it harder to find components, it also offers some huge benefits, such as the ability to store multiple versions next to each other. Also upgrades can be made more reliable, because you can install another version next to an existing one. Furthermore, builds can also be made more pure and reproducible, because it's required to provide the locations of these components explicitly. In global folders such as /usr/lib a dependency may still be implicitly found even if it's not specified, which cannot happen if all the dependencies are stored in separate locations. More information about isolation can be found in my blog post about NixOS and the FHS.

  6. Think about a component naming convention. Apart from storing components in separate directories which offers some benefits, it's also important to think about how to name them. Typically, the most common naming scheme that's being used consists of a name and version number. This naming scheme can be insufficient in some cases, for example:

    • It does not take the architecture of the component into account. In a name-version naming scheme a 32-bit variant and a 64-bit variant are considered the same, while they may not be compatible with another component.
    • It does not take the optional features into account. For example, another component may require certain optional features enabled in order to work. It may be possible that a program incorrectly uses a component which does not support a required optional feature.

    I recommend you to also take relevant build-time properties into account when naming a component. In Nix you get such a naming convention for free, although the naming convention is also very strict. Nix hashes all the build-time dependencies, such as the source code, libraries, compilers and build scripts and makes this hash code part of the component name, for example: /nix/store/r8vvq9kq18pz08v24918my6r9vs7s0n3-firefox-8.0.1. Because of this naming scheme, different variants of a component, which are (for example) compiled with another version of a compiler of for a different system architecture do not share the same name.

    In some cases, it may not be necessary to adopt such a strict naming scheme, because the underlying component technology used is robust enough to offer enough flexibility. In one of my case studies covering Visual Studio projects, we only distinguish between variants of component by taking the name, version, interface and architectures into account. because they have no optional features and we assume the .NET framework is always compatible. We organize the filesystem in such a way that 32-bit and 64-bit variants are stored in separate directories. Although a naming scheme like this is less powerful than Nix's, it already offers huge benefits compared to traditional deployment approaches.

    Another example of a more strictly named component store is the .NET Global Assembly Cache (GAC), which makes a distinction between components based on the name, version, culture and a cryptographic key. However, the GAC is only suitable for .NET library assemblies and not for other types of components and cannot take other build properties into account.

  7. Think about component composition. A system must be able to find its dependencies at build-time and run-time. If the components are stored in a separate folders, you need to take extra effort in order to compose them. Some methods of addressing dependencies are:

    • Modify the environment. Most platforms use environment variables to address components, such as PATH for looking up executables, CLASSPATH for looking up Java class files, PERL5LIB for addressing Perl libraries. In order to perform a build these environment variables must be adapted to contain all the dependencies. In order to run the executable, the executable needs to be wrapped in a process, which sets these environment variables. Essentially, this method binds dependencies statically to another component.
    • Composing symlink trees. You can also provide a means of looking up components from a single location by composing the contents of the required dependencies in a symlink tree and by referring to its contents. In conjunction with a chroot environment, and a bind mount of the component directory, you can make builds pure. Because of this dynamic binding approach, you can replace dependencies, without a rebuild/reconfiguration, but you cannot easily run one executable that uses a particular variant of a library, while another runs another variant. This method of addressing components is used by GoboLinux.
    • Copy everything into a single folder. This is a solution which always work, however it is also a very inefficient as you cannot share components.

    Each composition approach has its own pros and cons. The Nix package manager supports all three approaches, however the first approach is mostly used for builds as its the most reliable one, because static binding always ensures that the dependencies are present and correct and that you can safely run multiple variants of compositions simultaneously. The second approach is used by Nix for creating Nix profiles, which end users can use to conveniently access their installed programs.

  8. Granularity of dependencies. This lesson is very important while deploying service-oriented systems in a distributed environment. If service components have dependencies on components with a large level of granularity, upgrades may become very expensive because some components are unnecessarily reconfigured/rebuilt.

    I have encountered a case in which a single configuration file was used to specify the locations of all service components of a system. When the location of a particular service component changes, every service component had to be reconfigured (even services that did not need access to that particular service component) which is very expensive.

    It's better to design these configuration files in such a way that they only contain properties that a service components need to know.


Conclusion


In this blog post I have listed some interesting lessons to improve the deployment process of complex systems based on my experience with Nix and related tools. These can be implemented in various deployment processes and tools. Furthermore, it becomes easier to adopt Nix related tooling by taking these lessons into account.

I also have to remark that it is not always obvious to implement all these lessons. For example, it is hard to integrate Visual Studio C# projects in a stricter deployment model supporting isolation, because the .NET runtime has no convenient way to address run-time dependencies in arbitrary locations. However, there is a solution for this particular problem, which I have described in an earlier blog post about .NET deployment with Nix.

UPDATE: I have given a presentation about this subject at Philips recently. As usual, the slides can be obtained from the talks page of my homepage.

One year later

$
0
0
Today, it's my blog's first anniversary, so I thought this is a good opportunity to do some reflection about it.

Motivation


So why have I started this blog in the first place? The main reason is that as a software engineer and researcher, I don't necessarily only write code or write academic papers:

  • Sometimes I have to solve engineering problems, instead of doing science (whatever that means). In my opinion, this is also interesting and useful to report about. For example, while most of my research is about Nix, NixOS, Disnix, sometimes I have to apply my work in specific scenarios/environments which is challenging enough to get it to work. A notable example is the deployment .NET software. Without proper application of the stuff I'm investigating, the usefulness of my research isn't so great either.
  • Sometimes I have to express ideas and opinions. For example, what others say about the research we're doing or about general software engineering issues.
  • Sometimes I need to do knowledge transfer about issues I have to keep explaining over and over again, like the blog post about software deployment in general.
  • Sometimes I have some fun projects also well.

The main purpose of my blog is to fill this gap with academic paper publishing. Apparently, it seems that some of my blog posts have raised quite some attention, which I'm very happy about. Moreover, some blog posts (like the .NET related stuff) also gave me some early feedback which helped me solving a problem which I was struggling with for a long time.

Writing for a blog


For some reason, I find writing blog posts more convenient than writing academic papers. In order to write an academic paper I have to take a lot of stuff into account next to the scientific contribution I want to make. For example:

  • Because I'm doing research in software deployment and because this is a neglected research topic, I have to adapt my paper to fit in the scope of a conference I have to submit to, because they are typically about something else. This is not always easy.
  • I have to identify the audience of the particular conference and learn about the subjects and concepts they talk about.
  • I have to read a lot of related work papers to determine the exact scientific contribution and to describe what the differences are.
  • I have to integrate my idea into the concepts of the given conference.
  • I have to explain the same concepts over and over again, because they are not generally understood. What is software deployment? Why is software deployment difficult and important? What is Nix? Why is Nix conceptually different compared to conventional package managers? etc. etc.
  • In each paragraph, I have to convince the reader over and over again.
  • It should fit within the page limit
  • I have to keep myself aware of the fact that my paper must be scientific paper and not an engineering paper.

Writing for my blog is actually much easier for me, because I don't have to spent so much time on these other issues next to the contribution I want to make. Furthermore, because I can link to earlier topics and I know my audience a bit, I don't have to explain the same things over and over again.

Although these observations are quite negative, this does not mean that I want to claim that I shouldn't write any academic papers and that academic papers are useless, but nonetheless it's still a funny observation I have.

Blog posts


Another funny observation is the top 10 of most popular blog posts. The top 10 (at this time) is as follows:

  1. Software deployment complexity. I'm happy that my general blog post about software deployment complexity has raised so much attention, because within the software engineering research community it's typically an ignored subject. In just one week, it surpassed the number of hits of all my other blog posts.
  2. Second computer. For some reason my blog post about my good ol' Commodore Amiga is very popular. For a long time, this was actually my most popular blog post and it's not even research related! It seems that 19 years after Commodore's demise, the Amiga is far from dead.
  3. First blog post. This is the first blog post in which I briefly introduce myself. Apparently, people want to know who I am :-)
  4. NixOS: A purely functional Linux distribution. This is a general blog post explaining the idea and features of NixOS, the Linux distribution built on top of the Nix package manager, which we use as a foundation for our current research project.
  5. First computer. Apart from my good ol' Commodore Amiga, my first computer the: Commodore 128 also still lives on!
  6. The Nix package manager. This blog post covers the Nix package manager, on which NixOS is built. Apparently people are interested in the main Nix concepts as well.
  7. Concepts of programming languages. This blog post is about the 'Concepts of programming languages' course taught at the TU Delft, for which I was a teaching assistent. This course covers various programming languages, which are conceptually different from each other. I actually have no idea why this blog post is so popular.
  8. Using NixOS for declarative deployment and testing. This blog post covers two very nice applications of NixOS in which you can automatically deploy a distributed network of NixOS machines and use the same specification to generate a network of virtual machines for testing. I have presented this topic at FOSDEM, Europe's biggest free and open source software event, and my presentation was well received there :-).
  9. On Nix, NixOS and the Filesystem Hierarchy Standard (FHS). This blog post responds to one of the common criticisms I have received about Nix and NixOS from other distributions. In this blog post I explain why we are different and that it's for a very good reason.
  10. Self-adaptive deployment with Disnix. This blog post is about one of my biggest research contributions, which I have presented at the SEAMS symposium (co-located with ICSE) in Hawaii. In this blog post I have built a framework on top of Disnix and the underlying purely functional deployment model of Nix to make systems self-adaptable by redeployment in case of an event.

My biggest surprise is the fact that the Amiga stuff is so popular. Actually, I have some fun projects that I'm working on, so if I can find any time for it, there may be more to report about.

Conclusion


It seems for me that it pays off to have blog, so hopefully next year there will be much more interesting things to report about. I have one more thing to say and that is:


HAPPY NEW YEAR!!!!!!! (I took the fireworks picture above during the ICSE in Hawaii, just in case you wanted to know ;) )

Porting software to AmigaOS (unconventional style)

$
0
0
As I have mentioned in my previous blog post (in which I reflected over the last year), the Amiga is still not quite dead yet and (for some reason) my blog post about my good ol' Amiga has attracted much more visitors than I expected. In fact, for a long time this was the most interesting story I have written, while most of my other blog posts are mostly about the research that I'm currently doing.

Nowadays, there is still an active community developing Amiga software. For that reason, I have decided to pay some attention to this subject once more. This time I'm going to make it a bit more related to the research I'm currently doing. If you are curious to see how I achieve that goal, please read on...

Geek Gadgets


One of the interesting efforts done in the past is a project called Geek Gadgets, in which the GNU toolchain and many other UNIX utilities are ported to AmigaOS. You could see this effort as something similar to Cygwin, providing a UNIX environment and GNU toolchain on Microsoft Windows.

Interesting packages included in this project are:

  • ixemul.library. A BSD 4.3 kernel running under AmigaOS, which internally translates a number system API calls to AmigaOS kernel calls. The API is specifically modelled after NetBSD.
  • libnix. An ANSI C API library directly using the AmigaOS libraries, instead of the Unix compatibility layer. This library is better suited for developing native AmigaOS applications not requiring any UNIX functionality.
  • GNU Compiler Collection. The free/open-source/ubiquitous compiler suite used on many platforms, such as Linux, Cygwin, FreeBSD, OpenBSD, NetBSD and Mac OS X.
  • Korn Shell. Geek Gadgets provides the pdksh shell as a Bourne-compatible shell instead of bash, which is commonly used on other GNU systems. Probably because it's smaller and faster.

These tools make it possible to port Unix-like applications to AmigaOS as well as writing native AmigaOS applications, using development tools commonly found on free software systems, such as Linux.

Quite a number of applications are ported using this toolset such as TeX, Emacs, the X Window System and SDL, a library which is commonly used on Linux to develop games and other multimedia applications.

Using Geek Gadgets


Below, I have included a screenshot showing the Amiga Workbench and an Amiga Shell. In this Amiga shell, I have opened a Korn Shell session to show the contents of the Geek Gadgets toolset and the version of the GCC compiler.


As you may notice in the screenshot above, the /gg directory is the Geek Gadgets root directory in which a typical UNIX-like filesystem hierarchy is defined with its associated files and utilities.

The Amiga filesystem is organized quite differently as a UNIX filesystem. Whereas a UNIX filesystem is a tree with only one root directory, an Amiga filesystem has many roots. For example, on the Amiga a path can be identified by Assign:RootDirectory/Subdirectory/File, in which an assignment can represent a disk drive identifier, disk label or a random assignment which you can attach to any folder in the filesystem.

Like Cygwin, the ixemul kernel also provides a UNIX to native filesystem mapping, by defining assignments as root directories. For example the /gg directory represents the GG: assignment in which the Geek Gadgets files are stored.

Deploying Geek Gadgets


Deploying a Geek Gadgets environment was a bit trickier than I expected:

  • The latest stable version is much too old, dating from 1998. The Geek Gadgets documentation is quite outdated and does not accurately describe what packages you need from the latest snapshot.
  • In order to use any Geek Gadgets tools, I need to manually set up the Geek Gadgets environment each time, by executing the GG:Sys/S/GG-Startup script and by raising the stack size, because otherwise I can get mysterious lock-ups/crashes. Of course, I could also add these instructions to S:User-Startup, but I don't want the Geek Gadgets to spoil up my regular system when I use native AmigaOS applications.
  • Geek Gadgets uses a traditional UNIX filesystem organisation, with all its disadvantages. For example, packages are deployed in an impure manner because their contents is scattered across the filesystem. I don't like it very much to let development packages pollute my filesystem.

Most importantly, my research as a PhD student is about software deployment in which I try to deal with such inconveniences. For Amiga readers not knowing anything about it, one of our key aspects is the Nix package manager, which we use to build software components from declarative build specifications. Furthermore, Nix has several distinct features such as the ability to store components in isolation, atomic upgrades and rollbacks and garbage collector which safely removes components no longer in use.

Nowadays, I use the Nix package manager for virtually everything that I develop and I have to compile, because it stores all builds isolated and it never pollutes my system. Furthermore, I can also easily use the Nix package manager to build several variants of the same package (e.g. for i686-linux and x86_64-linux), just by modifying several build parameters in the Nix expression for that particular package.

Building AmigaOS applications with Nix


So an interesting question that I have raised to myself is: "Can I use my research about software deployment to deal with these deployment inconveniences of Geek Gadgets on AmigaOS?".

An answer that you probably would expect me to give is that I have ported the Nix package manager to AmigaOS, but unfortunately that isn't possible because Nix requires much more memory than an Amiga has. Furthermore, the ixemul library does not completely support the POSIX API and does not support symlinks, which makes it impossible to run the Nix package manager properly.

Instead, I have developed a Nix function, which should be invoked on a Linux machine. This function launches UAE, the Ultimate Amiga Emulator, to perform a build and stores the build result in the Nix store of the host system. To develop this Nix function I had to create a basic disk image and a function that starts UAE with this disk image in which the actual build is performed.

Creating a disk image



Creating a basic disk image is a straightforward process:

  • UAE must be configured to use a host filesystem directory as a hard drive partition. In the UAE GUI this can be enabled by clicking on 'New filesystem...' button in the 'Harddisks' tab.
  • The Amiga Workbench 3.1 diskettes are required to perform a hard drive installation of the Amiga Workbench. The install disk contains a wizard which takes care of these steps. I performed an 'Immediate user installation' in which I only installed the English language locale, no printers and an American keymap.
  • I have also installed the LhA archiver, because this is the most widely used archiver on the Amiga. I have obtained this version from Aminet: http://aminet.net/package/util/arc/lha. This file is a self extracting archive, which can installed by running the following instructions from the command-line interface:
    T:
    Protect lha.run +e
    lha.run
    Copy lha_68k C:lha

Installing the Geek Gadgets environment is a little trickier though:

  • I used this simple README file from Aminet as a reference describing the base packages I need: http://de4.aminet.net/dev/gg/0README-GG.txt
  • I did not download the Geek Gadgets packages from Aminet, but instead I downloaded the latest snapshot, which I found here: ftp://ftp.back2roots.org/pub/geekgadgets/amiga/m68k/snapshots/990529/bin.
  • Instead of gcc, I have downloaded egcs. Additionally, I have downloaded a2ixlibrary and gawk, which are frequently required to build packages. libg++ is not included in the latest snapshot and apparently also not required.
  • I've extracted all the tarballs on the host system into the GG subfolder of the Amiga drive, because this is much faster. I had to fix to bin/sh symlink to the ksh manually, because the symlink in the tarball is incorrect.
  • A GG: assignment is required so that Geek Gadgets knows where to find its files. This assignment can be made by adding the following line to the S:User-Startup file:
    Assign >NIL: GG: DH0:GG
  • If you want to create native AmigaOS applications, you need to copy the Amiga system headers into GG:os-include. I have found a collection of Geek Gadgets compatible os-include headers here: http://ftp.back2roots.org/back2roots/cds/fred_fish/geekgadgets_vol1_9610/ade-bin
  • In order to automatically perform builds from Nix expressions, we need to start the build process right after the system is booted. To make this possible I commented out the last two lines from the S:Startup-Sequence, to disable the Workbench and to boot into command-line mode:
    ; C:LoadWB
    ; EndCLI >NIL:

    I have added the following lines to the S:User-Startup script to initialize the Geek Gadgets environment and to automatically start the build process:
    Execute GG:Sys/S/GG-Startup
    Stack 200000

    DH0:T
    sh build.sh

Writing a Nix function


Now that we have a basic disk image containing the Amiga Workbench and the Geek Gadgets utilities, we need to write a Nix function that automatically performs the build steps. I will list pieces of the code of this Nix function here, with some explanation.

The AmigaOS build function, takes 4 arguments where 1 argument is optional:

{name, src, buildCommand, buildInputs ? []}:

The name parameter specifies the name of the component, which also appears in the resulting Nix store path. The src parameter is used to specify the source code that must be compiled. This parameter could refer to a tarball, or a directory containing source code. You could also bind this parameter to a function, such as fetchurl to remotely obtain a source tarball. The buildCommand parameter is a string which specifies how the source code can be built. The buildInputs parameter can be used to install additional packages into the Geek Gadgets environment, such as libraries or other build tools which aren't included in the basic disk image.

The next line imports all the Nix package build functions into the scope of our AmigaOS build function, so that we can conveniently access UAE and other utilities:

with import <nixpkgs> {};

We also need to specify where we can find the disk image containing the Workbench and Geek Gadgets. The UAE emulator also needs a kickstart ROM image. The following code fragment specifies where to find them (you need to replace these paths to match your situation):

let
amigaBase = ./amigabase;
kickRom = ./kickrom/kick.rom;
in

The following lines invoke the stdenv.mkDerivation function, which we need to specify how we can actually perform a build. The following code fragment inherits the name from our function header. Furthermore, it adds the UAE emulator in our environment so that we can boot our disk image and perform the compilation. We need procps to kill the emulator, once the build has finished:

stdenv.mkDerivation {
inherit name;

buildInputs = [ uae procps ];

buildCommand = ''

The remainder of the function specifies how the build should be performed. As we're not allowed to mess up the original base image (it's read-only anyway during a Nix build), we need to create a new one in our temp directory of our build. Fortunately, most parts of the AmigaOS filesystem can be used in read-only mode, so we only need to symlink these system directories. The following code fragment creates symlinks to all static AmigaOS directories:

    mkdir hd
cd hd

for i in ${amigaBase}/{C,Classes,Expansion,Fonts,L,Libs,Locale} \
${amigaBase}/{Prefs,Rexxc,S,Storage,System,Tools,Utilities}
do
ln -s "$i"

# Symlink icons
if [ -f "$i.info" ]
then
ln -sf "$i.info"
fi
done

The Geek Gadgets environment however, must be copied to our new temporary hard drive, because we may need to install other packages in this environment. Additionally, we need to fix the permissions of the copied GG directory, because in the Nix store it has been made read-only and we require a writeable GG directory:

    cp -av ${amigaBase}/GG .
chmod 755 GG

cd GG

for i in `find . -type d` `find . -type f`
do
chmod 755 $i
done

If we have any build inputs (such as library packages), we need to unpack them into the Geek Gadgets environment:

    for i in ${toString buildInputs}
do
cp -av $i/* .
done

The next step is copying the source code into a location in which a build can be performed. For this purpose we create a temp T directory in our AmigaOS filesystem. If the source code is a directory, we need to strip the hash off it and we need to make it writable again:

    cd ..

mkdir T
cd T

stripHash ${src}
cp -av ${src} $strippedName

if [ -d "$strippedName" ]
then
chmod -R 755 "$strippedName"
fi

Then we have to execute the instructions defined in the buildCommand somehow. We generate a shell script called buildinstructions.sh containing the contents of the buildCommand string. This script is executed at boot time by the Korn shell.

    echo "src=$strippedName" > buildinstructions.sh

cat >> buildinstructions.sh << "EOF"
${buildCommand}
EOF
We can't directly invoke the build instructions, because we also have to determine whether a build has succeeded or failed. The following code fragments creates an additional script called: build.sh, which invokes the buildinstructions.sh script. After the build instructions script has finished, it determines whether it has succeeded or failed and writes the status into a file called done which is stored in the resulting Nix store path:

    cat > build.sh << "EOF"
( sh -e buildinstructions.sh

if [ $? = 0 ]
then
echo "success" > /OUT/done
else
echo "failure" > /OUT/done
fi
) 2>&1 | tee /OUT/log.txt
EOF
We now have basically configured a bootable disk image, which automatically performs a build. The next step is to provide a number of settings to UAE so that our temporary disk image can be used and that a build is performed properly:

    cd ../..

# Create UAE config file
export HOME=$(pwd)

cat > .uaerc <<EOF
config_description=UAE default configuration
use_gui=no
kickstart_rom_file=${kickRom}
sound_output=none
fastmem_size=8
chipmem_size=4
cpu_speed=max
cpu_type=68ec020
gfx_linemode_windowed=double
filesystem2=rw,:HD0:$(pwd)/hd,1
filesystem=rw,HD0:$(pwd)/hd
filesystem2=rw,:OUT:$out,0
filesystem=rw,OUT:$out
EOF

The code fragment above defines our temporary build directory as HOME directory (In a Nix build environment this variable is set to a non-existent path: /homeless-shelter in order to remove side effects). Furthermore, we generate a UAE configuration file with the following properties:

  • We disable the GUI, because this prevents us running UAE non-interactively.
  • We need to specify where the Kickstart ROM image can be found. This property is defined earlier in the kickRom variable.
  • We disable sound support, because we don't need it and it may cause lock ups in some cases.
  • The Geek Gadgets tools require quite an amount of RAM to run properly, so we've configured the UAE instance to use 2 MiB of Chip RAM and 8 MiB of Fast RAM.
  • Normally the UAE emulator tries to accurately match the speed of a 7 MHz Motorla 68000 chip, which makes building software very slow compared to nowadays' standards. Fortunately, UAE can also use the host CPU as efficiently as possible, which we do in our build function to make builds significantly faster.
  • We also configured two hard drive instances. The HD0: drive corresponds to the disk image we have created earlier containing the Workbench and Geek Gadgets. The OUT: drive corresponds to the Nix store output path, in which we have to store our build result.

After configuring UAE, we have to run it. Since UAE is a GUI application requiring a X11 display server, we have to specify the DISPLAY environment variable:

    mkdir -p $out

export DISPLAY=:0

# Start UAE
uae &

There is no way to shut UAE down from an Amiga session, so we wait until we see the done file in our output directory. Once this file exists we kill the UAE process:

    while [ ! -f $out/done ]
do
sleep 1
done

# Kill the emulator
pkill uae
sleep 1

# Check the build status
[ "$(cat $out/done)" = "success" ]

After executing all the previous steps, the build has either succeeded or failed. If a build has succeeded, we can remove the done file, as well as some temp files created by UAE:

    cd $out
rm done

rm -f `find . -name _UAEFSDB.___`
'';
}

Using the Nix function


The following code fragment shows how this Nix function can be used to build GNU Hello for AmigaOS:

import ./amigaosbuild.nix {
name = "hello";
src = fetchurl {
url = mirror://gnu/hello/hello-2.1.1.tar.gz;
sha256 = "1md7jsfd8pa45z73bz1kszpp01yw6x5ljkjk2hx7wl800any6465";
};
buildCommand = ''
tar xfvz $src
cd hello-2.1.1
./configure --prefix=/OUT
make || true
make install
'';
}

The expression above looks almost identical to the regular Nix expression building GNU Hello. Important to point out is that we store the output of the GNU Hello world in the /OUT directory, which corresponds to the OUT: drive. The GNU Hello build apparently requires help2man to generate a manual page. This tool is not present in our environment, and to make the build succeed I've added || true to the make instruction, so that it always succeeds. By running the following command line instruction:

$ nix-build hello.nix

The GNU Hello component gets build for AmigaOS, which looks like this:


I have also tried compiling a native AmigaOS application, which creates a very simple Intuition GUI window. I wrote the following test program for this purpose:

#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>

#include <stdio.h>

#define INTUITION_VERSION 37

struct Library *IntuitionBase = NULL;

struct TagItem win_tags[] = {
{WA_Left, 20},
{WA_Top, 20},
{WA_Width, 300},
{WA_Height, 120},
{WA_CloseGadget, TRUE},
{WA_Title, "Hello world!"},
{WA_IDCMP, IDCMP_CLOSEWINDOW},
{TAG_DONE, NULL}
};

void handle_window_events(struct Window *window)
{
WaitPort(window->UserPort);
}

int main(int argc, char *argv[])
{
IntuitionBase = OpenLibrary("intuition.library",
INTUITION_VERSION);

if(!IntuitionBase)
{
fprintf(stderr, "Error opening intuition library!\n");
return 1;
}
else
{
struct Window *window = OpenWindowTagList(NULL, win_tags);

if(window == NULL)
fprintf(stderr, "Window failed to open!\n");
else
{
handle_window_events(window);
CloseWindow(window);
}

CloseLibrary(IntuitionBase);
return 0;
}
}

And this is what the result looks like:


So apparently it works fine!

Conclusion


This blog post covers one of the craziest experiments I have done so far. I have developed a Nix function, which builds software for AmigaOS using the Geek Gadgets toolset by creating a disk image and by using UAE.

After reading this blog post (in case you're still interested :-) ), you may wonder if I actually have a real use case for this. The answer is: YES, although I'm not going to reveal what it is yet. Probably it will take a while, because I currently don't have that much spare time for fun projects like these.

I have decided not to commit this function to Nixpkgs, because it's quite hacky and it depends on stuff (like the Amiga Workbench) which I cannot distribute freely. It's probably not so hard to recreate this function yourself. You can freely use the code I have written under the MIT license.

References


  • In order to use this build function you need an Amiga Kickstart ROM image and the Amiga Workbench diskettes. If you don't have these, the legal way to obtain these is by ordering one of the Cloanto's Amiga Forever discs. Alternatively, you could try AROS, a free/open-source operating system reimplementing the AmigaOS APIs, although I have no experience with it so far.
  • Performing builds in virtual machines inside a Nix expression is nothing new. We have similar approaches in our Hydra build farm, in which we generate OpenSUSE, Ubuntu and Fedora machines to build RPM and Debian packages from Nix expressions. NixOS virtualization provides additional advantages, which I have described here.

Availability


UPDATE: I didn't expect this, but it seems that there are people around who actually want to use this. I have recently put some effort in it to make it a bit usable. The source code can be found on the nix-amigaosenv GitHub page, which contains updated instructions. Furthermore, I have made some enhancements, so that builds can be performed much faster and cheaper.

'Engineering' versus 'Science'

$
0
0
As part of my work as a PhD student, I do research in software engineering, in particular software deployment. My research consists of all kind of activities: I talk to all kinds of people (academic people, people from companies), I write and maintain various software tools, such as Disnix, I give presentations and I do various experiments. Most importantly, I write papers which report about various pieces of my research. Usually these papers are supposed to be presented at academic conferences.

Writing papers is not always an easy job. Conferences typically only accept high quality submissions for presentation. Papers are peer-reviewed by members of a program committee and submissions are in competition with each other. Usually, a small percentage of good papers are eligible for presentation. Some papers of mine got accepted immediately, others got rejected and received criticism.

In some of the reviews I have received so far, I get complimented with things like:

This is a remarkable piece of engineering work.

Although this may sound like a compliment, this typically means something bad, because conferences want valuable scientific research and not engineering work. In all these cases I've received such "compliments", the paper was rejected.

Although I understand that a paper has to conform to a certain quality level and not every story is suitable for presentation on a software engineering conference, such compliments bother me a bit, because I don't know exactly what they mean, nor I have an exact idea what the reviewers want me to do with these kind of criticisms. And another big question that I have is: When do we consider something engineering and when is it really science?

Software engineering conferences



There are many software engineering conferences around. We have sub-field conferences about specific domains, such as software testing, reliability engineering, programming languages, reverse engineering and repository mining. Furthermore, we have a number of top general conferences in which every software engineering task is potentially eligible for presentation. The International Conference on Software Engineering (ICSE) probably is the most well known top general conference in our field.

Most of the attendants of these conferences are academic people, although there is also some industry participation. For example, I have heard that the industry participation of ICSE is less than 20%, while this used to be around 50% in the past.

Difference between engineering and science


In the software engineering domain, the difference between science and engineering is not so clear to me. A common perception is that scientific research is what we should do in academia, engineering is what industry does.

Lately I have been looking for answers and (for fun) I dived into the history of the ICSE, the most popular software engineering conference in our field. I've looked into the proceedings of ICSE 1976, which was the first edition of the real ICSE (it seems that ICSE 1975 was actually NCSE: National Conference on Software Engineering). Furthermore, in this year the industry participation (if what I've heard is correct) is around 50%.

When I looked at the proceedings, the following paper caught my interest: 'Research Paradigms in Computer Science' by Peter Wegner from Brown University. In this paper, the author explores 4 influential definitions of computer science. Interestingly enough, this paper also reports about research in engineering:

Research in engineering is directed towards the efficient accomplishment of specific tasks and towards the development of tools that will enable classes of tasks to be accomplished more efficiently.

Furthermore, the paper also makes a distinction between a research engineer and a practicing engineer:

The problem-solving paradigm of the practicing engineer generally involves a sequence of systematic selection or design decisions which progressively narrow down alternative options for accomplishing the task until a unique realization of the task is determined.

The research engineer may use the paradigms of mathematics and physics in the development of tools for the practicing engineer, but is much more concerned with the practical implications of his research than the empirical scientist or mathematician.

Academic contributions


After reading this paper, assuming that this properly defines what research in engineering is about, I have the following idea about academic software engineering research contributions:

  • You shouldn't merely solve a problem for which you have to engineer something. It should be related to software engineering processes.
  • Your contribution should fill a gap within in a software engineering process. For example, it should offer an improvement or a new insight everybody should know about. Furthermore, this contribution must be novel.
  • The contribution should be significant enough.
  • You need strong motivation why this contribution is needed, which is not always obvious. You also need to look at what has been done before.
  • You need to prove what you claim is valid (or at least strong enough) and you need to describe how it compares to (possibly) related work.
  • And of course, you need to explain what you did

If you just solve an arbitrary problem by means of software engineering, without filling a gap, it is engineering.

Reflection


If I take what I have written in the previous section into account and look back to what I've done before, I don't think I have written a pure engineering paper so far. I think that in these cases probably something else went wrong. This is what I think that could have go wrong:

  • The motivation is unclear or misunderstood.
  • Perhaps the paper may contain too many implementation details.
  • There is something wrong with the evaluation method or the evaluation is not strong enough.
  • Reviewers have different expectations about submissions. Maybe this is also due to the fact that software deployment is a very uncommon research subject.
  • A solution is/looks too simple

I find it a bit disappointing that I have to guess about these reasons myself. If I get a bad review, I would appreciate it if reviewers also make themselves clear why they think it's engineering, so that I can do something with their feedback (or preferably: use concrete criticisms as I have shown above). I think that's what peer-reviewing is about, right?

Engineering


I'd also like to elaborate a bit more on engineering in this blog post. Although academic conferences want scientific contributions, is doing engineering work a bad thing? In my opinion it's also a good thing to do engineering work (even as a researcher), for the following reasons:

  • Typically, many software engineering problems arise in practice. Being in the field gives you a lot of experience and a better understanding of particular software engineering problems.
  • Many software engineering contributions are implemented as tools. Tools need to be constructed from various components by using various means. So in order to fill a gap in software engineering processes, you also have to do some software engineering.
  • Tools need to be applied in real world scenarios. In such cases, you may have to study existing systems, extend/integrate your tooling, or even implement work-arounds because you're tooling assumes ideal behaviour.
  • There may be lessons that you have learned in your research that every software engineer should know about.

In my period as a PhD researcher, I have done many engineering contributions, next to the scientific papers I have written. Typically, I use my blog to report about these, such as applying Disnix for deploying .NET services or comparing NixOS with GoboLinux. Although these blog posts aren't really useful scientific contributions, they are if fact more appreciated by the people I work with. Furthermore, these blog posts have also attracted many more readers than all my academic papers combined.

Last year I have also presented pieces of my work at FOSDEM, the Free/Open-Source Developers' European Meeting attracting thousands of developers from all over the world. For some reason, my talk attracted quite a lot of people and I also received much more interesting questions than I have ever received on any academic software engineering conference.

So what's the big deal anyway?


Next to the discussion of the meaning of science and engineering, I'd like to point out that engineering is not something bad, although it may not always be something reviewers of academic conferences are interested in. Engineering aspects, however, are very useful for industry people. They typically care more about what benefits new tools could offer and how they can apply these techniques in their environment instead of seeing a mathematical proof.

There have been many discussions among academic conference organisers about the question why the industry participation is so low these days and how this could be improved. I think one of the big reasons is a mismatch of interests. There are of course more reasons, but this is probably not something you could blame academic people for.

Conclusion


In this blog post, I have tried to discover what scientific research in software engineering is and what ordinary engineering is. I have also expressed my opinion about engineering and that it's not useless, although it may not be something that program committee members of academic conferences are interested in.

Finally, I want to make myself clear that I have nothing against ICSE or any other academic conference. This blog post is not an ICSE rant. I find the ICSE a good conference, which I have attended with pleasure in 2009 and 2011. I have attended a number of very good presentations and I have also met quite a number of great people. Also I'm currently collaborating with a few researchers that I have met there.

(Ok! Ok!... I'm not going to lie about the fact I'm a bit disappointed that our paper for this years' edition has been rejected and I agree that certain parts of the paper can be improved. Furthermore, this blog post is not elaborate about this rejection, but about a phenomenon occurring within the academic software engineering research community that bothers me a bit.)

Deployment of mutable components

$
0
0
It's been quiet here for a while. Lately, I'm very busy with all kinds of research related things (including working on my thesis). So I thought it's time for a new research related episode here on this blog... Yesterday, a paper of mine got accepted.

Purely functional deployment


As you may know, the Nix package manager is also known as the purely functional deployment model (which happens to be the title of Eelco Dolstra's PhD thesis), because it borrows concepts from purely functional programming languages, such as Haskell. In Nix, packages are derived from purely functional build functions, also called derivations:

  • The result of a derivation exclusively depends on the specified inputs of a derivation. If a dependency is not specified, it cannot be found and thus a build fails.
  • In a Nix build environment, many side effects are removed. For example, most environment variables are cleared or set to non-existing values, such as HOME=/homeless-shelter. Also certain commands cannot be used because they have side effects, such as date or hostname.
  • Various common build tools (e.g. GCC and binutils) have been patched to ignore impure directories, such as /usr/lib and /usr/include which may accidentally allow a build to succeed, with improper dependency specifications.
  • Nix stores every component in a so-called Nix store using a special filename, such as: /nix/store/a92pq...-firefox-9.0.1 in which the former part: a92pq... is a hash code derived from all build-time dependencies. This filesystem organisation prevents that dependencies can be implicitly found unless they are explicitly specified in a build process, e.g. through configuration flags or environment variables.
  • To improve purity, builds can be optionally performed in a chroot() environment.
  • Nix components which have been successfully built, are made immutable by removing the write permission bits, analogous to purely functional language objects which are immutable.

As explained in many earlier blog posts, although this approach is unconventional, it has a number of distinct advantages, such as the fact that multiple versions or variants of components can be safely stored next to each other, upgrades are always safe, dependencies are always complete and so on.

Mutable components


Although Nix has several powerful features, one aspect that it is lacking is supporting the deployment of (which I call) mutable components, such as databases. Apart from the fact that the state of mutable components changes continuously (which cannot be supported in Nix, because components are made immutable), they also have several other important properties:

  • Mutable components are typically hosted inside a container, such as a DBMS or application server. In order deploy a mutable component filesystem operations are not always enough; also the container must be notified.
  • The state of mutable components is very often stored in an unisolated directory and in a format close to the underlying implementation of the container. In order to transfer a mutable component from one machine to another, copying state files may (in many cases) not work, because they are incompatible with the target architecture or temporarily inconsistent, because of locks and/or unfinished write operations.

Because of these issues, many containers include tools which allow you to capture state in a portable format and in a consistent manner, e.g. mysqladmin. In the paper, I call the actual files representing state, physical state whereas the dump captured by a tool, such as mysqladmin the logical representation of state.

Dysnomia


To support automated deployment of mutable components using concepts similar to Nix, I have developed a tool called Dysnomia, which originate from the Disnix activation scripts package.

Dysnomia provides a generic interface for mutable components. Basically, it's an extended version of the activation scripts, implementing a snapshot and restore operation, which capture the state of a mutable component and restores them (respectively) by invoking tools that can consistently capture state in a portable manner. Also, for certain types it supports incremental snapshots.

Apart from a generic interface to support deployment of mutable components, we also have to uniquely identify the logical representation of mutable components in a unique manner, similar to hash codes for immutable Nix components. This makes it possible to perform efficient upgrades, because components with the same name do not have to be deployed again.

In Dysnomia, we address components using the following naming convention:

/dysnomia/<type>/<container identifier>/<component name>/<generation number>

The latter component, the generation number, is derived from a container property, such as a MySQL binlog sequence number or Subversion repository number. It may also be possible to use a timestamp, although this has some practical issues.

Extending Disnix


In a few days time, I have created a very hacky version of Disnix using Dysnomia. I have adapted the deployment process of Disnix in two variants:

  • The simple version. In the transition phase, we capture all state of mutable components, transfer the state and restore the state. During this phase access may be blocked and can be very expensive for large datasets.
  • The optimised version. In this version, we transfer the state outside the transition phase so that the system is still accessible. After transferring the state, we enter the transition phase and we transfer an incremental dump of the mutable state components to take changes into account which have been made meanwhile. In this version, the blocking time window is reduced to a minimum reducing the costs of blocking as much as possible.

Discussion


After reading all this, you may think that the problem of dealing with state in conjunction with Nix has been solved and the world has become a much better place. Unfortunately, there are a number of drawbacks, which may be significant:

  • The filesystem is used as an intermediate layer, which may be very expensive for very large databases. Database replication tools can solve these problems much more efficiently.
  • It is not part of Disnix yet. I'm still thinking of integrating it, but it radically changes the behaviour of Disnix. Perhaps it may become an optional feature in the future.
  • Also, the costs of managing state may be higher than the benefits that it gives.
  • The number of supported mutable components is still limited, and not all types of mutable components can be efficiently snapshotted.

Where comes the name from?


One of the aspects not covered in the paper is where the name Dysnomia comes from and it probably sounds very strange to you. Unfortunately, the space in the paper is very limited to explain it :-)

This is how I came to it:

  • Nix is derived from the Dutch word for nothing: 'Niks' (because if you don't specify dependencies, Nix cannot find anything) combined with UNIX, hence: Nix. Coincidentally, Nix is also a mythological figure as well as a name for a moon of the dwarf planet Pluto which is part of the Kuiper belt.
  • Disnix and NixOS also use the original naming convention. For example, Disnix is DIStributed NIX.
  • Hydra, our continuous integration server and Charon, our cloud deployment tool are names based on the other moons of Pluto.
  • Apparently, Pluto has a fourth moon, which is recently discovered, but it does not have a name yet. Furthermore, I don't think this hacky tool is also worthy to bear that new name.
  • I took another dwarf planet from the Kuiper belt: Eris, which happens to be the largest dwarf planet discovered so far. Apparently it has a moon named: Dysnomia. So that explains where the name comes from. Furthermore, I also think it's better to take a moon of a different dwarf planet, because Dysnomia could also be used without Nix (and related applications).


Conclusion


Although I have a very experimental extension supporting deployment of mutable components, it has a number of drawbacks. When I started thinking about this tool, I thought it was a great idea. However, after implementing it and doing some experiments, I think that in some cases the costs are actually higher than the benefits. But nonetheless, I still think it's important to have a solution for this problem and some knowledge, which could lead to interesting discussions.

More details can be found in the paper titled: 'A Generic Approach for Deploying and Upgrading Mutable Software Components' which can be found on my publications page. As usual, my slides can be found on my talks page, once I have prepared them.

I'm going to present this paper at the HotSWUp workshop in Zurich (which is co-located with ICSE 2012). In my last blog post, I was a bit disappointed about my ICSE rejection, but it turns out that I'm going to be there anyway, just in case you want to meet up :-)

To prove once more that I have nothing against ICSE and that I actually like it, here is some shameless promotion:

Software engineering fractions, collaborations and "The System"

$
0
0
As I have explained many times on this blog, software engineering is complicated. It happens quite often, that in order to solve problems or to gain knowledge, people collaborate with each other by various means. Nowadays, we have a wide range of means to share information and to collaborate. A few examples are:



As you may notice, some of these means are quite common in certain fractions of the software engineering community and very uncommon in others. I can roughly divide the software engineering community into three fractions, having a number of distinct characteristics, interests and peculiarities (beware that I'm using stereotypes here and these fractions are not necessarily mutually exclusive):

Academic fraction


This is the group where I currently belong to. Academics are people working for a university and their main goal is doing scientific research. As I have explained earlier, scientific research within the software engineering domain is a bit strange, because there is no clear consensus what this actually means. Earlier, I have dived into literature and I have found a definition, which I will rephrase here once more:
Research in engineering is directed towards the efficient accomplishment of specific tasks and towards the development of tools that will enable classes of tasks to be accomplished more efficiently.

The "deliverables" that academic people produce are, in principle, papers published in peer-reviewed academic conference proceedings and scientific journals. Paper submissions are typically in competition with each other and only papers that are good enough are eligible for publication. The software engineering domain is a bit exceptional compared to many other scientific disciplines, because conference papers are more popular than journal papers.

Academic conferences are primarily about presenting research papers. Most of the attendees of these conferences are other academic people. According to some sources, there used to be a high participation degree of industry people in the past, but this is no longer true, unfortunately.

Industry fraction


The primary goal of industry is (not surprisingly) to develop and sell software (as a product or as a service) or to provide IT services and make profit, which is (preferably) as high as possible.

In order to achieve that goal, industry typically want to be as cost efficient as possible. Therefore, they don't want to invest too much time and effort in secondary goals, such as developing software tools, as these tools cost money and do not immediately give them any profits. Rather, they want to focus themselves as much on their primary goals as possible.

The conferences that industry people attend, are often related to the technology they are using. For example, companies using Java typically attend JavaOne, or companies using Microsoft technology may attend Microsoft TechEd. Companies may also participate in "trade show" conferences, such as CeBIT, to advertise their products and to attract potential new employees.

Community project fraction


Another fraction is what I call the "community project" fraction. Typically, a lot of people refer to this fraction as "Open-Source projects", but I don't want to refer to them like that. While most community projects are distributing their software under free and open-source licenses, there are also commercial parties doing this, without outside involvement. I have written an earlier blog post about Free and Open Source software explaining what this is all about.

Community projects are usually formed by various individuals having various affiliations, share a common interest and work together on common goals. There are many prominent examples of community projects around, such as The Linux Kernel and KDE.

Another notable trait of community projects is that nearly all contributors are also users of the software. Many community projects have an informal organization structure and copyright is owned by each individual contributor. Some community projects are also governed by a legal entity owning the entire codebase, such as the Free Software Foundation, Apache Software Foundation and the Eclipse Foundation.

There are also a number of free and open source conferences around, such as FOSDEM and LinuxCon. Most attendees of these conferences are either users or contributors to community projects and very much interested in new capabilities of software.

"The System"


The industrial and academic fractions have "targets" which they have to reach within a certain period of time. Usually this period is short term. These fractions also want to grow, improve and perform better than the competition.

People in both fractions are periodically assessed by some kind of measurement standard, indicating whether the results (according to this standard) are satisfiable and have increased enough. As a consequence, people in these fractions have a tendency to do as much as possible to improve these numbers according to this standard, rather than doing what have to be done. I call this phenomenon "The System".

Implications of "The System" on the academic fraction


In the academic world, publication records are used as the main productivity / efficiency measurement unit. This often means that the more papers you produce the better you are as a researcher. Furthermore, various other publication quality attributes are taken into account, such as the ranking of the conference or journal and the amount of citations that you have. Some metrics that measure a researchers' productivity are the G-index and the H-index.

Because publications are the primary (or sometimes the only) measurement unit of research, many researchers primarily work to improve these numbers. In my opinion, this is a bad thing.

As a consequence, many researchers spent most of their time aiming at a collection of academic conferences and journals. Each conference and journal have particular requirements, boundaries, traits and peculiarities, such as the allowed subjects, page limits, evaluation methods, stuff of which you know that is going to be well-received by the Program Committee members and stuff which don't. Some of the "tactics" researchers use to get their paper accepted is 'identify the champion', which means that you have a look at the list of Program Committee members and write your paper to please at least one of them, so that he will probably vote in favor of your acceptance of your paper.

Sometimes, I get the impression that doing research this way, looks like a darts game, in which you keep aiming at a fixed number of sections, and keep modifying your arrows until you hit the right score.

If you look at the definition of 'research in engineering' I have given earlier, writing publications and improving publication records is not the only thing that needs to be done. For example, sometimes also "uncommon" aspects have to be investigated, which do not necessarily produce great results, but are nonetheless worth knowing.

Furthermore, new software engineering concepts typically result in tools which have to be developed. Eventually, ideas developed in the academic world have to reach a broader audience and I think tools are the primary way to achieve that goal.

A lot of researchers refrain from doing these steps, because "The System" enforces them to do so. I have heard some people saying: "You shouldn't spent so much time on development. Just develop a prototype and then move on to your next goal!". As a consequence, lots of papers tend to become "forgotten knowledge" and the rest of the software engineering community doesn't care and perhaps reinvent the wheel some day, but implement it in a much crappier way.

Implications of "The System" on the industry fraction


In industry, quite often developers are seen as "code production units" and they have to be used as efficiently as possible. In order to be as efficient as possible, it is desired to reduce as many costs as possible and employees should focus themselves on the primary goals of the company as much as possible. One of the 'solutions' companies implement is to outsource labour to countries in which salaries are lower, to delegate certain tasks to other companies, or completely relying on an external vendor to provide a solution.

In my opinion this is a bad thing for the following reasons (I have taken these arguments from my colleague Rini van Solingen's video log: vlog episode 2 (in Dutch) ):

  • Developing software is not necessarily a process that merely costs some amount of money. Software development is an investment and also gives benefits. The benefits are often overlooked by a lot of managers. Reducing costs, e.g. by hiring cheaper employees with less knowledge, may typically result in fewer benefits.
  • In order to reach your primary goals, you also have to reach secondary goals. For example, banks are not really software companies, but they have to become software companies because their organization depend completely on software.

    I think the same is true for software companies doing software engineering. People developing financial software, may not want to think about build management complexity issues, but they have to, because otherwise it is impossible to properly engineer systems for end-users.

Many companies have the tendency to delegate secondary problems as much as possible, with the assumption that others can do it better, cheaper and more efficiently. In my opinion this is not always necessarily true. Sometimes secondary problems are so specific to a particular industry that there is no general solution provided by an external vendor or by somebody else willing to provide a solution for this.

In such cases, you have to solve these secondary yourself, but many organizations refrain from doing so. They decide to keep living with the burden and prefer to be inefficient. I have worked for several companies (which I'm not going to mention here) and I can speak from experience. I have had several unconventional ideas in mind back then, and the only thing I was doing was fighting resistance, while I could have already solved many secondary problems already.

Another trait I have frequently encountered is that some companies are afraid to participate with other communities, because of the potential advantages the competitors could get. I think for most secondary goals this is not really an issue.

Implications of "The System" on community projects


As far as I can tell, there is no "System" for community projects, as these projects are typically not bound to deadlines or formal assessment procedures. Community projects basically have to keep themselves and the community as a whole happy. Furthermore, these projects are not composed by members of a single organization, but from various individuals all over the world. However, community projects also have a few peculiarities that I'd like to mention.

Quite often, because the developers are also the users of a particular application, it is difficult for non-technical users to get involved and have their problems solved. Sometimes applications delivered by community projects are seen as very unfriendly by non-techinal users.

Also, there are "social-issues" in community projects, such as developers who receive criticism (either about them in personally or about the project in general) immediately feel themselves offended and developers pissing of non-technical users claiming that they are stupid and they don't need a particular feature. The Linux Haters Blog often elaborates on this issue. Another famous phenomenon is "bikeshedding", in which big discussions are held over relatively minor problems, while important bigger problems are overlooked.

Discussion


"The System" of each of these fractions have arised with the intention of improving themselves, but personally I think that these "Systems" actually conflict with other and make things worse, not better.

In principle, the academic fraction (which investigates software engineering techniques) solve secondary problems for the industry fraction. But in order to completely "solve" a secondary problem, usable tools have to be developed, which academic people refrain to do so because it is a waste of time, according to their "System".

Second, industry has to focus themselves on their primary goal (because their "System" requires that) and they don't want to spent too much effort in secondary goals, such as working together with academics to successfully apply research or get involved with community projects sharing knowledge.
It almost looks a bit like a prisoners dilemma to me. Collaboration between these fractions obviously requires several small sacrifices, but it also offers all parties benefits. I also see community projects as a good means to collaborate between academia and industry (and anyone else who is interested). Although this is obvious, all fractions stick to their "System" and, as a consequence, they diverge from each other and don't benefit from each other at all.

I have a few concrete examples of this:

  • The Dutch government as well as the industry in the Netherlands, spent a relatively small amount of money in research, while they want our country to be a 'knowledge economy'. It's actually the least of all countries in the European Union. The government is planning to reduce these investments even more. They expect that companies invest more in research, but in my experience, apart from a few notable exceptions, most of companies are reluctant or have no clue what is going on in the research world. We have very good researchers in the Netherlands, but their work isn't applied that well in industry. In my opinion, that's a shame and a waste. (I have used this blog post as a reference (In Dutch) )
  • As mentioned in an earlier blog post, industry participation at academic conferences is low. Industry people often have different interests than academic people. Nowadays, they rather attend technology related conferences. For industry people, application and benefits of tools and technology is important. More important than a mathematical proof or evaluation showing numbers, which they don't understand.

    I have encountered several boring presentations at academic conferences, showing lots of "greek symbols" and all kinds of complicated things I didn't understand. I'm pretty sure that if the presenter would have attendees from industry, they have no clue what they are talking about and they quickly lose interest.
  • Sometimes people reinvent the wheel, but in a crappier way, which they have to maintain themselves. In my research, for example, I have seen many custom build systems that have a significant maintenance burden. People usually stick to these suboptimal solutions for a long time, while there are many solutions available that are more convenient, more powerful and easier to maintain.

Recommendations



In order to improve the struggle of diverging fractions, I think all fractions have to cooperate better with each other (which is obvious of course) and let themselves go of their "System" in some degree (or better: make sure that the "System" changes). I have a few recommendations:
  • I think "The System" of academic researchers shouldn't be merely about publications. Furthermore, they shouldn't be merely about these fixed collection of conferences/journals each having their own "borders". Publishing stuff is not a bad thing in my opinion, as concepts must be properly explained, evaluated and peer-reviewed. But concepts are useless without any deliverables that can be applied.

    "Playing darts" by only aiming at "sections on a dart board" is bad for research. For example, Edsger Dijkstra, one of the most famous computer scientists published a lot, but most of his publications were his "EWDs"; manuscripts, which he wrote about any subject he want, whenever he wanted, without aiming at anything or keeping some kind of "System" satisfied.
  • As an academic software engineering researcher, you are typically investigating stuff for some kind of "audience" (e.g. developers or testers) and it may possibly be related to certain kind of technology (e.g. Java, Eclipse, Linux etc.). Therefore, I think it's also important to directly work with people from these fractions, address them regularly (e.g. visit them and participate in their technology-related conferences) and see whether you can make your work interesting for them.
  • It's also a good thing to make your tools available by some means. Perhaps joining a community project or start your own community project can be good thing.
  • Companies must know that developing software is an investment and that secondary goals have to be reached in order to achieve primary goals. Some secondary goals cannot be solved efficiently by third parties, as it's too specific for the domain of the company.
  • Companies should not be afraid in participating in other fractions' community means. In fact, they should be more eager in finding out what other fractions have to offer them.

These recommendations may look challenging, but I think the barrier to build better "bridges" between software engineering fractions isn't that high. I have outlined a list various means in the beginning of this blog post, that may help you and I think they are relatively easy to apply without any additional costs.

For example, besides publishing academic papers, I also have this blog and I use Twitter to regularly report about results, findings and other stuff. Furthermore, the tools we are developing are made available to everyone through a community project, called the Nix project.

Apart from academic conferences, I have also presented at an industrial conference as well as FOSDEM, the biggest Free and Open-Source conference in Europe. Actually, our work has been very well received there. Far better than any academic conference I have attended so far.

Why am I writing this?


With the work that I'm doing as a PhD student, I'm trying to address the complete software engineering community, not just a small subset. It's also a shame if 4 years of hard work becomes forgotten knowledge that nobody cares about.

Furthermore, I think that for many reasons, building "bridges" between these software engineering fractions is essential and gives all fractions benefits. But the "Systems" of all these fractions (which are basically there to improve them) drive these fractions apart.

Besides publishing papers, I have spent I considerable amount of time in development of tools, case studies and examples. For example, according to the COCOMO estimation method of ohloh.net, I have spent 2 man-years of effort in Disnix (and I'm the sole author). Furthermore, I have also developed several extensions to Disnix and I also did many contributions to other Nix projects. Apart from development, I'm also maintaining this blog in which, apart from my research, I report about several other technical issues and fun projects.

While all this work is very much appreciated by the people I work with and talk with, it's actually is a waste of time according to "The System" of my fraction. If I would have sticked to "The System", then this blog would never exist. Moreover, I would have never produced the following blog posts, because I don't know how to submit them to any academic conference or journal:

These blog posts are very useful and appreciated. Perhaps not for academic people, but certainly for the other fractions! Finally, these blog posts have attracted many more readers than all my academic papers combined.

P.S. If anyone knows how to "sell" this stuff "scientifically" and knows to make a "dart" out of this which I can throw in a good "section", please let me know! I'd like to integrate this stuff in my PhD thesis, which is primarily about research! ;)

Conclusion


In this blog post, I have identified three fractions within the software engineering community. Each fraction have their distinct characteristics. The academic and industrial fractions have a "System", which have arised to improve the individual fractions, but drive the fractions apart from each other. I have proposed a few recommendations to "bridge" these fractions, but in order to achieve that goal, they have to let themselves go of their "System", which is not easy.

As a final point, I'd like to point out that I have used stereotypes to describe these fractions. These descriptions do not always accurately reflect what happens the real world. In practice, not every academic researcher is completely focused on writing papers. I know many researchers besides me, who write tools and make them publicly available. Actually, my supervisors encourage me to work on tooling and they appreciate the work I'm doing. Furthermore, many of my colleagues also have very good collaborations with other fractions, and often present at non-academic events, which I'm very happy about.

I also said that academic presentations are boring. While I have attended quite a number of boring presentations, I have also seen many good ones, which I liked very much. It's a shame that the rest of the software community does not know about these.

Furthermore, companies aren't necessarily completely driven by making profits. They also care about their customers in some degree and thinking about improvements in technology. And yes: there are collaborations between these fractions which sometimes produce good results.

But nonetheless, although the real word is a bit better than the "stereotype" world I have described, I still see a lot of room for improvement in "bridging" these fractions.

Dynamic analysis of build processes to discover license constraints

$
0
0
As I have explained earlier in the blog post about software deployment complexity, software is rarely self-contained nowadays, but typically use many off the shelf components. Reuse has advantages, such as the fact that productivity increases and products can be finished more quickly. One of the disadvantages is an increasingly more complicated deployment process.

Apart from productivity and deployment aspects, the usage of components under Free and Open Source licenses is very popular. This is probably due to the fact that the source code is available, can be adapted and most software packages are available for free through the internet (free in price, a.k.a. gratis).

What a lot of vendors don't realize, is that most Free and Open-Source components are not in the public domain. They are in fact copyrighted and distributed under licenses ranging from simple permissive ones (allowing you to do almost everything you want including keeping modifications secret) to more complicated copyleft licenses imposing requirements on derived works. The GNU General Public License (GPL) is the most famous copyleft license around.

Because of the obligations that these licenses impose on users, licenses have become a very important non-functional requirement of software systems. Not obeying these licenses could result in costly lawsuits by copyright holders. Busybox is a well-know example of a software package which has been defended successfully in court several times.

Some clarification


Before you read on, I first want to give some clarification to readers unfamiliar with Free and Open Source software. I have written an earlier blog post about Free and Open-Source software explaining what it is and what it is not. In this blog post I also try to clarify a number of common misconceptions.

Most outsiders think that these lawsuits are about money, which is not true. These lawsuits are not held because people include FOSS components in their commercial products and ask money for these products. As I have explained earlier, selling free and open-source software is fine.

These lawsuits are held because some copyleft licenses require that the source code of the derived products or parts thereof are available under the conditions of the same license, which includes access to the source code. Typically, many vendors refrain from publishing source code and do not obey the obligations that these licenses specify. In many cases, vendors are unaware of this.

Background


The research I have done about this subject has a bit of history, which I'd like to explain here :-)


A couple of years ago, when I was in my first year as a PhD student, I've attended ICSE 2009 and there was one talk that I found very inspiring and gave me a lot of ideas. The paper was titled: 'License Integration Patterns: Addressing License Mismatches in Component-Based Development' and presented by Ahmed E. Hassan, which basically covered a large number of FOSS licenses and described patterns how to combine components governed under various licenses in a proper way.

Although their paper covers a great amount of license issues, they were still looking into automation of their patterns, for example to automatically verify derived works. This process turns out te be quite challenging because automating such processes require you to have powerful deployment tools and a complete notion of all dependencies involved in producing an artifact, such as a binary. Fortunately, deployment research is our expertise and our tools are designed for such purposes. For a while, I had several ideas about a possible solution in mind, but I never implemented anything.


Some time later at ASE 2010, which I also attended, there was another talk related to this subject titled: 'A sentence-matching method for automatic license identification of source code files' and given by Yuki Manabe. In this paper a tool was developed, called Ninka, which can be used to analyse sentences in comments of the source code, to determine under which license a source file is governed. I asked Yuki whether the tool was available somewhere, but unfortunately the idea quickly appeared on the bottom of my todo list and I forgot about this (which is a shame).

A while later Daniel German, who is involved in all the publications I have mentioned, was invited by Eelco Dolstra to visit our group in Delft. That visit resulted in an eventual collaboration between me, Eelco Dolstra (from our group), Daniel German, Julius Davies (from University of Victoria) and Armijn Hemel (who is from the gpl-violations.org project as well as owner of Tjaldur, a company specialised in software governance and license compliance engineering).

Motivation


In order to say something about the rights and obligations of software systems, you must know the following things:

  • How are source files combined into a final executable (e.g. static linking, dynamic linking)?
  • What licenses govern the (re)use of source files that were used to build the binary?
  • How can we derive the license of the resulting binary from the build graph containing the source files?

We together wrote a paper to provide an answer for the first question.

Approach


To provide a good answer for that question, we have crafted a method which traces system calls of build processes (essentially the involved processes and what files go in and out) and we produce build graphs out of these traces. Furthermore, the traces of each package are stored in a central database, so that inter package-dependencies can be determined.

We have used the Nix package manager to manage all the build processes. Nix is a very convenient instrument, as it has a number of good features, such as the fact that builds are pure (so no undeclared dependencies can affect the reliability of our results), that it guarantees dependency completeness (so that we are certain that no crucial dependencies affecting the license of the result binary are missed) and because Nix stores all packages in isolation in separate directories, we can easily identify inter-package relationships by looking at absolute file names. Furthermore, the Nix expression language allows us to modify the standard builder environment, without changing any package build specifications.

Tracing system calls


We trace the following system calls:
  • File related system calls, e.g. open(), execve()
  • Process related system calls, e.g. fork(), clone(), vfork()

Apart from capturing traces, there were a number issues we had to deal with:

  • We have to translate all relative paths to absolute paths
  • In Linux, pids wrap around if they exceed 32767, so we have to use a different attribute to distinguish between processes
  • Cycles appear in the graph, if files are read/written multiple times, which we have to remove
  • The are coarse grained processes, such as the install process, which install multiple files in one run. In the resulting graph it looks like the resulting artifact is dependent on all other artifiacts installed by the same process, which is not true. We have to identify these processes and rewrite them.
  • We don't want to know anything about the dependencies of the build tools themselves, because these are not considered derived work.

I have kept the mechanics intentionally brief here, because I don't want to explain them again here. The exact details can be found in the paper.

Build trace graphs


Below I have included a graph of cupsd, an executable belonging to the CUPS package, which we have derived with our tool:



The SVG pictures of this graph as well as several other graphs, can be found here.

By using a graph such as the one of cupsd and by using Ninka to analyse the source files in this graph, one can say something about the license under which the resulting binary is covered. In the paper, we have found an interesting problem with a well known free/open-source package, which I'm not going to reveal in this blog post :-)

Discussion


A reader with Nix experience may probably wonder why we have implemented an additional tracing approach, next to the Nix package manager. The answer is that Nix works on package level, but licenses do not always cover complete packages. There are packages in which individual files are covered under several licenses. Therefore, a more fine-grained tracing approach is required.

Unfortunately, the paper was rejected from ICSE 2012, which I was a bit disappointed about a while ago (although I'm still there anyway because I have to present another paper at HotSWUp). The fact that a paper is not "good enough" is not really what bothers me, but what bothers me is that it is a bit unclear whether this contribution is useful or useless and the fact that the solution is seen as 'too simple' (which is NOT a bad thing IMHO).

Perhaps it may indeed be too simple for a top general conference, but I also have no idea to what other type of conference or journal I could send this. And if this solution is too "practical", would it then perhaps be useful for a 'Software Engineering in Practice Track / Experience Track' at some conference? Although I have heard somebody talking about "engineering perspective", I haven't heard any reviewers suggesting about submitting to another track type.

The only thing that becomes clear to me from the reviews I have received, is that they are not really critical about the contents (although certain details can be strengthened of course), but rather about the significance of the contribution.

I have also noticed that the goal of this paper is generally misunderstood. People think that we are actually solving the complete licensing problem, but instead we provide an important ingredient, which is not there yet. Realising these build graphs, which cover complete build processes are already complicated enough, although the idea of using system call tracing for various purposes is not new. Nobody, however, has used system call tracing for this purpose yet (and therefore had to solve several problems as well). And furthermore, because we're using Nix, the process of experimenting with builds, suddenly becomes much simpler, which with conventional solutions will take significantly more effort.

If you look to the three questions I have given earlier, the paper is about the first question. The ASE 2010 paper provides a solution for the second. The third question is still future work, for an eventual license calculus. But in order to develop such a license calculus the ingredient of complete build trace graphs is required. I'm pretty sure that if I would talk to software deployment people about this, that this story will be appreciated. Unfortunately, as I have explained before, software deployment is a very cold research subject, without a real community.

I'm still thinking what to do with this paper, but I have no idea yet. Furthermore, the amount of time that I have left, is pretty limited. I have decided to put it online and announce it through this blog anyway. Normally, I always report about papers after they have been accepted, but not everything in research can be a 'success story'. Of course, I'm always open for all suggestions.

References


The paper is titled: 'Discovering Software License Constraints: Identifying a Binary's Sources by Tracing Build Processes'. As always, papers can be obtained from my publications page.

The techniques described in this blog post are becoming part of the service portfolio of Tjaldur, a company specialised in software governance. Furthermore, one day I expect that this tool is also going to be integrated in the Nix project.

IFF file format experiments

$
0
0
I haven't written any blog post for a while, but don't worry... I'm still alive, though very busy with writing my PhD thesis. There is still a fun project that showed some interesting results a while ago, but so far I never allowed myself to take the time to report about it.

A while ago, I wrote a blog post about my second computer, the Commodore Amiga. I also mentioned that one of my favourite Amiga programs was Deluxe Paint, which stores images in a so-called "IFF file format", which was ubiquitous on the AmigaOS and supported by many Amiga programs.

Nowadays, this file format is rarely used and also poorly supported in modern applications. Most common viewers cannot open it, although a number of more advanced programs can. However, the quality of their implementations typically differ as well as the features that they support.

What is the IFF file format?


IFF is an abbreviation for Interchange File Format. Quite often, people think that it is just a format to store images, as the most common IFF application format is the InterLeaved BitMap (ILBM) format used by Deluxe Paint and many other programs.

In fact, IFF is a generic purpose container format for structuring data. Apart from pictures, it is also used to store 8-bit audio samples (8SVX), musical scores (SMUS), animations (ANIM) and several other formats. The IFF file format as well as a number of application file formats were designed by Electronic Arts, nowadays a well-known game publishing company, and described in several public domain specifications, which everybody was allowed to implement.

The confusion with the IFF file format is similar to the OGG file format, which are quite often mistakenly identified as Vorbis audio files, as Vorbis is the most common OGG application file format. In fact, OGG is a container format for bitstreams, while Vorbis is an application format to provide lossy audio compression and decompression. There are many other OGG application formats, such as Theora (for video) and Speex (for speech).

IFF concepts


Conceptually, IFF files have a very simple structure. Every IFF file is divided into chunks. Each chunk consists of a 4 character identifier followed by a signed 32-bit integer describing the chunk size, followed by the given amount of bytes representing data:



The picture above shows a very simple example chunk with identifier: 'BODY' which contains 24000 bytes of data. The data in the chunk body represents pixel data.

Although the concept of IFF files using chunks is ridiculously simple, it immediately offers a number of useful features for handling file formats. By looking at a chunk identifier, a program can determine whether it contains useful information to present to end users or whether a chunk is irrelevant and can be skipped. Furthermore, the chunk sizes indicate how much data has to be read or how many bytes must be skipped to reach the next chunk. Using these attributes make it possible to implement a robust parser capable of properly retrieving the data that we want to present.

In principle, every chunk captures custom data. Apart from data chunks, the IFF standard defines a number of special group chunks, which can be used to structure data in a meaningful way. The IFF standard defines three types of group chunks:


  • The FORM chunk, contains an arbitrary collection of data chunks or other group chunks, as shown in the picture above. Our example, defines a FORM which has the type ILBM. In principle, every application file format is essentially a form in which the form type refers to the application file format identifier. In the body of the FORM several data chunks can be found:
    • The BMHD defines the bitmap header containing various general settings, such as the width, height and the amount of colors used.
    • The CMAP defines the red, green and blue color channel values of each color in the palette.
    • The BODY chunk contains pixel data.
  • The CAT chunk may only contain a collection of group chunks, that is only FORM, CAT or LIST chunks.
  • The LIST chunk is an extended CAT chunk that also contains a number of PROP chunks. PROP chunks are group chunks which may only reside in a list and contain a collection of data chunks. These data chunks are shared properties of all group chunks inside the LIST. For example, a LIST containing ILBM FORM chunks, may use a PROP chunk containing a CMAP chunk, which purpose is to share the same palette over a number of bitmap images.

Application file formats can define their own application specific chunks and their attributes. For example, the ILBM file format defines the BMHD data as BitMap Header chunk, containing important attributes of an image, such as the width, height and the amount of colors used and the BODY chunk that stores the actual graphics data.

Apart from these basic concepts, IFF has a number of other small requirements:
  • If a chunk size is odd, then the chunk data must be padded with an extra 0 byte, so that the next chunk is always stored on an even address in memory (as shown in the example form). This requirement was introduced, because the 68000 processor (which the Amiga uses) processes integers much faster on even addresses in memory. In our example form shown earlier, the CMAP chunk is padded.
  • Also application file format attributes of word and long word sizes, must be word aligned (stored on even addresses in memory).
  • All integers must be big-endian, because the Amiga was a big-endian system. This means that on little-endian systems, such as PCs, the byte order of integers has to be reversed.

IFF file format support


The IFF file format is yet simple, but also powerful and served it purpose really well when the Amiga was still alive. For a very large and cool experiment (which I will keep secret for a while) I wanted to open ILBM images in a SDL application (a cross-platform library frequently used to develop games and multimedia applications), as well as modifying ILBM files and saving them. I ran into several issues:

  • Support for most IFF application formats is not present in many common viewers and players. However, some more advanced programs support it. For example, Paint Shop Pro and the SDL_image library have support for viewing ILBM images.
  • These applications all have their own implementation of a specific IFF application format. Some implementations are good, others lack certain features. For example, I have seen several viewers not supporting the special Amiga screen modes, such as Extra HalfBrite (EHB) and Hold-and-Modify (HAM) or the color range cycle chunks.
  • Applications can open simple IFF files that consist of a single FORM, but do not know how to deal with IFF scrap files, i.e. CATs/LISTs containing multiple FORMs of various types, possibly with shared options.
  • Most applications can view IFF application formats, but cannot write them or check for their validity, which may result in crashes if invalid IFF files are opened.
  • A number of open file formats have generic parser libraries, e.g. PNG (libpng), JPEG (libjpeg), GIF (giflib), Ogg (libogg), Vorbis (libvorbis) etc. that applications use to open, parse and save files. There is no equivalent for ILBM and other IFF application formats.

IFF libraries experiment


So after I ran into these issues I've decided to take a look at the IFF specification to see how hard it could be to implement the stuff I needed. After reading the standard, I started appreciating the IFF file format more and more, because of the simplicity and the practical purpose.

Furthermore, instead of implementing yet another crappy parser that only supports a subset, I have decided to do it right and to develop a set of general, good quality, reusable and portable libraries for this purpose, with similar goals to the other file format libraries so that application programs can support IFF application file formats as easy as the common file formats that we use nowadays.

I also think it's good to have file formats which used to be widely used, properly supported on modern platforms. Finally, it looks like fun, so why not doing it?? I did a few experiments that resulted in a number of interesting software packages.

Implementing a SDL ILBM viewer


First, I have decided to implement support for my primary use case: Proper ILBM image support in SDL applications. I have implemented a SDL-based viewer program, having the following architecture:


In the picture above, several components are shown:

  • libiff. This library implements the properties defined in the IFF specification, such as parsing data chunks and groups chunks. Furthermore, it also supports writing IFF files as well as conformance checking.
  • libilbm. This library implements the application chunks as well as the byte run compression algorithm defined in the ILBM specification. Furthermore, it supports several extension chunks and the file format used by the PC version of Deluxe Paint (which has several minor differences compared to Amiga version). Application chunks can be parsed, by defining a table with function pointers to the ILBM functions that handle these and to pass the table to the IFF library functions.
  • libamivideo. This library acts as a conversion library for Amiga graphics data. As explained earlier, the Amiga uses bitplanes to organise graphics and has several special screen modes (Extra-Halfbrite (EHB) and Hold-and-Modify (HAM)) to display more colors out of the predefined color registers. In the SDL viewer we use the libamivideo library to convert Amiga graphics data to chunky or RGB graphics and to emulate the special screen modes.

    Images saved by the PC version of Deluxe Paint however (which have the PBM form type instead of ILBM), do not use bitplanes but chunky graphics, and thus conversion is not necessary.
  • SDL_ILBM. This package contains a high level SDL library as well as the ilbmviewer command-line tool, directly generating SDL surfaces from IFF files containing ILBM images as well as performing the required conversions automatically.

Usage of the SDL ILBM viewer is straight forward:


$ ilbmviewer picture.IFF

The viewer can also be used view IFF scrap files. For example, it may possible to combine several ILBM images as well as other formats (such as a 8SVX file) into a single IFF file. By passing the combined file to the viewer, you can switch between images using the 'Page Up' and 'Page Down' keys. For example:


$ iffjoin Champagne Venus.lores Sample.8SVX > join.IFF
$ ilbmviewer join.IFF

Below I have included some screenshots of the SDL ILBM viewer. The picture on the top left is an image included in Graphicraft, which defines a color range cycle to animate the bird and the bunny. By pressing the 'TAB' key, the viewer cycles the color range to show you the animation. The other screenshots are images included with Deluxe Paint V. As you can see, the viewer also knows how to view HAM images (the Aquarium) and AGA images (the desk).



Implementing a SDL 8SVX player


To see how well my IFF library implementation is designed, I have decided to implement a second IFF application format, namely the 8SVX format used to store 8-bit audio samples. The architecture of the SDL 8SVX player is quite similar to the SDL ILBM viewer, with the following differences:

  • lib8svx. This library implements the application chunks as well as the fibonacci-delta compression method defined in the 8SVX specification. As with libilbm, it also defines a table with function pointers handling application specific chunks to the IFF parser.
  • libresample. This library is used to convert sample rates. 8SVX samples have variable sample rates, while on the PC hardware samples are typically passed to audio buffers with a fixed sample rate. Therefore, we have to convert them.
  • SDL_8SVX. This package contains a library as well as the 8svxplayer command-line tool. Sample rate conversion is automatically done by the SDL library.

As with the SDL ILBM viewer, the SDL 8SVX player can also play samples from scrap IFF files:

$ iffjoin Picture.ILBM Sample.8SVX > join.IFF
$ 8svxplayer join.IFF

Backporting the ILBM viewer to AmigaOS


The third experiment I did was a really crazy one. I have backported the libraries and tools to the AmigaOS. People probably wonder why I want to do something like this, but hey: it is fun, so why shouldn't I do it? The reasons are the same why people want to backport WINE to Windows or AROS back to the Motorola 68000 platform.

Another reason is that I wanted to know how well these libraries perform on the original platform were these file formats were designed for. The Nix AmigaOS build function I have developed previously, helped me a lot in achieving this goal. Apart from a few small fixes, mainly because getopt_long() is not supported, I could easily port the codebase in a straight forward manner without implementing any workarounds.



The architecture shown above is nearly identical to the SDL ILBM viewer. The only difference is the role of the libamivideo library. In the AmigaOS viewer application, it serves the opposite goal compared to the SDL version; it converts images saved by the PC version of Deluxe Paint in chunky graphics format to bitplanes.

It was also nice to write a Intuition GUI application for AmigaOS. Back in the old days, I have never programmed in C and I never wrote a GUI application (apart from a few small experiments in Amiga BASIC), simply because I did not have the knowledge and tools available back then. The AmigaOS libraries were not very difficult to understand and to use.

Below I have included some screenshots of the UAE emulator running the viewer using my own libraries. As you can see, the GUI application has implemented Intuition menus allowing you to open other IFF files using a file picker and to navigate through IFF scrap files:



Conclusion


In this blog post I have described several software packages that resulted from my IFF file format experiments, because I could not find any IFF libraries that have all the features that I want. The purpose of these packages is to provide a set of high quality, complete, portable libraries to display, parse, write and check several IFF application formats.

All the software packages can be obtained from the IFF file format experiments page my homepage and used under various free and non-copylefted software licenses, such as the MIT license and the zlib license.

I haven't made any official releases yet, nor I have defined a roadmap, so don't consider these libraries production ready. Also, the API may still evolve. Probably, at some time in the future I will make it more stable.

I have also found two other projects who implement the IFF standard:

  • The IFF project on Sourceforge, is a C++ library using uSTL, which deviates on some aspects. For example, it stores integers in little-endian format. Furthermore, I haven't seen any application file formats using this library.
  • I also found a project named libiff on Google Code. It seems to have no releases and very little documentation. I have no clue about its capabilities and features.

It is also interesting to point out that I have more stuff on my hard drive, such as libraries supporting several other file formats, which utilise several packages described here. When I can find the time, I'll make these available as well.

A review of conferences in 2008-2009

$
0
0
As some of you may know (and some others probably don't :-) ), I have visited several conferences, which I'm required to attend as part of my job as PhD student. Most of the conferences are academic conferences where I have to present papers that I publish. In contrary to many other research fields - in software engineering - we typically publish at conferences instead of journals.

Apart from academic conferences, I have visited a number of non-academic conferences as well, because apart from being a researcher, I'm also a person interested in technology and development.

In this blog post, I'm going to list the conferences I have visited the past few years and I'm going to share some experiences. The reason that I have written this blog post is basically because of what I have written earlier about software engineering fractions. It's not to have a rant about these conferences, but to share my personal experiences about the topics, audience, peculiarities and other traits, because I think it's important to know how to reach several types of audiences instead of living on an isolated island.

The conference experiences here are in chronological order. In order to keep blog posts short, I start with the first two years (2008-2009):

DSM: Workshop on Domain-Specific Modeling (2008)


This is the first academic event I have ever attended. DSM is a workshop about Domain-Specific Modeling and is typically co-located with OOPSLA (nowadays known as SPLASH). I have attended the 2008 edition in Nashville, Tennessee, USA, which was also my first trip to the USA.

I didn't have to present anything here, but the main reason of attending was that students were allowed to attend any co-located event at OOPSLA for free and one of my colleagues had to present a paper there.

The workshop covers short papers about both theoretical and practical aspects of domain specific modeling. I have seen many kinds of submissions, ranging from simple ideas to a number of tools that have a significant practical use. I have even seen some submissions that me and my colleagues still laugh about today (including their paper).

One of the nice aspects of this workshop is that there is a lot of room for discussion with the attendants and a relatively low barrier of getting your idea published (this is both positive as well as a negative thing).

The attendants of this workshop are mostly academic people, but also quite a number of industry people, showing industrial applications. Below I have included a picture taken of the attendants (people who know me will surely recognise me :-) )


HotSWUp: Workshop on Hot Topics in Software Upgrades (2008)


HotSWUp is the second academic event I have attended. HotSWUp is a cross-disciplinary workshop about software upgrades in any sub field, such as programming languages, operating systems, distributed systems and so on. This event was also co-located with OOPSLA and held in Nashville.

In this workshop, I had to present my first research paper, covering distributed atomic upgrades, an important aspect of my masters thesis.

HotSWUp was a very great workshop and a great experience for me. There were many nice papers covering great ideas, such as distributed upgrades, package management upgrades and how to safely mirror software components with untrusted parties. Even though many of these papers are not directly applicable to my research, they still have a fair amount of practical usage that I liked very much.

I received interesting questions, suggestions and feedback. Furthermore, there was also a lot of room for discussion that gave me many interesting ideas and several new research directions.

I have also met a number of interesting people close to my research. I met two "competitors" from the Mancoosi project (one of them is now the current Debian project leader), who also investigate package management related issues. We had a very nice opportunity to get to acquainted and share ideas about package management. I also met two other people who did similar kind of research with distributed systems.


OOPSLA: Object-Oriented Programming, Systems, Languages & Applications (2008)


OOPSLA is the first academic conference I have attended (which was basically the host conference of the two previous workshops). Actually, OOPSLA was the only conference I knew about before I started my PhD and I very much liked the fact that I was able to attend it. Moreover, another colleague of mine had to present a full paper there and several others had a poster submission about WebDSL.

The papers of OOPSLA were mostly about practical aspects of Object-Oriented programming languages or related issues, such as garbage collection. There were quite a number of interesting papers showing good practical usage, such as the fact that using inverse lookups is better way of refactoring code. I saw an interesting paper using Robocode as a case-study, to which I was addicted when I started learning programming in Java.

There were also some presentations that were a bit hard to follow. For example, I still remember this presentation showing ovals with curly lines attached to it. When I saw those figures it reminded me of something totally different (which was probably not something that the presenter has intended :-) )

Another funny thing I have noticed during the presentations, was some guy in the audience, who was always sleeping during the presentations and could not keep his eyes open.

Apart from attending presentations, I also attended two tutorials, which were also free for students. I learned a thing or two about the Scala programming language, which combines object-oriented, functional programming and several other concepts in a new programming language which builts on top of the Java virtual machine. I also did a Smalltalk tutorial involving the Squeak implementation, which can also be used to develop web applications in Smalltalk.

Nowadays, OOPSLA no longer specifically focuses itself on object-oriented programming languages anymore. It's even not focused on programming languages, but on software engineering in general. To reflect the broadened scope, the new name of the conference is SPLASH: Systems, Programming, Languages and Applications: Software for Humanity.

FOSDEM: Free and Open Source Software Developers' European Meeting (2009)


FOSDEM was the next and a non-academic that I have visited. I was not required to visit it nor I had to present something. The main reason of attending it, was because I have always been involved with free and open source software.

FOSDEM is the biggest free and open-source event in Europe in which virtually every well known free and open-source project is represented, such as the X Window System, the Linux kernel, KDE, Mozilla, GNOME etc. FOSDEM is always held in Brussels at the campus of the Université libre de Bruxelles and can be visited by anyone interested for free (gratis).

When I arrived there for the first time, I was actually a bit "surprised" about the conference venue (the quality of the buildings were a bit "different" than I expected, after the impression I got when looking at their website :-) ).


I also noticed that there were an overwhelming amount of attendants. At the keynote presentation, the entire Janson auditorium is completely filled with free and open source enthusiasts, as shown in the picture above. Some of them were really, really enthusiastic about the stuff they are working, as may see in the picture when looking at the headgear of some of the attendants.

Apart from a filled Janson auditorium room, it was also very difficult to move from one room to another or to look for somebody you know, because the hallways were always full of people.

The quality of the talks is -- as with many conferences -- of varying quality. I liked the talks about GEM/KMS and Ext4. There were also a number of talks, that were hard to follow and not well prepared. In contrary to academic conferences, where the session chair typically has a question for you (when nobody else has one), here at FOSDEM, the session chair has no mercy and immediately announces the next speaker.

ICSE: International Conference on Software Engineering (2009)



ICSE was the second top general software engineering conference I have attended. The main reason of attending it was because I had to present a paper at the co-located cloud computing workshop.

This conference was held in Vancouver, British Columbia, Canada and my visit was actually a bit special, as it was the first time for me to travel by plane alone and to travel such a long distance. :-)

The ICSE conference is a very broad conference covering topics in the entire software engineering spectrum, ranging from requirements engineering, testing, model checking and collaboration. Although software deployment is also listed on their call for papers, I haven't encountered any papers covering this subject in the last few years, unfortunately.

This years' ICSE edition had a very good atmosphere and I've met quite a number of interesting people there as well as some familiar ones from OOPSLA and HotSWUp. One of the papers presented there resulted in a collaboration many years later.

I also had to cheer for my former colleague: Ali Mesbah who presented his paper: 'Invariant-Based Automatic Testing of Ajax User Interfaces' for which he won the ACM SIGSOFT Distinguished paper award.

The social event was held at the Vancouver Aquarium and included a nice show with dolphins. Apart from the conference, I also took a few days off to explore the environment and I went to many interesting places, such as Stanley Park, Dr. Sun-Yat Sen Garden and Granville Island.

I also ended up in an infamous street called: 'East Hastings', for which I have been warned not visiting it, a few days later (so you have been warned now!!). I have some interesting pictures included below:


ICSE-Cloud: ICSE Workshop on Software Engineering Challenges in Cloud Computing (2009)



The ICSE Cloud workshop was the last event I have attended in 2009 in which I had to present a paper. The picture above, is taken by Jan S. Rellermeyer who also attended this workshop and HotSWUp, which I have described earlier.

Apart from a very good ICSE experience, the ICSE cloud shop was also a very nice workshop, with lots of discussions. Another important aspect was the high industry participation degree and especially the first keynote, given by somebody from Amazon, the company who basically pioneered the 'cloud computing' term.

Although I have to admit that the paper I had to present there was not one of my strongest contributions, it was actually quite well received there. Furthermore, for some unknown reasons, it also my most downloaded and cited paper.

Conclusion


This blog post reports about my conference experiences from the begin period of my career as a PhD researcher. In a future blog post I'll report about the next years, so stay tuned...

A review of conferences in 2010

$
0
0
Previously, I wrote a review of the conferences I have attended in 2008-2009. In this blog post, I will cover those I have visited in 2010. 2010 was a very busy conference year for me and in order to keep things short, I have decided to dedicate a full blog post to this year.

FOSDEM: Free and Open Source Software Developers' European Meeting (2010)


The first conference that I attended in 2010 was FOSDEM, which I visited for the second time. As with my visit last year, the experience was nearly identical - the same building with the same "peculiar atmosphere" and the same kind of enthusiastic people. I also slept in the same hotel in Brussels (whose staff is unable to speak Dutch, for some reason).

During this years' edition I have met quite a number of interesting people. Two of them were Nix developers I have frequently spoken with on the IRC, but never met in person.

Nicolas Pierron gave a talk about NixOS and the NixOS configuration system, which he had implemented in his spare time.

Apart from a number of Nix developers, we have also seen some members of the competing Macoosi project. Eelco and I met the RPM5 maintainer (also member of Mancoosi). He had some interesting ideas about package management and he proposed to merge our approaches (i.e. the purely functional model), although he did not clearly explain how. Although some attempts have been made by the Mancoosi members, it did not result into anything useful, unfortunately.

SEAA: EUROMICRO Conference on Software Engineering and Advanced Applications (2010)


The next conference of 2010 was another academic one - SEAA, which was a conference I did not know about. I ended up visiting this conference, because my CBSE paper submission was rejected.

The rejection was actually not a surprise. I really did a poor job. Parts of the paper were incomplete, I tried to put too many technical details in it and I did not study related work too well. Most of these flaws were due to time pressure.

Although it was disappointing to have a paper rejected, the good thing about it was that the reviewers listed all my flaws, suggested how certain sections of the paper could be improved and they gave me a number of references that I should study. A few days later I received an e-mail in which they encouraged me to submit my revised paper to SEAA, which I did.

As a sidenote: I think this is something that more reviewers of conference papers should do. Nearly all my other rejections always resulted in a few vague comments, which were not useful to me at all, nor gave me any insights in what to revise.


The SEAA conference was located in France, in a city called Lille (which apparently has a Dutch translation: Rijsel) and held at the Polytech' Lille. I had no idea what to expect from this conference, but my experience was quite positive. The conference had very friendly and enthusiastic organizers. Some of them apparently have a long organizing reputation and knew many participants quite well.


Moreover, the conference was co-located with the EUROMICRO DSD (Digital System Design) conference and the keynote sessions of SEAA and DSD were shared. During these keynotes, I also learned a thing or two about embedded systems and VHDL. A few keynotes were given by industry people.


The social event was a dinner at Chateau de Bourgogne in Estaimbourg and the wine tasted good :-).

Unfortunately, I had to present my paper the next day as the second presenter, in the first presentation slot (somewhere at 9:00 in the morning). I really had a hard time getting up and to get myself motivated, but it turned out that I was well prepared - nobody was sleeping during my presentation and I received a number interesting questions.

WASDeTT: Workshop on Academic Software Development Tools and Techniques (2010)


The next event that I attended was WASDeTT, which was co-located with ASE and held at the University of Antwerp.

As explained earlier, my CBSE submission was rejected partially because I included too much implementation details. Some time later I "discovered" this workshop that is focused on the development of tools within academia and development aspects in general. For that reason, I have decided to write a tool-oriented paper for Disnix, covering the latest version, implementation details and extensions. Because the page limit was 25 pages, I could write down all the stuff that I could not do in the SEAA paper.

The workshop was not about the tools themselves, but rather about their development aspects. So instead of presenting the concepts of Disnix again, I have explained all its related tool development aspects and development choices. We have had some interesting discussions, most notably - how to make research tools available to other researchers, which (of course) is a deployment issue.

One of the ideas was making a tool available as a web application. I also suggested Nix, as it provides complete dependencies and reproducible deployment. The suggestion, however, was slammed by a fellow workshop participant stating that Nix is nice, but a "conquer-the-world approach".

ASE: International Conference on Automated Software Engineering (2010)



I have also attended ASE, the host conference of the WASDeTT workshop. ASE is a conference that was known as KBSA (Knowledge Based Software Assistant) in the past, as it purpose was to use artificial intelligence techniques to automate all phases of a software engineering process. Nowadays, the domain has been broadened to software engineering in general and ASE is more or less a general conference on nearly the same level as ICSE, with a comparable paper acceptance rate.

Before I left, I considered Antwerp a very "boring" place compared to all the previous conference locations (as I have visited Antwerp many times and I can speak to its residents in Dutch, my native language), but the entire experience was much much better than I expected.


One of the good things about ASE compared to ICSE, is that it is less crowded and it has fewer parallel sessions (at ASE there were only 2 parallel sessions, while at ICSE there are 6 or even more, I'm not sure :-) ). At ASE, it was easier for me to meet new people and to have discussions.

Two papers were very interesting at ASE. One of them was from the Mancoosi project (our "competitors"), in which they have used SAT-solvers for solving dependency resolution problems. The other one was about a tool called Ninka, which can be used to derive licenses from source files using sentence matching techniques. We have used Ninka in our research as well.


ASE included two social events - a beer tasting event in the city hall (which was interesting, because I have seen the city hall many times, but I have never seen it from the inside) and a banquet at the Antwerp Zoo. After both events, I noticed that several conference attendees were unable to walk back to their hotels in a straight line. I have to admit that it took me a bit of effort too :-)

ISSRE: International Symposium on Software Reliability Engineering (2010)


ISSRE was the third academic conference that I have attended in 2010. ISSRE is a conference about reliability engineering and related subjects, such as testing. We ended up there, because our ICSE submission was rejected (although we made it very close). We have turned the testing part of this rejected paper into a paper for ISSRE.

ISSRE was also an unknown conference to me and held in a suburb of San Jose, California, which was basically composed of a large number of Cisco buildings. The conference itself was also held at Cisco.


I've noticed that the conference also had very friendly and enthusiastic organizers and a loyal group of visitors that knew each other quite well. Furthermore, the organizers and session chairs were eager to meet all the new/unknown participants including me and Eelco.

A lot of the papers covered topics that were completely unknown to me. For example, I still remember a paper covering a software aging analysis of the Linux kernel. Before attending the presentation, I had no clue what software aging was. In turned out that it was about "progressive performance degradation or a sudden hang/crash of a software system due to exhaustion of operating system resources, fragmentation and accumulation of errors".

There were many more interesting papers. Another paper I liked was about fixing certain undefined features in the C programming language and the "political process" of the C standards committee.

There was also another presentation in which (apparently) something went wrong, and the speaker cried some kind of F-word out loud :-)


Another good aspect of this conference was the high industry participation degree of which the organizers were very proud. I've talked to one of them about other conferences that I've attended, such as ICSE, and he said to me that these conferences are "so highly academic", which turned out that this is indeed true, unfortunately (which does not implicate that they are useless, of course).


The social event was held at the Tech Museum in San Jose, which had some exciting attractions, such as an earthquake simulator and an interesting exercise in which you had to construct a road by using a number of random objects, so that the ball can safely roll from the entrance to the exit. As you may see in the picture above, Eelco is a smart guy and knew how to do it.

LAC: Landelijk Architectuur Congres (translation: 'National Architecture Congress') (2010)


The LAC (Dutch National Architecture Congress) was the last conference I have attended in 2010, which was basically an industry oriented conference with a bit of research participation. Furthermore, nearly all the presentations were in Dutch.

I ended up visiting this conference, because our funding agency: NWO/Jacquard had its own session and I was asked to give a presentation about PDS, the research project I'm participating in.

Apart from giving a presentation about my project, I also took some time to explore the conference venue. There were a lot of companies there presenting themselves (probably to attract new potential employees), showing all kinds of pictures representing software architectures.

One of those pictures captured my interest, because it looked like a painting and it did not make sense to me.

I asked one of the presenters what the picture is supposed to mean and I heard a story that I did not understand. After a while, he started talking about his projects, such as the traffic light systems, and suddenly the conversation became much more interesting.

Another funny thing is that the conference was dominated by certain buzz words, such as Agile and TOGAF (which I have never heard of previously). It turned out that TOGAF is an framework developed by The Open Group providing a comprehensive approach for designing, planning, implementing, and governing an enterprise information architecture.

One of the major differences I have noticed between this conference and an academic conference covering software architectures, is that industrial conferences are dominated by tools and standards, whereas academic conferences are mostly about concepts.

Conclusion


In this blog post I have described all conferences that I have attended in 2010. Stay tuned, as there are two more years to come...

A review of conferences in 2011-2012

$
0
0
It's time for the final episode in the "visited conference series". Fortunately, 2011 and 2012 were not as busy as 2010, so I can put the remaining ones in a single blog post.

FOSDEM: Free and Open Source Software Developers' European Meeting (2011)


2011 started with FOSDEM as with 2010. As with all the previous editions, the FOSDEM experience is always the same as usual - the same peculiar building etc. etc. (see my previous blog posts).


In this edition, I have also given a talk about NixOS titled: "Using NixOS for declarative deployment and testing". I didn't really know what to expect, but it turned out that it was received quite well. After my talk, I saw some #fosdem tweets on Twitter, in which one of the attendants described my talk as one of the most exciting ones next to systemd and the Google Go language (personally, I also find these two other talks quite good).

SEAMS: Software Engineering for Adaptive and Self-Managing Systems (2011)


The next event was another academic one: SEAMS, which is about self-adaptive and self-managing systems. SEAMS was co-located with ICSE and a number of other events, such as MSR, and held in Honolulu, Hawaii.


SEAMS looked like an interesting event to me, but I had some difficulties finding attendants that were looking into the same issues I did. Most of the presentations were about embedded software and covered issues I did not know about or understand. Although service-oriented systems were listed on their call for papers, I was the only one with a paper in that domain.

I missed some interaction between the participants in general. Perhaps, it's due to the fact that SEAMS was originally a workshop and upgraded to a symposium. Furthermore, this edition had a record number of participants and submissions. Also, the panel discussion was not very interesting and apart from the panel members, nobody took part.

Another disappointing thing is that after the panel discussion a number of attendants left and I had to present my paper in the final slot, with only half of the people left.


The social event was at a Chinese restaurant in Honolulu and was much better. Here, I finally had the opportunity to meet people and to have discussions about research. One attendant suggested a partial solution to me, I was struggling with for a while.

In general, SEAMS was not a bad event although several aspects could be improved and the domain does not entirely map to the kind of research that I'm doing.

ICSE: International Conference on Software Engineering (2011)


Apart from SEAMS, I also attended ICSE, which was held at the same place (Honolulu, Hawaii).


The picture above shows how awesome the environment is. This picture has nothing to do with the conference of course, but I like to show it to you anyway :-)


The conference experience was good and actually a bit better than the 2009's edition, that I have attended previously. A colleague as well as a former colleague had to present a paper there about spreadsheets and testing cross browser compatibility. Apart from my colleague's presentations, there was another good presentation titled: "An Empirical Study of Build Maintenance Effort", which contains a collection of empirical results relevant to our research.


The social event was a dinner, which included an amazing show with lots of typical Hawaiian cultural aspects.

FOSDEM: Free and Open Source Software Developers' European Meeting (2012)



I started 2012 with FOSDEM, as with the previous two years. This year was a bit special compared to the others, as I had a lot of difficulties getting there due to the weather conditions. In 2012, there was a lot of snowfall. As a result, I arrived in Brussels somewhere in the afternoon, although it gave me some pretty pictures, such as the one above, which I took from a small train station en route, because we had to wait until a defect was fixed.

You probably expect me to say that the FOSDEM experience is same as usual. Although it was held at the ULB campus like all the other years, several more buildings were used for the talks. These buildings also had a much better quality compared to the regular ones. As a result, the hallways were less crowded (which is a good thing). Normally, I was always struggling to get from one devroom to another.


The picture above shows a room in a newer building in which the Wayland talk was held.

HotSWUp: Workshop on Hot Topics in Software Upgrades (2012)


In 2012, I attended HotSWUp for the second time. HotSWUp was the first academic event that I have attended four years earlier. This time it was co-located with ICSE and held at the Irchel Campus of the University of Zürich, Switzerland.


I haven't attended any academic events for a while, and a day before the workshop I didn't expect it to be that exciting. The first HotSWUp was already great, and this one was even a bit better.

There were many interesting presentations, covering upgrade aspects in various domains ranging from programming language level, to component level and system level. As with the first HotSWUp, I liked the cross disciplinary aspect very much.

I was quite satisfied with my own presentation, which raised a number of interesting questions, such as how to version components. Moreover, I received an interesting suggestion that I could use to optimise the approach described in my paper.

The social event was a dinner in a vegetarian restaurant. Normally, I wouldn't pick such a location, but it was interesting anyway. The fake meat tasted like real meat. After the dinner, me and several other participants had a couple of beers somewhere else.

ICSE: International Conference on Software Engineering (2012)



In addition to HotSWup, I also attended ICSE - the host conference held in the Kongresshaus Zürich. It is the third time for me attending ICSE.

This years ICSE was nice, had some interesting talks (two of them were of my colleagues, one about code smells in spreadsheets and the other about test confessions of developers), but I'm a bit critical about this years' edition compared to my previous experiences.

The quality of the first two keynote presentations were a bit disappointing and I really had to force myself listening, which (of course) failed after a few minutes. The third keynote was much better, although the speaker could have included more recent examples of research in software architectures.

Another thing was the conference venue itself. The rooms for the research talks were much too small, overly crowded and without any air conditioning (so the temperatures were really high). As a result, I sometimes had difficulties listening to a talk and it was almost impossible to ask questions.

Furthermore, it was difficult to talk to new people on the hallways, also partially due to the weird structure of the conference venue. Fortunately, I did not limit me entirely to meet new people, but it could have been better.


We had two social events at ICSE. The last one was a dinner, which included a show with two singers and a keyboard player, as shown above.

Although I'm critical about this years' ICSE, it was not a bad conference, but some things could have been better.

Conclusions


In this blog posts I have described the events I have attended in 2011 and 2012, which were less busy as 2010. The only new event I have attended was SEAMS.

These were all the conferences I have visited in my period as as a PhD student. In a next blog post, I'll try to draw some general conclusions from these blog posts.

My post-PhD career, a.k.a. leaving academia

$
0
0
It's been quiet here on my blog for a while now. Meanwhile, I'm more or less finished writing my PhD thesis. I still have to defend my thesis -- currently, it's being reviewed by my supervisors and my reading committee. As I have decided not to write a thesis in which (apart from the introduction and conclusion) the chapters are composed of my papers (as most people do in our research group), this will take a bit longer than usual.

Furthermore, my employment contract with the university has expired (in the Netherlands PhD students are typically employed a university). Since this month, I have started my new job at an industrial company. So essentially, I left academia.

On leaving academia


I think that some people that know me and haven't seen me in a while may be surprised (or perhaps shocked :-) ) by this announcement, so I think it would be a good idea to give an explanation why I have decided not to pursue a research career.

First, I'd like to stress out that the last four years were great, although there were a few periods that could have been better. I have no regrets becoming a PhD student (as opposed to working for an industrial company) -- I did many interesting things, I have been at many interesting places around the world, presented my research and software at a number of international software engineering conferences, learned interesting/useful stuff and I have met quite a number of interesting people. I'm really thankful for that to my supervisors, who gave me this opportunity.

Apart from research, one of the other things I'm really proud of is the practical impact of the work I'm involved with. For example, I gave a presentation at FOSDEM about NixOS -- a non-academic event -- which was quite successful. Apart from FOSDEM, I also gave a number of talks and demonstrations at industrial companies that were very well received. Finally, I'm also happy about the impact of my blog.

After listing all these positive traits, it almost sounds a bit odd that I'm not continuing the same path, which I often hear from outsiders. I have the following reasons for this:

  1. My working style does not completely map to the job description of a researcher. Apart from doing the work to get things published, I have also invested a significant amount of time and effort in the tools and their practical usage.

    As I have also presented frequently to people outside the academic community, I typically use a lot of practical examples and I often have a number of demos showing good practical usage. These aspects are nice, but are (in principle) not part of my job description. Quite often, outsiders become happy after seeing these aspects and think that my research is about doing that kind of stuff, which is not true.

  2. It's about publishing. As I have explained earlier in a number of blog posts, researchers have to publish and often it's used as the primary means to measure their productivity.

    I know some people that have left academia because they hate writing papers and the pressure that it sometimes gives. I don't really hate writing papers, although I've had my frustrating moments sometimes -- actually, if I have a good idea I'm very eager to write them down.

    What bothers me is that my research subject -- software deployment -- is not a very popular topic in the software engineering research world. If I would continue my career in research, I have to produce more publications, preferably at highly ranked conferences and journals.

    It's difficult to achieve this goal with my current research topic and working style. As a consequence, I'm more or less forced to pick subjects that are better publishable, which basically forces me to check the interests of the program committee members and do stuff that I'm not always interested in. I'm not somebody who likes to work that way.

    Some research topics are hyper-specialized, which is not always a good thing. I have noticed that even for my research (that already looks quite practical to most people in the research community) is difficult to sell conceptually to non-academic people, unless I do it the right way. For a number of presentations that I have seen at conferences, I'm pretty sure that people for industry would lose their interest in a matter of minutes and have no clue what the speaker is talking about.

    For many of these papers, the "real world" does not care about and as a consequence they tend to become forgotten knowledge. I'm not somebody who likes to do stuff that nobody cares about and do not bring any value to the software engineering community as a whole.

    Furthermore, if I would spend my time to publish more, there is less time to do engineering work and to produce/improve tools that can actually do something.

    I've picked my current research project, because I like solving problems that I really believe that they are relevant and I want to add value. However, the "deliverables" of my style unfortunately don't always map to publishable units at academic events.

  3. I want to add more practical value. I have always been a person that likes to build stuff. If I have a nice idea in mind, I'm always very eager to try it out and to make piece of software that does something, although it is not always very relevant. For the last 6 months, I had no time for doing stuff like this. Nearly all my time was consumed by finishing publications, writing my thesis and preparing/visiting a conference.

Looking for a new job


As my time was completely consumed by finishing publications and writing my thesis the last 6 months, I didn't really had the time to think about a new career perspective. At the end of August, I have decided to put my CV online and I have used the entire month of September to visit and talk to companies.

I was approached by many companies and I have visited all of them in a circle of Rotterdam, Amsterdam, Eindhoven and Utrecht. So I have traveled quite a lot :-).

In the beginning, I felt a bit worried, because it's been a long time ago that I officially applied for a job and I knew that there are a number of prejudices that industry people have on academics like me. This a bit funny, because when I was still a bachelor's student I was not worried about application procedures or getting a job at all :-)

First it looked like my view on industry turned out to be true -- some potential employers did not care about my research career, just asked me: "can you program in Java?" and offered me a salary, which was way lower that my current salary. Some of them also did not know what a PhD is and treated me the same as an undergrad student.

Furthermore, at one company I had to perform a number of capacity tests to check whether I was smart enough. I had to do tests, such as verbal analogies, number sequences, and abstract reasoning. Fortunately, I did the test well enough. There were a few applicants that immediately had to leave because their score was too low and the company was not even interested talking to them. I have made it to the last round and they gave me a job offer, but I refused it. :-)

Fortunately, I did not unlearn my application skills (nearly all of them went quite successfully) and not all companies that I talked to were disappointing -- in the last 2 weeks of September I had "collected" 4 interesting job offers, with good salaries and interesting job aspects. I have met a number of interesting people at these companies and it was very hard for me to turn 3 of them down. A few of them were very disappointed that I rejected them. :-)

In total, I received 6 job offers, one application turned out to be a mismatch of interests from both sides, and 1 rejection after the second round. Apparently, that company was looking for somebody that just wants to write code and not somebody who's critical like me :-).

My new job: Software Architect @ Conference Compass



Currently, I have joined Conference Compass, a Delft-based startup company developing applications (mostly Apps for mobile devices) to improve the experience of conference participants.

I will fulfill the role of Software Architect -- I'm involved with many technical aspects, ranging from design, implementation, documentation and (interestingly enough) deployment.

The main reason of joining this company is that the company is small, there is a lot of interesting challenges that I can work on, a lot of room in things that I can do/improve, and the atmosphere -- 3 employees are PhDs (once I graduate they have 4 of them) and are -- apart from technical aspects -- very much interested in applying new concepts.

Even more interesting is that there is room in which I can use my experience from my research background and that they are very much interested in participation in free and open-source software projects.

Another interesting aspect is that they are located in the YES!Delft incubation centre, which is supported by various external parties including Delft University of Technology. In fact, I'm not that far away from my previous working spot (only 100 meters or so). I can see my former employer's building from the window here. :-)

In my past career, I have worked for medium sized companies as well as big ones. Joining a small group is a new experience to me.

The future of Disnix and other components of the Nix project


After reading this, you may possibly wonder what the future is of the software that I wrote during my PhD career, in particular Disnix and other components part of the Nix project.

As I may have already partially revealed on this blog, my new employer is also interested in the deployment technologies of my previous job. One of their biggest interests is having this technology supported in the mobile space and in the cloud.

Furthermore, my former employer is still using our Nix-based Hydra buildfarm and my two former colleagues (who are now also employed elsewhere) still maintain it and use the Nix technology at their company as well.

So in short: The Nix project is far from dead and is still actively being used. Now that we're not required to publish papers anymore, we even have more time to improve the tools and to make it even better applicable.

Also, my homepage and this blog will remain to exist. It will still be tech-related, cover deployment and other technical aspects that I may run into in the near future. My new job is not only about software deployment, so I will also be working on other aspects.

The future of research in software deployment


As the Mancoosi project has come to an end and because me and my former colleagues working on Nix (including the Nix author) have left the university, deployment research is pretty much dead now, which is a shame, because I think it's very important in practice.

However, I have agreed with my supervisors (and still have the intention!) to publish one journal paper that contains some unpublished stuff from my PhD thesis, in my spare time. Maybe (you'll never know) I have more stuff published when I can find the time and space for it, but I can't give you any time window. :-)


It's not that since I have switched to industry that I'm not interested in research anymore and that I don't want to read or write a paper. I'd still like to be involved in a healthy/doable way, but it's no longer my primary task.

In fact, if academia and industry invest some effort, it can result in fruitful collaborations that give both parties benefits. I wrote a very large blog post about this some time ago, titled 'Software engineering fractions, collaborations and "The System"' that I'd like to encourage both academic and industry people to read.

So to all my academic friends: I'd like to say that if you have a new idea, let me know and make sure that you show that it's relevant to read or even better -- something that I can actually use/try.

Concluding remarks


In this blog post, I have announced that I have moved from academia to industry. The title contains "leaving academia" which sounds very dramatic and a bit like a farewell message. Although I'm no longer employed by the university, I'm actually still located quite close to it, and I have visited my former colleagues twice this week. Furthermore, the technology that we have "invented" is still actively being used and maintained.

I also have the intention to retain the relationship with people from the research world, although I still have to see how I can properly integrate that into my new job description.

Finally, I still have to defend my PhD thesis. Once I have more details about this, I'll announce it here and at several other places of course :-).

An alternative explanation of the Nix package manager

$
0
0
As I have explained in my previous blog post, I started working at a new company as a software architect. One of the things I'm working on is (obviously) deployment.

Recently, I had to give my new employer some background information about my past experience and the Nix package manager. I have frequently presented Nix and related subjects to various kind of audiences. However, I nearly always use a standard explanation recipe, that is somewhat similar to what I have described in an old blog post about the Nix package manager.

This time, I have decided to give an alternative explanation, which I will describe in this blog post.

The Nix package manager


In short: Nix is a package manager, which is a collection of software tools to automate the process of installing, upgrading, configuring, and removing software packages. Nix is different compared to conventional package managers, because it borrows concepts from purely functional programming languages to make deployment reliable, reproducible and efficient. The Nix project has been initiated by Eelco Dolstra as part of his PhD research.

Purely functional programming languages


So, what are purely functional programming languages?

Many programming languages that are in use nowadays support functions. Functions in mathematics are an early inspiration source for "building bricks" in higher level languages.

For example, if we would have sticked ourselves to machine language or assembly, implementing and calling functions is not very obvious -- developers have to follow a function calling convention, that sets the function argument values in the right memory locations, pushes/pops memory addresses onto/from the stack, jumps from one memory location to another etc. For example, the following Intel assembly code fragment, shows how a function invocation can be implemented, using a certain calling convention:


.486
.MODEL FLAT
.CODE
PUBLIC _myFunc
_myFunc PROC
; Subroutine Prologue
push ebp ; Save the old base pointer value.
mov ebp, esp ; Set the new base pointer value.
sub esp, 4 ; Make room for one 4-byte local variable.
push edi ; Save the values of registers that the function
push esi ; will modify. This function uses EDI and ESI.
; (no need to save EBX, EBP, or ESP)

; Subroutine Body
mov eax, [ebp+8] ; Move value of parameter 1 into EAX
mov esi, [ebp+12] ; Move value of parameter 2 into ESI
mov edi, [ebp+16] ; Move value of parameter 3 into EDI

mov [ebp-4], edi ; Move EDI into the local variable
add [ebp-4], esi ; Add ESI into the local variable
add eax, [ebp-4] ; Add the contents of the local variable
; into EAX (final result)

; Subroutine Epilogue
pop esi ; Recover register values
pop edi
mov esp, ebp ; Deallocate local variables
pop ebp ; Restore the caller's base pointer value
ret
_myFunc ENDP
END
I don't expect anyone to understand this code fragment, but it's pretty obvious that something as simple as invoking a function, is very complicated on machine level, as opposed to the following code fragment, written in the C programming language that defines a sum function that adds two integers to each other:


int sum(int a, int b)
{
return a + b;
}

int main()
{
return sum(1, 2);
}

Although many programming languages support functions, these are not the same as functions in mathematics. Consider the following mathematical theorem, known as Leibniz' Principle:

x = y => f(x) = f(y)
The above theorem states that if two function arguments are identical, the result of their function applications are identical as well, something which looks very obvious and makes sense. However, in most programming languages, this is not always the case, such as the C programming language. Consider the following C code example:

int v = 0;

int add(int a)
{
v = v + a;
return v;
}

int main()
{
int p = add(1); /* 1 */
int q = add(1); /* 2 */
}
The add function is called twice in this program with the same function argument. However, each function invocation yields a different result. The reason that this happens is because we have a global variable v that is accessed and overwritten in each function invocation to add.

There are many causes why function invocations with the same parameters yield different results, such as functions returning time-stamps, generating random numbers, performing I/O, accessing global variables. These causes are called side-effects in the functional programming community.

Because C (and many other commonly used programming languages) allow these side-effects to be programmed, they lack referential transparency, meaning that functions cannot be replaced by its value without changing the behaviour of a program.

Purely functional languages are an exception. In purely functional programming languages the result of a function invocation exclusively depends on the definition of the function itself and their parameters, as they do not allow side-effects to be programmed and they exclude destructive updates, such as having a global variable that can be updated. Purely functional programming languages have no variables, but identifiers that are bound to immutable objects. As a consequence, functions in these language support referential transparency.

Another characteristic of functional programming languages is that they often use lazy evaluation, which means that an expression only gets evaluated when it's really needed. A well known purely functional programming language is Haskell.

Because of these properties, purely functional programming languages, such as Haskell, have a number of interesting benefits -- thanks to the fact that functions always yield the same result based on their definition and their arguments, we can cache evaluation results, so that they only have to be executed once, improving efficiency. Laziness offers the advantage that a particular function only has to be evaluated when it's needed, improving efficiency even more. Because of referential transparency and the closures of the functions are known, we can also easily divide function execution over multiple cores/CPUs improving execution speed.

Although purely functional languages have some benefits, they also have some drawbacks. For example, the laziness and caching properties conflict with time predictability, which makes it very hard to develop real-time systems. Moreover, programs written in purely functional languages are much harder to debug.

Purely functional package management


Now I'm trying to draw an analogy to package management: What if we treat the deployment process of a package as a function in programming languages (consisting of steps, such as configuring, building from source, installing and/or upgrading)? In conventional package managers like RPM, such "functions" look very much like functions in imperative programming languages, such as C.

For example, most packages that are in use today, are rarely self contained -- they usually depend on other components that are needed during build-time, such as a compiler, and at run-time, such as libraries. Dependencies can be considered function arguments to a function that deploys a specific package.

However, conventional package managers, have a number of drawbacks. For example, while executing a function (i.e. deploying a package), we are often capable of destructively modifying other packages, by overwriting or removing files belonging to another package. Although it may look obvious now that these properties have drawbacks, it's very common that such operations happen. Especially upgrades are destructive and may result in problems, such as the "DLL hell", because after an upgrade, a program may utilise a library that is incompatible or does not work properly.

Furthermore, files belonging to packages are often stored in global locations, such as /usr/lib on Linux, or C:\WINDOWS\System32 on Windows, allowing packages to find their dependencies even if they are not declared (you could see these implicit dependencies as global variables in a programming language). These factors limit reproducibility. For example, if we would run the same function on another machine, the deployment may fail, because the undeclared dependency is not present.

Because the contents of packages deployed by conventional package managers are often installed in global locations, it's hard to allow multiple versions or variants to safely co-exist, unless the packager has manually checked that there is no file that shares the same name with another package.

The Nix package manager is designed to overcome these drawbacks, by borrowing concepts from purely functional programming languages. In Nix, we describe the build recipes of packages in a domain-specific language called the Nix expression language and every build is modeled after a function that describes the build and a function invocation that builds the package with its required dependencies.

The following example shows a Nix expression that describes how to build the GNU Hello package:

{stdenv, fetchurl}:

stdenv.mkDerivation {
name = "hello-2.6";

src = fetchurl {
url = ftp://ftp.gnu.org/gnu/hello/hello-2.6.tar.gz;
sha256 = "1h6fjkkwr7kxv0rl5l61ya0b49imzfaspy7jk9jas1fil31sjykl";
};

meta = {
homepage = http://www.gnu.org/software/hello/manual/;
license = "GPLv3+";
};
}
The expression shown above defines a function that takes two arguments: the stdenv component is the standard environment providing common UNIX utilities, (such as cat and ls), GNU Make and GCC, fetchurl is a function that downloads a file from an external source.

In the remainder of the function definition, we invoke the stdenv.mkDerivation function that is used to build a package from source, its dependencies (which are passed as function arguments) and a specified build recipe. In our example, we have omitted the build recipe. If no build procedure is specified, the standard Autotools build procedure: ./configure; make; make install is executed.

The earlier code fragment only defines a function, but in order to build a package we need to compose it, by calling it with the right function arguments, which is done in the following expression:

rec {
stdenv = ...;

fetchurl = import ../build-support/fetchurl {
inherit stdenv curl;
};

hello = import ../applications/misc/hello {
inherit stdenv fetchurl;
}

...
}
Here, the hello attribute is bound to the function defined in the earlier expression and invoked with the right function arguments. The dependencies of GNU Hello are also defined and composed in the above expression.

The derivation functions used to build packages as well as the Nix expression language itself are purely functional -- the build result of a package exclusively depends on the function definition and its given arguments, files belonging to another package are never overwritten or removed, dependencies can only be found if they are specified, and we can easily divide derivations over multiple CPUs, cores or machines to improve scalability.

As may become evident now, applying purely functional concepts in package management makes deployment of packages reliable, reproducible, scalable and efficient.

The remaining open question is how Nix achieves these purely functional properties:

  • To ensure that packages cannot be overridden or removed by build functions of other packages, we store the result of each build in a separate location on the filesystem, in directories that are made immutable (by removing write permission bits), so that they cannot be changed. To create, such a unique location, we store component in a store called the Nix store and we use hashing (derived from all inputs to the function, such as their dependencies, sources and build scripts) to generate a unique directory name, e.g. /nix/store/xq2bfcqdsbrmfr8h5ibv7n1qb8xs5s79-openssl-1.0.0c. If we, for example, change any of its build parameters, such as the used compiler, the hash will differ and thus its safe to allow multiple variants to coexist as they never share the same name.
  • By using the Nix store concept, we get another important property "for free" -- because every package variant is stored in a unique location, as opposed to global locations, such as /usr/lib, we have stricter guarantees that dependency specifications are complete, as they cannot be implicitly found. In order to allow a dependency to be found we have to explicitly specify it, for example, by adding it to the PATH environment variable.
  • To reduce the chances on side effects even more, we run build scripts in isolated environments with unprivileged user rights and we can optionally use a chroot() environment to limit access to the host filesystem even more.
  • We have also patched several common UNIX utilities, such as gcc and ld to ignore global locations, such as /usr/lib.

Nix applications


Apart from package management, Nix has been used for a number of other applications:
  • NixOS is a GNU/Linux distribution completely built around the Nix package manager. Apart from the fact that every component (including the Linux kernel and configuration files) are managed by Nix, it is also used to deploy entire system configurations from declarative specifications.
  • Disnix is an extension to Nix developed by me to automatically deploy service-oriented systems composed of distributable components, in networks of machines.
  • Hydra is a continuous build and integration server, built around Nix and using the Nix expression language to define build and test jobs.

Why am I writing this blog post?


As I have explained Nix on my blog before, you may probably wonder why I'm doing it again? It's not that since I have switched jobs, that I wanted to reboot my blog :-)

At my new working spot, my colleagues are not system administrators or packagers, but people with programming language experience, including functional languages, such as Lisp. Therefore, I have decided to give them an alternative explanation, instead of the traditional one.

In the past, I sometimes had some trouble properly explaining the Nix concepts to certain kind of audiences. In many ways I think this alternative explanation is better than the traditional one, albeit it's also a bit longer, but oh well... :-)

In the traditional explanation, I start explaining conventional package managers (and their drawbacks) and showing the Nix store concept and the hash-codes in the path name. Usually when people see this, they initially have a weird feeling. Some even think that we're crazy.

Then we show more stuff, such as how to write Nix expressions specifying how to build packages, increasing the confusion a bit more. Then we have to put some effort in 'justifying' this means. Quite often, after some confusion people see the point and understand some of the benefits. Some of them, however, have already lost interest by then.

Furthermore, we often avoid the term 'purely functional', because it causes extra confusion. In this alternative explanation, I do not omit the term 'purely functional'. The described means (such as the Nix store paths with hash codes) make sense in this explanation, as they are a direct consequence of mapping the goal of purely functional languages to the deployment of packages.

Downsides of this alternative explanation


Although I find this explanation better, there are also some drawbacks. In this explanation, programming languages are the main focus point. Usually our intended audience consists of system administrators, system engineers, packagers and (of course) researchers. Most of them are often not programmers, and have no affinity with programming language research concepts. Especially uncommon languages, such as purely functional ones (including the term: purely functional).

I have especially suffered from this while trying to publish papers in the systems community. They often slam our papers, because "their event is not about programming languages" and we never receive any valuable feedback from them either, even though I have always used the traditional explanation instead of this one.

Conclusion


In this blog post, I have given an alternative explanation of the Nix package manager, using programming languages as a basis concept. In many ways, I find this explanation better than the older/traditional explanation, although it also has its drawbacks. I think properly explaining Nix without any confusion is still an open challenge.

References

Building Android applications with the Nix package manager

$
0
0
Some time ago, I have used the Nix package manager to build and test software packages for AmigaOS, as a fun project. Furthermore, I have announced that I have switched jobs and that I was exploring the mobile device space. This blog post, is a report on the first step in which I show how to build and emulate Android Apps through the Nix package manager. The approach is comparable to what I have done with the AmigaOS emulator. I think it may be good to hear that I'm actively turning research into practice!

Packaging the Android SDK


The first step in automating a build process of Android Apps, is to package the Android SDK as a Nix package, which contains all required utilities for building, packaging and emulating. We must package it (as opposed to referring to an already installed instance), because all build-time dependencies must be handled through Nix in order to achieve reliability and reproducibility.

Unfortunately, the Android SDK is not very trivial to package:

  • The Android SDK from the website is not a source package. Google does not seem to provide any proper source releases, except for obtaining the sources from Git yourself. The downloadable distribution is a zip archive with Java JAR files and a hybrid of native i686 and x86_64 executables. Native executables do not work with Nix out of the box, as they try to lookup their run-time dependencies from global locations, which are not present on NixOS. Therefore, they must be patched using PatchELF.
  • The Android SDK is not self-contained. It requires developers to install a number of add-ons, such as platform tools, platform SDKs, system images, and support libraries, by running:

    $ android update

  • In the normal workflow, these additions are downloaded by the android utility and stored in the same base directory as the SDK, which is an imperative action. This conflicts with the Nix deployment model, as components are made immutable after they have been built. Moreover, these additions must be installed non-interactively.

Android SDK base package


I have packaged the Android SDK base package in Nix (which is obtained from the Android SDK page) by unzipping the zip distribution and by moving the resulting directory into the Nix store. Then I have patched a number of executables, scripts and libraries to allow them to work from the Nix store.

As explained earlier, we cannot run ELF executables out of the box on NixOS, as Nix has no global directories, such as /usr/lib, in which executables often look for their dependencies. Moreover, the dynamic linker also resides in a different location.

First, we have to patch executables to provide the correct path to the dynamic linker (which is an impurity and does not reside in /lib). Then by running ldd on the ELF executables, we can see that all of them require libstdc++ (32-bit):


$ ldd ./emulator-x86
linux-gate.so.1 => (0xf76e4000)
libdl.so.2 => /nix/store/7dvylm5crlc0sfafcc0n46mb5ch67q0j-glibc-2.13/lib/libdl.so.2 (0xf76de000)
libpthread.so.0 => /nix/store/7dvylm5crlc0sfafcc0n46mb5ch67q0j-glibc-2.13/lib/libpthread.so.0 (0xf76c4000)
librt.so.1 => /nix/store/7dvylm5crlc0sfafcc0n46mb5ch67q0j-glibc-2.13/lib/librt.so.1 (0xf76af000)
libstdc++.so.6 => not found
libm.so.6 => /nix/store/7dvylm5crlc0sfafcc0n46mb5ch67q0j-glibc-2.13/lib/libm.so.6 (0xf7689000)
libutil.so.1 => /nix/store/7dvylm5crlc0sfafcc0n46mb5ch67q0j-glibc-2.13/lib/libutil.so.1 (0xf7684000)
libgcc_s.so.1 => not found
libc.so.6 => /nix/store/7dvylm5crlc0sfafcc0n46mb5ch67q0j-glibc-2.13/lib/libc.so.6 (0xf7521000)
/nix/store/7dvylm5crlc0sfafcc0n46mb5ch67q0j-glibc-2.13/lib/ld-linux.so.2 (0xf76e5000)

In order to allow these executables to find a particular library, we have to add its full path (provided by evaluating a derivation) to the RPATH header of the ELF executable. The following build commands will patch most of the utilities:

cd tools

for i in dmtracedump emulator emulator-arm emulator-x86 hprof-conv \
mksdcard sqlite3
do
patchelf --set-interpreter ${stdenv.gcc.libc}/lib/ld-linux.so.2 $i
patchelf --set-rpath ${stdenv.gcc.gcc}/lib $i
done
Two other tools apparently do zip compression/decompression and require zlib in addition to libstdc++:

for i in etc1tool zipalign
do
patchelf --set-interpreter ${stdenv.gcc.libc}/lib/ld-linux.so.2 $i
patchelf --set-rpath ${stdenv.gcc.gcc}/lib:${zlib}/lib $i
done

A shared library used by the monitor (lib/monitor-x86/libcairo-swt.so) requires many more libraries, which are mostly related to the GTK+ framework.

In addition to ELF binaries, we also have a number of shell scripts that start Java programs. They have a shebang refering to the bash shell residing at /bin/bash, which does not exist on NixOS. By running the shebangfix tool this line gets replaced to refer to the right Nix store path of bash:


for i in ddms draw9patch monkeyrunner monitor lint traceview
do
shebangfix $i
done

After performing these patching steps, there are still a bunch of utilities not properly functioning, such as the emulator, showing:

SDL init failure, reason is: No available video device
I have used strace to check what's going on:


$ strace -f ./emulator
...
rt_sigaction(SIGINT, {SIG_DFL, [INT], SA_RESTART}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL, [QUIT], SA_RESTART}, {SIG_DFL, [], 0}, 8) = 0
futex(0xfffffffff7705064, FUTEX_WAKE_PRIVATE, 2147483647) = 0
open("./lib/tls/i686/sse2/libX11.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./lib/tls/i686/libX11.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./lib/tls/sse2/libX11.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./lib/tls/libX11.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./lib/i686/sse2/libX11.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./lib/i686/libX11.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./lib/sse2/libX11.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("./lib/libX11.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
...
open("/nix/store/cy8rl8h4yp2j3h8987vkklg328q3wmjz-gcc-4.6.3/lib/libXext.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/nix/store/7dvylm5crlc0sfafcc0n46mb5ch67q0j-glibc-2.13/lib/libXext.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
...
open("/nix/store/cy8rl8h4yp2j3h8987vkklg328q3wmjz-gcc-4.6.3/lib/libXrandr.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/nix/store/7dvylm5crlc0sfafcc0n46mb5ch67q0j-glibc-2.13/lib/libXrandr.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, "SDL init failure, reason is: No "..., 55SDL init failure, reason is: No available video device
) = 55
unlink("/home/sander/.android/avd/foo.avd/hardware-qemu.ini.lock") = 0
exit_group(1)

Apparently these utilities also open a number of libraries dynamically, such as the ones belonging to the X Window System, which are not in the executable's RPATH. I have fixed this by wrapping the paths to these additional libraries in a shell script that sets the LD_LIBRARY_PATH environment variable and then executes the real executable, so that these can be found:


for i in emulator emulator-arm emulator-x86
do
wrapProgram `pwd`/$i \
--prefix LD_LIBRARY_PATH : `pwd`/lib:${libX11}/lib:\
${libxcb}/lib:${libXau}/lib:${libXdmcp}/lib:\
${libXext}/lib
done

Supporting plugins and optional packages


As explained earlier, the Android SDK is not self contained and provides many additions and optional packages, depending on what classes of devices a developer wants to support and what features he wants to provide. Apparently, there is no web page to easily download these additions from. Moreover, we do not need all of them. Downloading all possible additions require developers to download many gigabytes of data.

However, running:


$ android list sdk

reveals some interesting information:


Fetching https://dl-ssl.google.com/android/repository/addons_list-2.xml
Validate XML
Parse XML
Fetched Add-ons List successfully
Refresh Sources
Fetching URL: https://dl-ssl.google.com/android/repository/repository-7.xml
Validate XML: https://dl-ssl.google.com/android/repository/repository-7.xml
Parse XML: https://dl-ssl.google.com/android/repository/repository-7.xml
Fetching URL: https://dl-ssl.google.com/android/repository/addon.xml
Validate XML: https://dl-ssl.google.com/android/repository/addon.xml
Parse XML: https://dl-ssl.google.com/android/repository/addon.xml

The output shows that the Android SDK fetches a collection of XML files a number of URLs that provide package information. I have used these XML files to package all the additions I care about in separate Nix expressions.

Platform tools


One important addition that's not in the base package are the platform tools, which contains the Android debugger and a number of related utilities. The platform-tools' zip distribution is defined in the repository-7.xml file.

Packaging the platform tools in very straight forward. It must be unzipped and a number of native ELF executables need to be patched, such as adb. Fortunately, none of them uses dynamically loaded libraries. There is one shell script: dx that requires a shebang fix.

Finally, the platform tools must be accessible from the platform-tools directory from the Android SDK basedir. We can easily solve this by creating a symlink from the Android SDK base package to the platform tools package.

Platform SDKs and system images


Apart from the basic tools and platform tools, we have to be able to actually develop Android Apps. Android Apps are developed for a wide range of devices and operating system versions, ranging from the classic Android 1.5 OS to the recent Android 4.2 OS.

In order to be able to build an Android app for a particular device (or a class of devices), we require the appropriate Android SDK version for that particular Android version. Besides building, we also want to use the emulator for testing. The emulator requires the right system image for a particular Android OS version.

It would be very costly to have all Android versions supported by default, which requires developers to download a lot of data, while they often only need a small subset of it. Therefore, we want to package every SDK and system image separately.

Fortunately, the repository-7.xml XML file contains all the information that we need to do that. For example, each platform SDK is defined in an XML element, such as:


<sdk:sdk-repository ...>
<sdk:platform>
<sdk:version>2.2</sdk:version>
<sdk:api-level>8</sdk:api-level>
<sdk:codename/>
<sdk:revision>03</sdk:revision>
<sdk:min-tools-rev>
<sdk:major>8</sdk:major>
</sdk:min-tools-rev>
<sdk:description>Android SDK Platform 2.2_r3</sdk:description>
<sdk:desc-url>http://developer.android.com/sdk/</sdk:desc-url>
<sdk:archives>
<sdk:archive arch="any" os="any">
<sdk:size>74652366</sdk:size>
<sdk:checksum type="sha1">231262c63eefdff8...</sdk:checksum>
<sdk:url>android-2.2_r03-linux.zip</sdk:url>
</sdk:archive>
</sdk:archives>
<sdk:layoutlib>
<sdk:api>4</sdk:api>
</sdk:layoutlib>
</sdk:platform>

...
</sdk:sdk-repository>
The given XML elements can be transformed into a Nix expression, using XSL in a straight forward manner:


let buildPlatform = ...
in
{
...

platform_8 = buildPlatform {
name = "android-platform-2.2";
src = fetchurl {
url =
https://dl-ssl.google.com/android/repository/android-2.2_r03-linux.zip;
sha1 = "231262c63eefdff8fd0386e9ccfefeb27a8f9202";
};
meta = {
description = "Android SDK Platform 2.2_r3";
url = http://developer.android.com/sdk/;
};
};

...
}

The resulting Nix expression is an attribute set, in which every attribute refers to a package containing a platform SDK.

The buildPlatform function simply unzips the zip file and moves the contents into the Nix store. The <sdk:api-level> is an important element -- it's a unique version number that the Android SDK uses to make a distinction between various Android operating systems and is also used to make the attribute names in the above attribute set unique. As we will see later, we can use the API level number and this naming convention to relate optional components to a particular Android OS version.

To make a specific platform SDK available to developers, we must symlink it into the platforms/android-<api-level> directory of the Android base package.

For the system images, a similar approach is used that generates an attribute set in which each attribute refers to a system image package. Here, also a <sdk:api-level> element is defined, that we can use to relate the system image to a particular Android OS version. A system image can be made available by creating a symlink in the system-images/android-<api-level>.

Other additions


In addition to the platform SDKs and system images, there are many more optional additions, which are defined in the addon.xml file. For example, to allow Android Apps to use APIs, such as Google Maps, we need to make these package available as well. The Google API packages are defined in a similar manner in the XML file as the platform SDKs, with an api-level identifier and must be symlinked in into the addons/addon-google_apis-<api-level> directory of the Android SDK package.

There is also the support library that exposes certain newer functionality to older Android OSes and some utility APIs. The support library can be made available by symlinking it into support/ of the Android SDK base package.

Building Android applications


So far, I have described how we can package the Android SDK and its (optional) additions in Nix. How can we use this to automatically build Android Apps through the Nix package manager?

The first important aspect is that the Android command-line utility must be used to create an Android project, as opposed to using the Eclipse IDE. In addition to a basic project layout, the command-line utility produces an Apache Ant build file, that can be used to automatically build the project from the command line. An example of this is:


android create project --target android-8 --name MyFirstApp \
--path /home/sander/MyFirstApp --activity MainActivity \
--package com.example.myfirstapp

The above command-line instruction creates a new project targetting the Android API-level 8 (which corresponds to the Android 2.2 platform SDK, as shown earlier), with the name MyFirstApp, having a MainActivity and stores the code in the com.example.myfirstapp Java package.

By running the following command line instruction, an Android application can be built, which produces an APK archive (a zip archive containing all the files belonging to an App) signed with the debugger key:

$ ant debug
To create releases for production use, we also need to sign an APK with a custom key. A key can be created by running keytool, part of the Java SDK:

$ keytool --genkeypair --alias sander
If I add the following lines to the ant.properties file in the project directory, we can automatically sign the APK with a custom key:

key.store=/home/sander/.keystore
key.alias=sander
key.store.password=foobar
key.alias.password=foobar
By running the following command-line instruction:

$ ant release
A signed APK for release is produced.

I have encapsulated all the previous aspects into a Nix function, named: androidenv.buildApp, which can be used to conveniently build Android apps from source code and a number of specified options. The following code fragment shows an example invocation, building the trivial Android example application, that I have implemented to test this:

{androidenv}:

androidenv.buildApp {
name = "MyFirstApp";
src = ../../src/myfirstapp;
platformVersions = [ "8" ];
useGoogleAPIs = true;

release = true;
keyStore = /home/sander/keystore;
keyAlias = "sander";
keyStorePassword = "foobar";
keyAliasPassword = "foobar";
}
The expression above looks similar to an ordinary expression -- it defines a function that requires androidenv containing all Android related properties. In the remainder of the function, we make a function call to androidenv.buildApp, which can be used to build an App. As function arguments, we provide a name that ends up in the Nix store, a reference to the source code (which resides on the local filesystem), the API-level which we want to target (as we have seen earlier, API-level 8 corresponds to Android OS 2.2) and whether we want to use the Google APIs.

In this example, we have also enabled key signing. If the release parameter is omitted (it is false by default), then the remaining arguments are not required and the resulting APK is signed with the debug key. In our example, we provide the location, alias and keystore passwords that we have created with keytool, so that signing can be done automatically.

As with ordinary expressions, we also have to compose an Android package:

rec {
androidenv = import ./androidenv { ... };

myfirstapp = import ./myfirstapp {
inherit androidenv;
};
...
}
The above fragment contains a reference to the Android build infrastructure and invokes the earlier build expression with the given androidenv argument. The App can be built by calling (pkgs.nix corresponds to the above code fragement):

$ nix-build pkgs.nix -A myfirstapp
/nix/store/11fz1yxx33k9f9ail53cc1n65r1hhzlg-MyFirstApp
$ ls result/
MyFirstApp-release.apk
By running the above command-line instruction the complete build process is performed. The Android SDK is downloaded and installed, all the required platform SDKs and system images are installed, the App itself is built and signed, and a Nix component is produced containing the signed APK that is ready to be released.

Our build function composes the Android SDK with its optional features using the function parameters, so that only the additions that we need are downloaded and installed, ensuring reliability, reproducibility and efficiency. It would be a waste of time and disk space to download all possible additions, of course. :-)

Emulating Android apps


Besides building Android apps, it is also desirable to test them using the Android emulator. To run the emulator, we must first create an AVD (Android Virtual Device). On the command-line this can be done by:

$ android create avd -n device -t android-8
The above instruction generates an AVD named device targeting the Android API-level 8 (Android 2.2 OS). If we want to use the Google APIs, then we have to pick a different target, which is named: "Google Inc.:Google APIs:8", if which the integer represents the API-level.

Then we have to start the emulator representing the generated AVD:

$ emulator -avd device -no-boot-anim -port 5554
The above command-line instruction starts the emulator running our AVD, without displaying a boot animation. The debugger interface uses TCP port 5554. (As a sidenote, TCP ports are an impurity inside Nix expressions and it seems that the emulator cannot use Unix domain sockets. In order to cope with this, I wrote a procedure that scans for a free TCP port in the even number range between 5554-5584, by grepping the output of: adb devices).

When we start the emulator, we have to wait until its booted so that we can install our generated APK. I have discovered that the Android debugger can wait until a device it has reached it's device state, so that the Android debugger is ready to talk to the emulator. This can be done by the following command-line instruction (the -s parameter provides the serial for our recently spawned emulator instance, which is composed of the string 'emulator' and the assigned port number shown earlier):

$ adb -s emulator-5554 wait-for-device
Although the device state has been reached, the device is not guaranteed to be booted. By running getprop command-line tool remotely on the device, we can query various device properties. When the device has been fully booted, the dev.bootcomplete should be 1, e.g.:

$ adb -s emulator-5554 shell getprop dev.bootcomplete
1
Then we should be able to install our APK through the debugger, and should we be able to pick it from the application menu on the device:

$ adb -s emulator-5554 install result/MyFirstApp-release.apk
Finally, we must launch the application, which is done by launching the start activity of an App. We can do this automatically, by remotely calling am that creates an intent to launch the start activity (MainActivity in the example that we have used) from our App package (com.example.my.first.app):

$ adb -s emulator-5554 shell am start -a android.intent.action.MAIN \
-n com.example.my.first.app/.MainActivity
Because we always have to compose a SDK having all our desired additions and due to the fact that we have to execute a lot of steps, I have decided to conveniently automate this procedure. I have developed a function called: androidenv.emulateApp encapsulating these. The following Nix expression shows how it can be invoked:

{androidenv, myfirstapp}:

androidenv.emulateApp {
name = "MyFirstApp";
app = myfirstapp;
platformVersion = "16";
useGoogleAPIs = false;
package = "com.example.my.first.app";
activity = "MainActivity";
}
The above expression is a function that takes two parameters: androidenv is the Android build infrastructure, myfirstapp refers to the build function of the example application, I have shown earlier.

In the remainder of the expression, we invoke the androidenv.emulateApp function that generates a script that automatically instantiates and launches the emulator and finally deploys our APK in it automatically. Here, we also have to specify which app to use, what API-level we want to target (in this example we target API-level 16, which corresponds to Android 4.1) and whether we want to use the Google APIs). The API-level used for emulation may differ from the level we used for building (i.e. it makes sense to test older Apps on newer devices). Finally, we specify the package name and the name of the main activity, so that we can automatically start the App.

By evaluating this expression and executing the resulting script, an emulator is launched with our example app deployed in it, and it's started automatically:

$ nix-build pkgs.nix -A emulate_myfirstapp
./result/bin/run-test-emulator

The above screenshot shows that it works :-)

Deploying Android apps on real devices


I guess the remaining question is how to deploy Android apps on real devices. After building the App through Nix, the following command-line instruction suffices for me, if I attach my phone to the USB port and I enable debugging on my phone:

$ adb -d install result/MyFirstApp-release.apk
This is the result:


It probably does not look that exciting, but it works!

Conclusion


In this (lengthy, I'm sorry :P) blog post, I have packaged the Android SDK in Nix and a large collection of its additions. Furthermore, I have implemented two Nix functions, that may come in handy for Android App development:

  • androidenv.buildApp builds an Android App for a particular class of Android devices.
  • androidenv.emulateApp generates a script that launches a particular emulator instance and automatically starts an App in it.

These functions take care of almost the entire deployment process of Android Apps hiding most of its complexity, including all its dependencies and (optional) additions. Due to the unique advantages of Nix, we can safely use multiple variants of SDKs and their libraries next to each other, all dependencies are always guaranteed to be included (if they are specified), we can use laziness and function composition to ensure that only the required dependencies are used (which improves efficiency), and we can easily parallelise builds thanks to the purely functional nature of Nix. Furthermore, this function can also be used in conjunction with Hydra -- the Nix-based continuous build and integration server to continuously assess the state of Android App code.

The only nasty detail is that the emulator and debugger use TCP ports to communicate with each other, which is an impurity. I have implemented some sort of a work around, but it's not very elegant and has various drawbacks. As far as I know, there is no way to use Unix domain sockets.

I'd like to thank my new employer: Conference Compass, for giving me the space to develop this and taking interest in the deployment technology I was involved in as a researcher. (hmm 'was'? I'm still involved, and this still is research in some way :-) )

Availability


The Android build infrastructure is part of Nixpkgs, available under the MIT license. The androidenv component can be used by including the Nixpkgs top-level expression. The trivial example case and its composition expression (containing the myfirstapp and emulate_myfirstapp attributes) can be obtained from my Nix Android tests GitHub page.

On Nix and GNU Guix

$
0
0

Quite recently, the GNU project has announced Guix, a new package manager for the GNU system. Guix is described on their website as:

GNU Guix is a purely functional package manager, and associated free software distribution, for the GNU system. In addition to standard package management features, Guix supports transactional upgrades and roll-backs, unprivileged package management, per-user profiles, and garbage collection.

The announcement has apparently attracted quite a lot of attention and it has been in the news quite a lot, such as on Linux Weekly News, Phoronix and Reddit. As my frequent readers may probably notice, this description looks very much like the Nix package manager.

GNU Guix


In fact, Guix is not a new package package manager -- it's using several crucial components of the Nix package manager and gains the mentioned unique interesting properties, such as transactional upgrades, from these.

What Guix basically provides is a new language front-end. The Nix package manager has its own domain-specific language (DSL), called the Nix expression language, to specify how packages can be built from source code and its required dependencies. I have shown many examples of Nix expressions in earlier blog posts. The Nix expression language is an external DSL, meaning that it has a custom syntax and parser to process the language.

Guix provides a different front-end using GNU Guile -- a Scheme programming language interpreter, which is blessed as the official extension language in the GNU project and embedded in a number free software programs, such as TeXmacs and Lilypond. Guix provides an internal DSL (or embedded DSL), meaning that it uses a general purpose host language (in this case Scheme) and its features to implement a DSL.

Furthermore, the Guix repository contains a small set of package specifications (comparable to Nixpkgs) that can be used to deploy a small subset of a system. The developers have the intention to allow a full GNU system to be deployed from these at some point in the future.

A comparison of package specifications


So how does the way packages are specified in Nix and Guix differ to each other? Using the Nix package manager, a package such as GNU cpio, is specified as follows:

{stdenv, fetchurl}:

stdenv.mkDerivation {
name = "cpio-2.11";

src = fetchurl {
url = mirror://gnu/cpio/cpio-2.11.tar.bz2;
sha256 = "1gavgpzqwgkpagjxw72xgxz52y1ifgz0ckqh8g7cckz7jvyhp0mv";
};

patches = [ ./cpio-gets-undeclared.patch ];

meta = {
homepage = http://www.gnu.org/software/cpio/;
longDescription = ''
GNU cpio copies ...
'';
license = "GPLv3+";
};
}

The above code fragment defines a function in the Nix expression language taking 2 arguments: stdenv is a component providing a collection of standard UNIX utilities and build tools, such as: cat, ls, gcc and make. fetchurl is used to download a file from an external source.

In the remainder of the expression, we do a function invocation to stdenv.mkDerivation, which is the Nix-way of describing a package build operation. As function arguments, we provide a package name, the source code (src which is bound to a function that fetches the tarball from a GNU mirror), a patch that fixes a certain issue and some build instructions. If the build instructions are omitted (which is the case in our example), the standard GNU Autotools build procedure is executed, i.e.: ./configure; make; make install.

The expression shown earlier merely defines a function specifying how to build a package, but does not provide the exact versions or variants of the dependencies that we should use to build it. Therefore we must also compose the package, by calling the function with the required function arguments. In Nix, we do this in a composition expression, containing an attribute set in which each attribute name is a package, while its value is a function invocation, importing package expressions and by providing their dependencies, which are defined in the same expression:

rec {
stdenv = ...

fetchurl = import ../pkgs/build-support/fetchurl {
...
};

cpio = import ../pkgs/tools/archivers/cpio {
inherit stdenv fetchurl;
};

...
}
In the above expression, the cpio package expression (shown earlier) is imported and called with its required function arguments that provide a particular stdenv and fetchurl instance. By running the following command-line instruction and by providing the above expression as a parameter, cpio can be built. Its result is stored in isolation in the Nix store:

$ nix-build all-packages.nix -A cpio
/nix/store/pl12qa4q1z...-cpio-2.11

In Guix, the GNU cpio package is specified as follows:


(define-module (distro packages cpio)
#:use-module (distro)
#:use-module (guix packages)
#:use-module (guix download)
#:use-module (guix build-system gnu))

(define-public cpio
(package
(name "cpio")
(version "2.11")
(source
(origin
(method url-fetch)
(uri (string-append "mirror://gnu/cpio/cpio-"
version ".tar.bz2"))
(sha256
(base32
"1gavgpzqwgkpagjxw72xgxz52y1ifgz0ckqh8g7cckz7jvyhp0mv"))))
(build-system gnu-build-system)
(arguments
`(#:patches (list (assoc-ref %build-inputs
"patch/gets"))))
(inputs
`(("patch/gets" ,(search-patch "cpio-gets-undeclared.patch"))))
(home-page "https://www.gnu.org/software/cpio/")
(synopsis
"A program to create or extract from cpio archives")
(description
"GNU Cpio copies ...")
(license "GPLv3+")))

As can be seen, the above code fragment defines a package in the Scheme programming language. The above code fragment defines a module (representing a single package), that depends on a collection of modules providing its build-time dependencies, such as all the other packages that are defined in the Guix repository, a module responsible for downloading files from external location and a module providing build instructions.

In the remainder of code fragment, a procedure is defined capturing the properties of the package (in this case: cpio). As can be observed, the information captured in this procedure is quite similar to the Nix expression, such as the package name, the external location from which the source code should be obtained, and the patch that fixes an issue. The build-system parameter says that the standard GNU autotools build procedure (./configure; make; make install) should be executed.

To my knowledge, the composition of the package is also done in the same specification (because it refers to modules defining package compositions, instead of a function, which arguments should be set elsewhere), as opposed to Nix, in which we typically split the build function and its composition.

GNU cpio can be built using Guix by running:

$ guix-build hello
/nix/store/pl12qa4q1z...-cpio-2.11

The above command connects to the nix-worker process (a daemon part of Nix, capable of arranging multi-user builds), defines a Nix derivation from the procedure described in the earlier code fragment and finally builds the derivation, resulting in a Nix component containing cpio, which is (like the ordinary package manager) stored in isolation in the Nix store and achieving the same purely functional deployment properties.

Possible advantages of Guix over Nix


So you may probably wonder why Guix has been developed and what (potential) benefits it gives over Nix. The presentation given by Ludovic Courtès at the GNU Hackers Meeting, lists the following advantages:

  • because it rocks!
  • because it's GNU!
  • it has a compiler, Unicode, gettext, libraries, etc.
  • it supports embedded DSLs via macros
  • can be used both for composition and build scripts

To be quite honest, I see some potential interesting advantages in these, but they are not entirely clear to me. The first two points are subjectively defined and should not be taken seriously I guess. I assume that it rocks, because it's cool to show that something can be done and I think it's GNU (probably) because it's using the GNU Guile language which has been used as an extension language for a number of GNU packages or due to the fact that Guix has been blessed as an official GNU project.

The third point lists some potential advantages, that are related to a number of potential interesting features of the host language (GNU Guile) that can be (re)used, which in an external DSL have to be developed from scratch, taking significantly more effort. This observation corresponds to one of the advantages described by others that internal DSLs have over external DSLs -- less time to invest in developing a language and host language features that can be reused.

The fourth point (supporting embedded DSLs) is also a bit unclear to me, why this is an advantage. Yes, I've seen macros that implement stuff, such as the standard GNU Autotools build procedure, but I'm not sure in what respect this is an advantage over the Nix expression language.

The fifth point refers to the fact that Scheme can be used for both writing package specifications and their build instructions, whereas in Nix, we typically use embedded strings containing shell code performing build steps. I'm not entirely sure what Guix does different (apart from using macros) and in what respect it offers benefits compared to Nix? Are strings statically checked? automatically escaped? I haven't seen the details or I may have missed something.

My thoughts


First of all, I'd like to point out that I don't disapprove Guix. First, Nix is free software and freedom 1 says:

The freedom to study how the program works, and change it so it does your computing as you wish (freedom 1). Access to the source code is a precondition for this.
So for me, it's perfectly fine that the GNU project scratches their itches. I also think Guix is interesting for the following reasons:

  • It's interesting to compare an internal vs external DSL approach in deployment. Although Ludovic has listed several potential benefits, I still don't see that these are proven yet by Guix. Some questions that came into my mind are:
    • Does compiling Guix specifications give any benefits, let's say in performance or in a different aspect?
    • Why do we need modules, such as gettext, for package specifications?
    • Can Guix expressions be better debugged than Nix expressions? (I know that the Nix expression language is a lazy purely functional language and that errors are very hard to debug).
    • I know that by using an internal DSL the language is extensible, but for what purposes is this useful and what can you do it what Nix currently cannot?

      On the other hand, I think the Nix expression language is also extensible in the sense that you can call any process from a derivation function (implementing an operation) and encapsulate derivation into a function with a nice interface. For example, I have used this for Disnix to integrate deployment planning algorithms. Maybe there are different kind of extensions or more efficient integration patterns possible with Guix? So far, I haven't seen anything concrete yet.
  • I also find the integration aspect with Nix interesting. I have seen many language/environment specific package managers, for e.g. Perl, Python, Eclipse and they all solve deployment issues in their own way. Furthermore, they do not offer all the features we care about, such as transactional upgrades and reproducible builds. By making it possible to integrate language specific package managers with Nix, we can remove this burden/annoyance.
  • If GNU packages can be easily packaged in a functional way, it will also make the lives of Nix packagers easier, as we don't have to implement any hacks/workarounds anymore and we can (semi-)automatically convert Nix and Guix expressions.
  • It's also good to have a critical look at the foundations Nix/Nixpkgs, such as the bootstrap. In Guix, this entire process is reimplemented that may yield useful techniques/lessons that we can apply in Nix as well.
  • To have Nix and the purely functional deployment model is the media always good, as we want to break conventional thoughts/ideas.

Apart from these potential benefits and the fact that Guix is far from finished, I currently see no reason to recommend Guix over Nix, or to see any reason using it myself. To me, it looks like a nice experiment, but I still have to be convinced that it adds value, apart from integration with language-specific package managers. The advantages of using an internal DSL approach still have to be proven.

On the other hand, I also think that external DSLs (which the Nix expression language is) have benefits over internal DSLs:

  • A more concise syntax, which is shorter and better comprehensible. However, I have to admit that I'm a bit biased on this, because I only have little hands-on experience with the Scheme programming language and quite some experience with the Nix expression language.
  • Better static consistency checking. External DSLs can produce more understandable error messages, whereas host language "abusement" may create all kinds of complex structures significantly making error reports much more complicated and difficult to grasp.

    Furthermore in an embedded DSL, you can also use the host language to do some unintended operations. For example, we could use Scheme to imperatively modify a variable, that is used by another package, affecting reproducibility (although the build of a derivation itself is pure, thanks to Nix). A packager has to manually take care that no side-effects are specified, while the Nix expression language prevents these side-effects to be programmed.

    Again, I have not done any comparisons with Nix and Guix, but I have worked several years in a research group (which besides me, includes Eelco Dolstra, the author of Nix) in which external DSLs are investigated, such as WebDSL, a domain-specific language for web applications.

    My former colleague Zef Hemel (along with a few others) wrote a series of blog posts covering issues with internal DSLs (one of them: 'When rails fails', covering some problems with internal DSLs in the Ruby programming language, has raised quite some (controversial) attention) and a paper titled: 'Static consistency checking of web applications with WebDSL' reporting on this matter.
  • External DSLs have often smaller dependencies. If an internal DSL (embedded in a host language) is used in a tool, it often needs the entire host language runtime, which for some programming languages is quite big, while we only need a small subset of it. One of the questions we have encountered frequently in the Nix community, is why we didn't use Haskell (a lazy purely functional language) to specify package configurations in Nix. One of the reasons is that the Haskell runtime is quite big and has many (optional) dependencies.

I have also observed a few other things in Guix:

  • The Nix expression language is a lazy purely functional language, whereas Guix uses eager evaluation, although the derivation files that are produced and built are still processed lazily by the Nix worker. In Nix, laziness offers various benefits, such as that only the desired packages and its required dependencies are built, while everything we don't need is not, improving efficiency. In Guix, other means have to be used to achieve this goal and I'm not sure if Guix has a better approach.
  • Guix's license is GPLv3 including the package descriptions, whereas Nix's license is LGPLv2.1 and the Nixpkgs is MIT licensed. Guix has a stronger copyleft than Nix. I don't want to have a debate about these licenses and the copyleft here, but for more information I'd like to redirect readers to an earlier blog post about free and open-source software and to form an opinion on this.

Concluding remarks


In this blog post I have covered GNU Guix, a package manager recently announced by the GNU project, which uses Nix under the roof to achieve its desired non-functional properties, such as transactional upgrades and reproducible builds. Guix differs from Nix, because it offers an internal DSL using Scheme (through GNU Guile), instead of the Nix expression language, an external DSL.

The main reason why I wrote this blog post is that GNU Guix has appeared on many news sites, which often copy details from each other. They do not always check facts, but just copy what others are saying. These news messages may sometimes suggest that GNU Guix is something entirely new and providing revolutionary new features to make deployment reliable and reproducible.

Moreover, they may suggest that these features are exclusive to GNU Guix, as they only mention Nix briefly (or sometimes not at all). These facts are not true -- these properties were already in Nix and Nix has been designed with these goals in mind. Currently, GNU Guix is merely a front-end to Nix and inherits these properties because of that. At some in the future this may give people the impression that "Nix is something like GNU Guix", which should be exactly the opposite. Furthermore, I'm a researcher and I have to look at stuff critically.

Finally, I'd like to stress out that there is no schism in the Nix project or that I have anything against the Guix effort, although I'm speaking on behalf of myself and not the entire Nix community. Furthermore, Nix is mentioned on the GNU Guix website and covered more in detail in the GNU Guix presentation and README.

Although I find it an interesting experiment, I don't see any benefits yet in using Guile over the Nix expression language. I have raised many questions in this blog post and its usefulness still has to be proven, in my opinion.

Viewing all 159 articles
Browse latest View live