A small story about outsourcing

A true story about why it isn’t always cheaper to produce more cost-effective. And a story about a process that wasn’t tailored around human requirements.

Let me tell you a story about human labor and automization, cost efficiency and the result of local optimization. The story itself is true, but nearly all details are changed to protect the innocent.

An opportunity

Once, there was a company that produced sensoric equipment with a large portion of electronic circuitry. The whole device was manufactured at the company’s main factory and admired for its outstanding rigidity. Then, one day, the opportunity offered itself to outsource the assembly of the electronics to a country in the asian region. The company boss immediately recognized the business value in this change: The same parts would be produced by the company, shipped to the asian contract manufacturerer, assembled and promptly returned. Then, the company’s engineers will provide the firmware and software for the final product. By outsourcing the most generic step in the production line, the production costs could be lowered significantly.

A detail

There is one little detail that needs to be told: The sensors relied on some very specific and fragile parts only the company itself could produce. These parts were especially sensible to the atmosphere they were assembled in. A very important aspect of the production process was a special purpose machine that could assemble the parts while sustaining the necessary gas mixture and pressure. Upon closer inspection, one could say that the essence of this product’s secret ingredience weren’t the parts itself, but the specifically tailored production process.

The special purpose machine had to be transferred to the contract manufacturer in asia, otherwise, the sensors could not be assembled. This was a minor inconvenience compared to the large profits that could be realized once the outsourcing was completed.

A success

The machine was transported to the contractor, installed and tested. A special crew of workers of the contractor’s staff was trained to operate the machine properly and within the necessary conditions. After a while, the production line began its work. The first sensors assembled offshore returned home. They all worked as intended. The local engineers couldn’t tell the difference but by looking at the serial number. The company management was pleased, the profitability was increased.

A failure

Everything went well for a while. Then, the local engineers noticed a slightly higher number of faulty sensors. Not long after, the quality assurance reported decreasing performance numbers of the devices. The rigidity of the device, the unique selling point, slowly deteriorated. The company management was worried and established a task force to indentify the root cause for this change to the worse.

A mystery

The task force inspected the reported problems and couldn’t make much sense of the numbers. It wasn’t a problem of whole faulty batches (indicating incidents like transport damage), but also not of individual faulty pieces. Instead, they found that if a piece was faulty, the next few pieces from that series were also faulty. Then, there were long intervals with perfectly good pieces until another group of clearly faulty pieces occurred. Something had to go wrong during the assembly process at the contractor.

A revelation

When the task force arrived in the contractor’s factory and inspected the special purpose machine, they found that the atmosphere regulator was damaged. This automatic part of the machine takes care of the mixture and pressure of the gas in the machine during operation and keeps it in the necessary range by applying or draining specific gas. The contractor didn’t bother to replace the rather expensive part when cheap human labor is readily available. They had hired a worker to perform the atmosphere regulation manually. Some lowly paid worker had to watch the pressure numbers and provide more or less gas, just as needed. This was nearly as good as the automatic regulation and still good enough to produce quality devices.

An explanation

But, the contractor only hired one worker per shift. This worker had to go to the toilet sometimes during the work day. When he was away from the machine, it went along unregulated, soon to be misadjusted to the point of only producing junk. Once the worker returned, he would balance the numbers and bring the machine in the OK state again. This situation occurred periodically, but not too often to taint whole batches. Only during his absence, the series of faulty devices would be produced.

A conclusion

I don’t want to add much moral to this story. Perhaps one thing should be considered when recapitulating: Both the company and the contractor “optimized” their costs locally by making cost efficient decisions that turned out to be expensive in the long run. The company chose between expensive, but controlled local production and cheap outsourced assembly, arguably the most delicate step in the whole production process. The contractor chose between a high one-time investment in an automatism and the low ongoing cost of cheap human labor. Both decisions are comprehensible on their own, but lead to a situation that would never have occurred in the original setting.

A short story about priorities

When you mix your own priorities with the ones of your customers, embarrassing things might happen.

Before I can tell you the story, I have to add this disclaimer: The story is true, but it wasn’t us. To protect the identities, I’ve changed nearly all the details, hopefully without watering down the essence of the story.

The assignment

A few years ago, when developing software for mobile devices wasn’t as ordinary as it is today, a freelance developer got a call from a loyal customer. He should develop a little web application that could also be used on a smartphone. The functionality of the application was minimal: Show a neat image containing two buttons to download a song teaser in two different file formats, probably MP3 and WMA. That’s all. The whole thing was a marketing app that should be used a few weeks or months and then be mothballed. Being a marketing app, the payment was very decent.

The development

The freelancer was excited to say the least. This was his chance to enter the emerging field of mobile device software development. And because it should be a web application, he would try out all these new fancy mobile web frameworks and settle for the best. The image of the website should rotate and adjust to the device screen if the user tilted his phone. And because phone screens weren’t that well equipped with pixels as today and mobile internet was expensive, the image should be optimized for the best possible tradeoff between details and file size.

Some mobile web frameworks provided access to the device type, so there were all kinds of javascript magic tricks to be potentially applied. Well, they weren’t applied, but very well could have been. The freelancer prototyped most of them, out of curiosity.

The web application itself was completed in one session once the song files and the master image were provided by the customer. The freelancer installed everything on a staging web server and communicated back success. The customer was pleased by the quick reaction time and appointed a meeting to inspect the results.

The presentation

The customer gave the freelancer a notebook attached to a beamer to present the application. The notebook had a screen resolution many times the envisioned target platform, so the intro image was very pixellated and far from appealing. The freelancer used his smartphone to present the image on a smaller screen, but the customer only shook his head: “You should develop a web application for both phones and PCs. Most of our customers will use their PC to visit the site.” The freelancer apologized and promised to add another browser switch to present a full resolution image to PC users.

Now, the freelancer continued to present the web application on his phone. He invited the customer to tilt the device and was satisfied when the web site adjusted perfectly. The customer was pleased, too. Then, he tapped on one of the buttons. Nothing happened. The whole application consisted only of two buttons and one wasn’t working. The freelancer frantically tried to figure out what had gone wrong, when the customer tapped on the other button. No reaction from that one, too. “But I’ve uploaded both song files to the right location with the right access rights.”, the freelancer just said to himself when it dawned him: He forgot to insert the link tags in the HTML file. The buttons were just images. He never actually clicked on one of the buttons during development.

The moral of the story

Recapitulating, the freelancer was asked to develop a web application with an image and two download buttons, but he managed to cripple the image for the larger part of the anticipated users and never provide any download functionality at all. The customer’s requirements somehow got lost along the way.

This isn’t so much a story about a confused freelancer or improper requirement analysis. It’s a story about priorities. The customer expressed his priorities through the requirements. The freelancer superimposed his own priorities very early in the process (without telling anybody) and never returned to the original set until the presentation. And while it is granted to have a secondary agenda as a service provider, it should never interfere with the primary agenda – the one set by the customer.

Don’t fool yourself into thinking that this could never happen to you. It’s not always as obvious as in this story. Some, if not most of your customer’s priorities are unintentionally (or even intentionally) kept secret. They can only be traced during live exercises, which is why early prototyping and using the prototype in real scenarios is a good way to reveal them.

A review of the year 2011 at Softwareschneiderei

This is a review of the year 2011 for the Softwareschneiderei, a software development company from Karlsruhe, Germany.

The current year 2011 is coming to an end. This is the traditional time to pause and reflect on what has happened. This blogpost tries to sum up our year in software development at Softwareschneiderei. It was an interesting, entertaining and successful year for us, that’s for sure.

The official parts

Our developer blog was alive throughout the hardest times of the year, when everyone was under full project load. Every week, one of our developer shares a little posting with the world. The blog is still managed by token only. Looking at the visitor statistics, we fully appreciate your attention. The first blog post of this year looked at the remainder of a failed project. “A tale of scrap metal code” was a detailed vivisection in three parts. Over the course of the year, we wrote about bogus error messages, Groovy, Grails, GORM and some confessions about coding style and multithreading. If you have the time, spend a few minutes to browse our blog post archive for this year.

Our “official” company blog, written in german language, had no activity this year. We can certainly do better than this and take it on the list for 2012.

The company homepage, written in german language, had continuous updates and extensions this year. We coupled the “Open Source Love Day” (OSLD) with our “Homepage Comittee”, when every employee has to improve the homepage in some aspects and present the change to the “comittee”. Unfortunately, this somehow lead to fewer OSLDs this year.

The ongoing Dev Brunch sessions thinned out a bit in the second half of the year. This was a concession to the ever-growing workload. We strive to establish a tighter schedule with accompanying blog posts in the next year.

The internal parts

We were under heavy development load this year. This isn’t a bad thing, but impacts the internal communication and team building process. We tried to cope a bit by restructuring the Open Source Love Day to a “Team Day”, when the whole team meets and works on various internal or hobby projects. Some of these days were spend on Code Camps and other training events. This means less love for the open source community, but crucial together time for us.

We picked up several “new” programming languages this year. You can tell by the blog posts that we worked with Python, Ruby, Flex/ActionScript and even VisualBasic on real projects. The VisualBasic experience was a little epiphany that it’s really the developer and not the language that leads to shitty software.

One method of continuous improvement is our “creativity budget”. Basically, it’s money every developer can spend to improve his workplace. This budget wasn’t used at all this year, as the workplaces seem to be optimal. This cannot be true, so we bought brand new computers or a big RAM upgrade for everyone. And every computer has a big enough SSD now. We took our own advice seriously and invested in our productivity.

Our developer crew grew again this year. We are beginning to think about the remaining space in the new office again. But as usual, we grow slowly and deliberately. There’s nothing worse than a team of strangers.

Conclusion

The year 2011 was great! We’re looking forward to the year 2012, with our motto of christmas 2011: “cheery and spry” (the original motto is in german language “froh und munter”, I hope the translation caught the original spirit).

Have a great turn of the year, everyone. We’d love to see you again next year.

Story about bogus error messages

Most computer users know the situation where some system or service that worked for months without problems suddenly stops working. I want to tell you of a small war story which happened some weeks ago to us.

We are maintaining an own mail server with imap access for our employees. That allows for relativly easy serverside spam protection, mailing list management and archiving and so on. We use the trusted combination of postfix, cyrus and mailman for the task and everything works very reliably. Then suddenly we got the error message ssl_error_rx_record_too_long in our e-mail clients. Nothing had changed software-wise. Googleing on the internet brought up all kinds of different obscure reasons for this error but no explanation why something like that would happen out of thin air.

Fortunately, looking in cyrus’ log files quickly showed the reason: the hard drive was full! A two days before the mail system failing there was a larger upload to the server for sharing stuff with a colleague. This upload fitted almost exactly onto the free disk space and some mails later the disk was full. It was really a murphy’s law situation because some kilo bytes less free space would have made the file sharing fail with a sensible error message. But it worked and made the mail system fail suddenly without immediate connection some changes to the server.

There are some lessons to be learned here:

  • Aside from file managers most applications assume memory and disk space are unlimited. If they do hit such a limit they usually fail miserably with complete bogus errors.
  • Monitor critical resources on important systems to receive warnings ahead of time before important service fail. Tools like Nagios can help here.
  • Try to be aware of side effects of your actions. Separating services to different machines may help to reduce unexpected side effects on seemingly unrelated stuff. We used the server to run many different unrelated services.

Verbosity is not Java’s fault

One of Java’s most heard flaws (verbosity) isn’t really tied to the language it is rooted in a more deeply source: it comes from the way we use it.

Quiz: Whats one of the most heard flaws of Java compared to other languages?

Bad Performance? That’s a long overhauled myth. Slow startup? OK, this can be improved… It’s verbosity, right? Right but wrong. Yes, it is one of the most mentioned flaws but is it really inherit to the language Java? Do you really think Closures, annotations or any other new introduced language feature will significantly reduce the clutter? Don’t get me wrong here: closures are a mighty construct and I like them a lot. But the source of the problem lies elsewhere: the APIs. What?! You will tell me Java has some great libraries. These are the ones that let Java stand out! I don’t talk about the functionality of the libraries here I mean the design of the API. Let me elaborate on this.

Example 1: HTML parsing/manipulation

Say you want to parse a HTML page and remove all infoboxes and add your link to a blog box:

        DOMFragmentParser parser = new DOMFragmentParser();
        parser.setFeature("http://xml.org/sax/features/namespaces", false); 
        parser.setFeature("http://cyberneko.org/html/features/balance-tags", false);
        parser.setFeature("http://cyberneko.org/html/features/balance-tags/document-fragment", true);
        parser.setFeature("http://cyberneko.org/html/features/scanner/ignore-specified-charset", true);
        parser.setFeature("http://cyberneko.org/html/features/balance-tags/ignore-outside-content", true);
        HTMLDocument document = new HTMLDocumentImpl();
        DocumentFragment fragment = document.createDocumentFragment();
        parser.parse(new InputSource(new StringReader(html)), fragment);
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        Node infobox = xpath.evaluate("//*/div[@class='infobox']", fragment, XPathConstants.NODE);
        infobox.getParentNode().removeChild(infobox);
        Node blog = xpath.evaluate("//*[@id='blog']", fragment, XPathConstants.NODE);
        NodeList children = blog.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            node.remove(children.item(i));
        }
        blog.appendChild(/*create Elementtree*/);

What you really want to say is:

HTMLDocument document = new HTMLDocument(url);
document.at("//*/div[@class='infobox']").remove();
document.at("//*[@id='blog']").setInnerHtml("<a href='blog_url'>Blog</a>");

Much more concise, easy to read and it communicates its purpose clearly. The functionality is the same but what you need to do is vastly different.

  The library behind the API should do the heavy lifting not the API's user.

Example 2: HTTP requests

Take this example of sending a post request to an URL:

HttpClient client = new HttpClient();
PostMethod post = new PostMethod(url);
for (Entry param : params.entrySet()) {
    post.setParameter(param.key, param.value);
}
try {
    return client.executeMethod(post);
} finally {
    post.releaseConnection();
}

and compare it with:

HttpClient client = new HttpClient();
client.post(url, params);

Yes, there are cases where you want to specify additional attributes or options but mostly you just want to send some params to an URL. This is the default functionality you want to use, so why not:

  Make the easy and most used cases easy,
    the difficult ones not impossible to achieve.

Example 3: Swing’s JTable

So what happens when you designed for one purpose but people usually use it for another one?
The following code displays a JTable filled with attachments showing their name and additional actions:
(Disclaimer: this one makes heavy use of our internal frameworks)

        JTable attachmentTable = new JTable();
        TableColumnBinder<FileAttachment> tableBinding = new TableColumnBinder<FileAttachment>();
        tableBinding.addColumnBinding(new StringColumnBinding<FileAttachment>("Attachments") {
            @Override
            public String getValueFor(FileAttachment element, int row) {
                return element.getName();
            }
        });
        tableBinding.addColumnBinding(new ActionColumnBinding<FileAttachment>("Actions") {
            @Override
            public IAction<?, ?>[] getValueFor(FileAttachment element, int row) {
                return getActionsFor(element);
            }
        });
        tableBinding.bindTo(attachmentTable, this.attachments);

Now think about you had to implement this using bare Swing. You need to create a TableModel which is unfortunately based on row and column indexes instead of elements, you need to write your own renderers and editors, not talking about the different listeners which need to map the passed indexes to the corresponding element.
JTable was designed as a spreadsheet like grid but most of the time people use it as a list of items. This change in use case needs a change in the API. Now indexes are not a good reference method for a cell, you want a list of elements and a column property. When the usage pattern changes you can write a new library or component or you can:

  Evolve your API.

Designed to be used

So why is one API design better than another? The better ones are designed to be used. They have a clearly defined purpose: to get the task done in a simple way. Just that. They don’t want to satisfy a standard or a specification. They don’t need to open up a huge new world of configuration options or preference tweaks.

Call to action

So I argue that to make Java (or your language of choice) a better language and environment we have to design better APIs. Better designed APIs help an environment more than just another new language feature. Don’t jump on the next super duper language band wagon because it has X or Y or any other cool language feature. Improve your (API) design skills! It will help you in every language/environment you use and will use. Learning new languages is good to give you new viewpoints but don’t just flee to them.

Schneide blog heartbeat revisited

A short review of our company blogging engagement in 2009, with a description of the underlying rules.

The start of a new year is a great opportunity to look back and review the old year. This article reviews this blog, how we run it and what happened in 2009.

The first review

This blog came to life in February 2007 and was revived and retrofitted with a basic rule set in August 2008. Exactly a year ago, i wrote a first review of the changes, explaining some of the rules behind it and judging the outcome. You might want to read it in order to understand some of the following metaphors.

A year with constant pace

We haven’t changed the rules in a year. We still run this blog at a constant, sustainable pace. We still collect and foster “vegetables”, our metaphor for blog entries. Everyone in our company has a “garden” full of blog entry drafts that evolve over time and finally get published. We still don’t think that maintaining a company blog has to lead to internal competition or a blog quality assurance department.

We ran this blog for a whole year with weekly entries by just passing the blog token around. Instead of getting tired to write yet another blog entry, we sometimes asked to publish our entry ahead of time just because it was ready and eager to meet the world. We kept discipline, but in a flexible manner.

The results

What can you expect to happen when all you do is to keep your flow (we call it “obeying the mechanics”)? A single picture tells it all:

You see the visitor statistics from the day we revived the blog. The small mound around 2008-10 was last year’s visitor maximum. We grew every month this year. We did expect the numbers to grow, but not exponentially as in the last months. We are overwhelmed by success. Which leads to a few additional rules.

The additional rules

  • As the amount of discussion around our blog rises, we introduced the rule of “author-based commenting“. Every comment on our blog needs to get our approval (by saying something on topic, we just filter out the spam) and will eventually get an answer from us. The responsible person for both actions is the original blog entry author. This may lead to slightly longer approval delays, but adds coherence to the comment trail and discussion tone.
  • We regularly publish our articles on aggregator sites like dzone.com. All of these sites provide their own commenting system. We tend not to answer comments on these sites. It would shatter the discussion without benefit for the ordinary visitor. If you want us to answer, feel free to copy the comment into our blog.
  • We introduced some regularly “events” in our company last year. The Open Source Love Day (OSLD), the Dev Brunch and the occasional Blog Harvest are all worth to write about, but are attended by many authors. We agreed to publish these special event entries out of turn, whenever they are ready but in a timely manner. These entries share a common icon set to distinguish them from regular entries. They are a cocktail of our combined writing skills and tend to be very specific. Regard them as “bonus tracks” on our written company album.

What to expect in the future

We are looking forward to keep our pace in 2010. The blog will receive a facelift and better integration with our website soon. We plan to provide some improvements on finding relating groups of existing articles. But we don’t want to make changes in our ruleset or dedication.

If you happen to follow us on our blog, drop a comment. We really like to hear from you. By the way, in 2010 the first entry on reader request will be published. Stay tuned!

We are software tailors

Our company is called Softwareschneiderei (which is German for software tailoring). This name describes our intention to write bespoken software, software that fits people perfectly. Over time different additional metaphors from the tailor’s world came around: seams/tucks which describe places in software systems where cuts can be made and testing can be done. Tailoring is a craftsmanship so an apprenticeship model and the pride in our work exists.
This describes the mentoring and bespoken software development we do. But besides that we do a lot of bug fixing, improvement of existing software which was written by others and evaluation of other people’s code. Thanks to a piece from Jason Fried (thanx Jason!) those other parts fit perfectly into our vision as software tailors: we iron/press (fix bugs, improve the code), we trim and cut (remove bottlenecks and unwanted functionality or extend the software to use other systems) and we measure (analyze, inspect and evaluate systems).

Our first Open Source Love Day (OSLD)

opensourcelovedayLast week we had our first OSLD and started with the usual hopes and fears:

  • how much time will be consumed setting the project up?
  • will we find issues that are small enough to be finished in one day?
  • the hope to learn something new: a new technology, language or tool
  • the hope to improve our skills in reading a different code style and a new codebase

As an additional challenge we tried to do object calisthenics (which we will covered in a different blog post). In short they are a list of coding guide lines which try to bend your mind to get more flexible when coding/designing software.

Start

After an initial meeting we decided to work on EGit/JGit. This project was on a familiar ground (Java) and had enough new tools (Git) and technologies (plugin development under Eclipse). Setup was very easy and fast (thanx to the EGit/JGit team!) and we started to look at the low hanging fruits linked from the EGit wiki which are basically issues that are categorized as easy. This is a very good idea for project newbies to start (in theory…). But the reality was that most of them were already patched and other had not enough information to make any sense for us (which could be also our lack of knowledge of the GIT wording and its internal concepts and function). At the end of the day we had worked on issues which were definitely too big for us (requiring changes in the infrastructure of JGit) and reported some issues as non-reproduceable.

Finish

So we learned a few things from the first day:

  • project setup can be very fast and easy
  • low hanging fruits are a very good idea
  • avoid infrastructure changes
  • a basic familiarity with the concepts involved is key to get along
  • don’t do too much on one day, instead: focus!
  • scratching your own itch would benefit the understanding of the issue and your motivation

So in the next month we give OSLD another chance and hope to learn even more.

Give open source some love back!

Like many others our work is enabled by open source software. We make a heavy use of the several great open source projects out there. Since they help us doing our business and doing it in a productive way, we want to give some love aehmm work back. So we decided to dedicate one day per month to open source contributions. These can be bug fixes, new features, even documentation or bug reports. I believe that every contribution helps an open source project and many projects need help.
The whole development team will work on projects they like. One day per month does not sound much but I think even starting small helps. And maybe you can suggest a similar day in your company, too ?
Besides the obvious boost in developer motivation (and therefore productivity) there are several things your company will benefit from:

  • help in your own projects: fixing bugs in the open source projects you use is like fixing bugs in your own project
  • image for your company: being active in open source gives a better image regarding potential future employees and also shows responsibility in the field they work in
  • PR for your company and an edge over your competition: writing about your contributions and your insights in your company blog, remember: out teach your competition

So get your company to spend just one day per month or so for open source. It may not be much but every little bit helps!

“Tag, you’re it!” – how we manage our blog heartbeat

We successfully revived a nearly abandonded blog by using a token and a few metaphors.

The new year 2009 just started. A great opportunity to review some things. Here is a review of our blogging.

heartbeatWe started this blog in February 2007. Soon afterwards, it was nearly dead, as no new articles were written. Why? We would have answered to “be under pressure” and “have more relevant things to do” or simply “have no idea about what to write”. The truth is that we didn’t regard this blog as being important to us. We didn’t allocate any ressources, be it time, topics or attention to it. Seeming unimportant is a sure death cause for any business resource in any mindful managed company.

The Revival

This changed in late August 2008, after we heard from several sources that our articles published so far were very promising. Some new contacts even asked about our Code Flow-O-Meter before they asked any other question. So we sat together and thought about a way to revive this blog with minimal possible effort. We came to the conclusion that, being a four-man-show company, it would be sufficient for everyone to write one blog article a month in order to show a weekly blog heartbeat. It’s simple math. The same discussion led to the conclusion that blogging in english would reach a broader audience.

It’s a management problem

This laid the foundation for a few new blog entries, as everyone was eager to tell some news. But how could we manage the blog heartbeat in a sustainable fashion, with minimal effort and attention of the individual?

blogtoken

We decided to give the “Blog Token” a try. This token is nothing more than a little index card informing you that you are responsible for the blog entry in the next week. You can keep the index card on your desk or take it with you to remind you of the task. If you published your entry, you hand it over to the following team member in line. The token order is defined on a very viewable whiteboard. It took us 5 minutes to set up the token and define the order. Everything else is managed by the one who wants to get rid of the token and the one who receives it.

It doesn’t work without metaphors

When we reviewed the process, we realized that without a few maxims and their impact, things would have gone astray even with the token in place. Here are some of our maxims, spelled by the metaphors we found for them:

  • “blog heartbeat”: When you want to “keep it flowing” in a sustainable pace, you need to have a pace first. We defined that our blog is alive when it has a periodic heartbeat. Weekly articles seemed to be a good start and were approved in every review yet.
  • “to grow vegetables”: Good ideas (and good blog topics) need to evolve and grow. You need to care about them for an amount of time and publish them when they are mature. But first of all, you need to put the seeds for ideas (and blog topics) in your garden. Whenever somebody mentions something that might be worth a blog entry, somebody calls “this is a vegetable!”. A first sketch of a new blog entry (a new vegetable in your garden) is born in this moment. To be honest, some vegetables starve over time.
  • “it’s not a competition”: We try to publish high quality blog entries. But it’s more important to us to tell you about our favorite vegetable (see second metaphor) than to win a pulitzer price for every article. We even try to remind ourselves that we do not compete for the recoginition from our readers (you, in this case!). To be honest here, too: Though it’s not a contest, we issued an internal price for our most read article: Using Hudson for C++/CMake/CppUnit

Reviewing the Revival

We revived our blog with three ingredients:

  • Our commitment (“it’s important to us”)
  • The Blog Token (“tag, you’re it!”)
  • Metaphors (“everyone can grow vegetables”)

Telling from the statistics, it simply skyrocketed us:

blog-stats

Thank YOU, our blog visitors, for making this possible. It’s been a great experience for us and we are looking forward to continue our blog heartbeat in 2009 with fully stacked vegetable gardens. Stay tuned and if you like, share your thoughts (or just say hello) by adding a comment. We really appreciate your opinion.