Bear up against static code analysis

If you ever had the urge to switch off a rule in your static code analysis tool, this article tries to convince you not to do it. By accepting challenges presented by your tools, you become a better developer and clean up your code on the run.

One of the first things we do when we join a team on a new (or existing) project is to set up a whole barrage of static code analysis tools, like Findbugs, Checkstyle or PMD for java (or any other for virtually every language around). Most of these tools spit out tremendous amounts of numbers and violated rules, totally overwhelming the team. But the amount of violations, (nearly) regardless how high it might be, is not the problem. It’s the trend of the violation curve that shows the problem and its solution. If 2000 findbugs violations didn’t kill your project yet, they most likely won’t do it in the future, too. But if for every week of development there are another 50 violations added to the codebase, it will become a major problem, sooner or later.

Visibility is key

So the first step is always to gain visibility, no matter how painful the numbers are. After the initial shock, most teams accept the challenge and begin to resolve issues in their codebase as soon as they appear and slowly decrease the violation count by spending extra minutes with fixing old code. This is the most valuable phase of static code analysis tools: It enables developers to learn from their mistakes (or goofs) without being embarrassed by a colleague. The analysis tool acts like a very strict and nit-picking code review partner, revealing every flaw in the code. A developer that embraces the changes implied by static analysis tools will greatly accelerate his learning.

But then, after the euphoric initial challenges that improve the code without much hassle, there are some violations that seem hard, if not impossible to solve. The developer already sought out his journey to master the tool, he cannot turn around and just leave these violations in the code. Surely, the tool has flaws itself! The analysis brought up a false positive here! This isn’t faulty code at all, it’s just an overly pedantic algorithm without taste for style that doesn’t see the whole picture! Come to think about it, we have to turn off this rule!

Leave your comfort zone

When this stage is reached, the developers have a deep look into the tool’s configuration and adjust every nut and bolt to their immediate skill level. There’s nothing wrong with this approach if you want to stay on your skill level. But you’ll miss a chance to greatly improve your coding skills by allowing the ruleset to be harder than you can cope with now. Over time, you will come up with solutions you now thought are impossible. It’s like fitness training for your coding skills, you should raise the bar every now and then. Unlike fitness training, nobody gets hurt if the numbers of your code analysis show more violations than you can fix up right now. The violations are in the code, if you let them count or not.

Once, a fellow developer complained really loud about a specific rule in a code analysis tool. He was convinced that the rule was pointless and should be switched off. I asked about a specific example where this rule was violated in his code. When reviewing the code, I thought that applying the rule would improve the code’s internal structure (it was a rule dealing with collapsible conditional statements). In the discussion on how to implement the code block without violating the rule, the real problem showed up – my colleague couldn’t think about a solution to the challenge. So we proceeded to implement the code block in a dozen variations, each without breaking the rule. After the initial few attempts that I had to lead program for him, he suddenly came up with even more solutions. It was as if a switch snapped in his head, from “I’m unable to resolve this stupid rule” to “Hey, if we do it this way, we even can get rid of this local variable”.

Embrace challenges

Don’t trick yourself into thinking that just because your analysis tool doesn’t bring up these esoteric violations anymore after you switched off the rules, they are gone. They are still in your code, just hidden and without your awareness. Bear up against your analysis tool and fix every violation it brings you, one after the other. The tools aren’t there to annoy you, they want to help you stay clear of trouble by pointing out the flaws in a clear and precise manner. Once you meet the challenges the tool presents you with, your skill level will increase automatically. And as a side effect, your code becomes cleaner.

Beyond clean code

Even if every analysis tool approves your code as being clean, it can still be improved. You might have a look at Object Calisthenics or similar code training rulesets. They work the same way as the analysis tools, but without the automatic enforcement (yet). The goal is always cleaner code and higher skilled developers.

Clean code is not enough

Not only well-crafted software, but useable and delightful software.

I keep hearing stuff like:
“we as software developers are craftsmen and should honor our craft and write clean code”

Using the metaphor of a craftsman we should also realize that we are building software for people (to use) not for its own sake.
Imagine a chair which is perfectly crafted and beautiful to look at but you can’t sit on it?
It might be art but nobody can use it for its original purpose.

Most if not all of the software we write is for people to use, to be empowered and yes, to be delighted.
But to what use (besides art) is a software which is cleanly built but unusable?
We as software developers have shied away for too long from learning to craft useable interfaces.
I think we should not neglect that we develop software for others to use.
A program is not an island, it only excels when it interacts with users or other programs.

Not only well-crafted software, but useable and delightful software.

Spice up your unit testing

Writing unit tests shouldn’t be a chore. This article presents six tools (with alternatives) that help to improve your developer experience.

Writing unit tests is an activity every reasonable developer does frequently. While it certainly is a useful thing to do, it shouldn’t be a chore. To help you with the process of creating, running and evaluating unit tests, there are numerous tools and add-ons for every programming language around. This article focusses on improving the developer experience (the counterpart of “user experience”) for Java, JUnit and the Eclipse IDE. I will introduce you to the toolset we are using, which might not be the complete range of tools available.

Creating unit tests

  • MoreUnit – This plugin for Eclipse helps you to organize your unit test classes by maintaining a connection between the test and the production class. This way you’ll always see which classes and methods still lack a corresponding test. You can take shortcuts in the navigation by jumping directly into the test class and back. And if you move one file, MoreUnit will move the other one alongside. It’s a swiss army knife for unit test writers and highly recommended.
  • EqualsVerifier – If you ever wrote a custom implementation of the equals()/hashcode() method pair, you’ll know that it’s not a triviality. What’s even more intimidating is that you probably got it wrong or at least not fully correct. The effects of a flawed equals() method aren’t easily determinable, so this is a uncomfortable situation. Luckily, there is a specialized tool to help you with this task exactly. The EqualsVerifier library tests your custom implementation against all aspects of the art of writing an equals() method with just one line of code.
  • Mockito (and EasyMock) – When dealing with dependencies of classes under test, mock objects can come in handy. But writing them by hand is tedious, boring and error-prone. This is where mock frameworks can help by reducing the setup and verification of a mock object to just a few lines of code. EasyMock is the older of the two projects, but it manages to stay up-to-date by introducing new features and syntax with every release. Mockito has a very elegant and readable syntax and provides a rich feature set. There are other mock frameworks available, too.

Running unit tests

  • InfiniTest (and JUnit Max) – Normally, you have to run the unit tests in your IDE by manually clicking the “run” button or hitting some obscure keyboard shortcut. These two continuous testing tools will run your tests while you still type. This will shorten your test feedback loop to nearly milliseconds after each change. Your safety net was never closer. InfiniTest and JUnit Max are both Eclipse plugins, but the latter costs a small annual fee. It’s written by Kent Beck himself, though.

Evaluating unit tests

  • EclEmma (and Cobertura) – If you want to know about the scope or “coverage” of your tests, you should consult a code coverage tool. Cobertura produces really nice HTML reports for all your statistical needs. EclEmma is an Eclipse plugin that integrates the code coverage tool Emma with Eclipse in the finest way possible. Simply run “coverage as” instead of “run as” and you are done. All the hassle with instrumenting your classes and setting up the classpath in the right order (major hurdles when using cobertura) is dealt with behind the scenes.
  • Jester (and Jumble) – The question “who tests my tests?” is totally legit. And it has an answer: Every mutation testing tool around. For Java and JUnit, there are at least two that do their job properly: Jester works on the source code while Jumble uses the bytecode. Mutation testing injects little changes into your production code to test if your tests catch them. This is a different approach on test coverage that can detect code that is executed but not pinned down by an assertion. While Jester has a great success story to tell, Jumble tends to produce similar results as cobertura’s condition coverage report, at least in my experience.

Summary

As you can see, there is a wide range of tools available to improve your efforts to write well-tested software. This list is in no way comprehensive. If you know about a tool that should be mentioned, we would love to read your comment.

CMakeBuilder Version 1.9

Introducing CMakeBuilder plugin version 1.9.

Today, I want to announce version 1.9 of the CMakeBuilder plugin for Jenkins (formerly known as Hudson). Concluding from the user feedback, there are no major missing features – at least for the moment.

So for this version, I implemented only one visible enhancement: It is now possible to use environment variables in every configuration setting. Even settings like “Preload Script” “Make Command” or “Install Command” can now be configured with the support of environment variables.

The major invisible change I did was the migration to the Jenkins development infrastructure using this very helpful guide. Moving the whole thing to git will be next.

Check it out!

Reversing an array in Java

Reversing an array is a popular interview question especially in languages like C. Some days ago I faced the problem in a Java legacy project I was maintaining. As a Java guy I did not want to fiddle with a for-loop and indexes. So I looked for another solution. Besides showing the one-liner I want to give some insights which some might not be aware of. Here is my solution:

public static <T> T[] reverse(T[] array) {
    Collections.reverse(Arrays.asList(array));
    return array;
}
  1. This approach works, because the ArrayList implementation Arrays.asList() returns a specially tailored ArrayList which writes the changes right through to the backing array. It is not a java.util.ArrayList!
  2. The above means that the array is changed in-place and no array copying is involved. The approach thus has good performance it that matters.
  3. My solution directly changes the given array. To make it free of side-effects you could create a new array and copy the original one into it before converting to a list and reversing.

Side note regarding Arrays.asList()

Arrays.asList() is nice for bridging to old code and APIs. It has to be used with caution though: If you read the API documentation and keep 1.) in mind you will notice, that the returned list is fixed size. So calls to add() and remove() will fail with an UnsupportedOperationException! Passing such lists around in your system using the java.util.List interface may lead to unexpected behaviour since most people expect lists to be of variable sized in Java. In our use case we do not return the resulting list to the caller but only use it temporarily and locally. So this is no problem here.

Conclusion

Reversing an array can be a nice interview question for Java candidates too as you can discuss about in-place reversing, memory and time complexity and different approaches. It may show their knowledge of the collection API and the utility classes. If the above approach is discovered there is also something to discuss as depicted in this article.

Grails: The good, the bad, the ugly

(Opinion!) After 3 years of Grails development it is time to take a step back and look how well we went.

After 3 years of Grails development it is time to take a step back and look how well we went.
(Info: we made several Grails apps ranging from small (<15 domain classes) to medium sized (50-70 domain classes) using front ends like Flex/Flash and AJAX)

The good parts

Always start with praise. So I tell you what in my opinion was and is good about developing in Groovy and Grails.

Groovy is Java with sugar

The Groovy syntax and the type system are so close to Java, so that when you come from a Java background you feel right at home.

Standard web stack

If you are accustomed to standard technologies like Spring and Hibernate you see Grails as a vacation.

Sensible defaults aka Convention over configuration

Many of the configuration options are filled with sensible defaults.

Fast start

You get from 0 to 100 in almost no time.

The bad things

Things which are not easily avoided.

Bugs, bugs, bugs

Grails has many, many bugs, unfortunately even in such fundamental things such as data binding and validation. A comment from a previous blog post: “To me, developing with Grails always felt like walking on eggs.”

Regression

Some bugs sneak back in again or are even reopened. Note that this is not the same as bugs, bugs, bugs because fixed bugs should be secured by a test.

Leaky abstractions

You have to know the underlying technologies especially Hibernate and Spring to get a foot on the ground. The GORM layer inherits all the complexity from Hibernate.

Slow integration tests

The ramp up time is 45 s on a decent build/development machine and then the first test hasn’t even started.

Uses the Java way of solving problems

Got a problem? There’s a framework for that!

Abandoned or prototype like plugins

Take a look at the list of plugins like Autobase, Flex.

Problems with incremental compiling

Don’t know where the real cause is buried: but using IntelliJ for developing Grails projects results in comments like:
Not working? Have you cleaned, invalidated your caches, rebuilt your project, deleted the .grails directory?

The ugly things

Things which are easily avoided or just a minor issue.

Groovys use of == and equals

Inherited from Java and made even worse: compare two numbers or a String and a GString

Groovys definition for the boolean truth

0, [], “”, null, false are all false

Groovys use of the NullObject and the plus operator

Puzzler: what is null + null ?

Uses unsupported/discontinued technologies

Hibernates SchemaExport comes to mind.

Mix of technology and intention

hasMany, hasOne, belongsTo have not only an intention revealing function but also determine how cascading works and the schema is generated.

Summary, opinionated

Grails has deficits and is bug ridden. But this will be better in the future (hopefully).
When you compare Grails with standard web stacks in the Java world you can gain a lot from it.
So if you want to know if you should use Grails in your next project ask yourself:

  • do you have or want to use Spring and Hibernate?
  • can you live without static typing? (remember: with freedom comes responsibility)
  • are you ready to work around or even fix an issue or bug?
  • is Java your home?

If you can answer all those questions with Yes, then Grails is for you. But beware: no silver bullets!

Fluent code – challenge your compiler

Learn how to leverage the abilities of your compiler to achieve highly readable code in Java (and probably other similar languages).

Making code more readable, that is, easier to read and therefor easier to grasp, has always been an important secondary goal for me when writing code. The primary goal is correctly working software, but immediately after the code works, it enters maintainance mode. Refactoring is a great tool to improve the structure and accessibility of existing code, but it doesn’t necessarily lead to code that is more readable. I’ve even found that there are multiple levels of “easily accessible” code, depending on your experience with different code structures. But that’s another topic for another blog post.

Readable code

Before I can talk about how to create readable code, I have to define what “readable” means to me: I see readable code as code everybody can read (out loud) and directly understand without further reference.

Here’s an example of a little code snippet in Java that follows my definition:

ForeachFile.in(directory).checkIf(IsOlder.than(5).days());

If you replace the parentheses and dots with whitespace, you can read the line fluently and gain a proper idea of what it is doing.

I’ve always found it much easier to write code similar to this example in dynamic languages. In Groovy, Scala or Perl, you are used to invent your own domain specific language dialect that’s much more readable and concise than using the underlying API directly with all the tedious details. But with a bit of practice, Java (and other statically typed languages) are nearly as flexible to reach (or get near) the highest level of readability: code in natural language.

Start with a sentence

The easy way to accomplish the really challenging task of matching computer programming language and naturally spoken language is to pass it on to the compiler. Start with the desired behaviour of a line of code written as a sentence. The compiler will raise all kinds of objections against this form of programming, and all you have to do is to follow the compiler’s complaints, add some special characters and camel casing and then fill out the classes and methods you just planned ahead.

In reality, it will not be as easy as outlined above, but the process stays the same:

  1. Write your desired code, neglecting all compiler errors
  2. Identify method calls, method parameters, class names and other language features as it fits best
  3. Outline the next code you’ll have to write by silencing the compiler with code stubs (use the code generation features of your IDE)
  4. Fill out the (empty) spots you just created, starting with point 1.

Your first attempts might not be as successful as hoped, so you have to backtrack and adjust for perfectly fluent code to a slightly less perfect form, but that’s just reasonable. You still came up with the possibly most readable code you were able to write.

Know when to stop

Although the process seems to be indefinitely repeatable as you descend deeper and deeper in your code (assuming you started with rather high-level code), there will be a fine line when you have to stop the process because the technical aspects of your code will overwhelm every attempt to wrap natural language around it. You probably still have a good amount of perfectly readable code that even non-programmers can grasp at first sight. Just if you dig deeper into its details, the readability will fade.

Your code will be partitioned into two regions: One region is meant to be read, understood and adjusted if requirements change. The other part of the code isn’t as readable and exists mostly to support the first type of code. This is where you still have to be a programmer to make a change. I assume that your partitioning will meander on the border between business requirements and technical implementation.

Observations along the way

My experimentation phase with this kind of programming revealed some insights that mostly other developers made intuitively when exposed to this style in pair programming sessions.

The most interesting revelation was that the names of my classes change: Instead of using nouns, I tend to use verbs in combination with prepositions (like CheckThat, CreateSome or WaitUntil). This is unfamiliar when reading the class name in isolation, but won’t bother you if you read it in the context of the use case.

Which brings me to the next revelation: The resulting code from the abovementioned process seems to be highly focussed on the current use case. It’s not that it isn’t modifiable or inflexible, but it will serve the task at hand in the best way and fall somewhat short for other use cases. It’s in the ability of the developer to refactor the code once additional use cases appear.

Due to the structuring the natural language imposes on the code, refactorings seem to have a “scope” that can verify if the change at hand is really suitable to bring the code forward. It will be very obvious if a refactoring breaks the ruling structure of the code – the readability of your code will degrade.

Another example

Here is another example of readable code written by the process described above, this time copied from an acceptance test:

station.currentPackage().withTypicalContent().send();
WaitUntilPackage.from(stationName).isProcessedWithin(
    Wait.LONGER).asShownOn(center().statusbar());
Wait.SHORT.perform();
assertThatFilesAreStoredInArchive();
assertThatFilesAreStoredOn(ftpSpace, with(exportName));

You can see that it aren’t always the classnames that drive the code, method names are just as important. And you can see the fitting usage of a code squiggle in the last line, a technique I often use to squeeze in the last missing pieces of fluency.

Summary

Writing readable code that can be read and understood by virtually everyone is a tough task. The programming cycle presented in this article uses the compiler’s ability to complain and the feature of modern IDE to create code stubs (named “quick fixes” or alike) to outline naturally readable code and then fill out the gaps in the best attempt. The result will be code that looks like plain english for the most important parts of the code, the translation of the business requirements. The downside is slightly unusual naming and structure in the other parts of your code.

If you have experiences with this approach to readable code, let us know about it.

The Grails performance switch: flush.mode=commit

Some default configuration options of Grails are not optimal for all projects.

— Disclaimer —
This optimization requires more manual work and is error prone but isn’t this with most (big) performance improvements?
For it to really work you have to structure your code accordingly and flush explicitly.

Recently in our performance measurements of a medium sized Grails project we noticed a strange behavior: every time we executed the same query the time it took increased. It started with 40ms and every time it took 1 ms more. The query was simple like Child.findAllByParent(parent)
The first thought: indexes! We looked at the database (a postgresql db) and we had indexes on the parent column.
Next: maybe the session cache got too large. But session.flush() and session.clear() did not solve that problem.
Another post suggested using a HQL query. Changing to

Child.executeQuery("select new Child(c.name, c.parent) from Child c where parent=:parent", [parent: parent])

had no effect.
Finally after countless more attempts we tried:

session.setFlushMode(FlushMode.COMMIT)

And not even the query executed in constant time it was also 10x faster?!
Hmmm…why?
The default flush mode in Grails is set to AUTO
Which means that before every query made the session is flushed. Every query regardless of the classes effected. The problem is known for hibernate but after 4! years it is still unresolved.
So my question here is: why did Grails chose AUTO as default?

Old Code

Why bother buying Stephen King’s horror books, just take a look at your old code.

There is a saying that if you don’t be embarrassed by code that you wrote six month ago, you haven’t learned anything. Recently, I stumbled upon a C/C++ project that dates back to the very early days of my programming career – this was many * six months ago – and I can tell you, I was very embarrassed.

I had just “learned” C++ and object-orientation at that time and, of course, wanted to program that way. The result was terrible. The only small piece of object-orientation was the use of the keyword class. There were public fields all over the place,  no interfaces or abstractions of any kind, switches over type-ids, and so on.

Another highlight was the vast amount of literals scattered all over the code. For example, as it was a curses-based application, I had to read and display user input using curses methods like

int mvwgetch(WINDOW *win, int y, int x);

and

 int mvwaddch(WINDOW *win, int y, int x, const chtype ch);

And what did I do? I hard-coded y and x positions on every call of those methods. So it would often be the case that I changed, say, the y position in one part and … well, you guessed it already.

Naming of variables was also big. Boolean values would often be called “flag”, a name length of more than 4 was considered way too long.

But there was also progress. In later parts of the software I started to use “advanced” things like auto_ptrs, std::list, and std::map. Hooray!

The only positive thing about this project was that since I made every possible mistake one can imagine, I learned quite lot about programming. And I remember that at the end of the project, I was already very embarrassed about the whole thing…

So if you like reading horror stories, try digging up your old code 😉 And share if you like.

A tale of scrap metal code – Part III

The third and last part of a series about the analysis of a software product. This part tries to give some rules of thumb on how to avoid failure like in this project.

In the first part of this tale about an examined software project, I described the initial situation and high-level observations about the project. The second part dove into the actual source code and pointed out what’s wrong on this level. This part will summarize everything and give some hints on how to avoid creating scrap metal code.

About the project

If you want to know more about the project, read the first part of this tale. In short, the project looked like a normal Java software, but unfolded into a nightmare, lacking basic requirements like tests, dependency management or continuity.

A summary of what went wrong

In short, the project failed in every respect except being reasonable functional and delivering business value to the customers. I will repeat this sentence soon, but let’s recall the worst parts again. The project had no tests. The project modularization was made redundant by circular dependencies and hardwired paths. No dependency management was in place, neither through the means of a build tool nor by manual means (like jar versions). The code was bloated and overly complex. The application’s data model was a widely distributed network of arbitrary collections with implicit connections via lookup keys. No effort was spent to grasp exception handling or multithreading. The cleverness was rather invested into wildcard usage of java’s reflection API capabilities. And when the cleverness of the developer was challenged, he resorted to code comments instead of making the code more accessible.

How can this be avoided?

First, you need to know exactly what it is you want to avoid. Let me repeat that the project was sold to happily paying customers who gained profit using it. Many software projects fail to deliver this utmost vital aspect of virtually every project. The problem with this project isn’t apparent yet, because it has a presence (and a past). It’s just that it has no future. I want to give some hints how to develop software projects with a future while still delivering business value to the customer.

Avoid the no-future trap

http://www.istockphoto.com/stock-photo-5407438-percent-blocks.phpThe most important thing to make a project future-proof is to restrain yourself from taking shortcuts that pay off now and need to be paid back later. You might want to believe that you don’t need to pay back your technical debts (the official term for these shortcuts) or that they will magically disappear sometimes, but both scenarios are quite unlikely. If your project has any chance to keep being alive over a prolonged amount of time, the technical debts will charge interest.

Of course you can take shortcuts to meet tight deadlines or fit into a small budget. This is called prototyping and it pays off in terms of availability (“time to market”) and scope (“trial version”). Just remember that a prototype isn’t meant for production. You definitely need the extra time and/or budget to fix the intentional shortcomings in the code. You won’t feel the difference right now (hey, it works, what else should it do?), but it will return with compound interest in a few years. The project in this tale was dead after three years. The technical debt had added up beyond being repairable.

Analyzing technical debts

It’s always easy to say that you should “do it right” in the first place. What could the developer for project at hands have done differently to be better off now?

1. Invest in automated tests

When I asked why the project has no tests at all, the developer replied that “it surely would be better to have tests, yet there was no time to write them“. This statement implies that tests take more time to write than they save acting as a guideline and a safety net. And it is probably true for every developer just starting to write tests. You will feel uncomfortable, your tests will be cumbersome and everything will slow down. Until you gain knowledge and experience in writing tests. It is an investment. It will pay off in the future, not right now. If you don’t start now, there will be no future payout. And even better: now your investment, not your debt, will accumulate interest. You might get used to writing tests and start being guided by them. They will mercilessly tell you when your anticipated solution is overly complex. And they will stay around and guard your code long after you forgot about it. Tests are a precaution, not an afterthought.

2. Review and refactor your code

The project has a line count of 80,000 lines of ugly code. I’m fairly confident that it can be reduced to 20,000 lines of code without losing any functionality. The code is written with the lowest possible granularity, with higher concepts lurking everywhere, waiting to be found and exposed. Of course, you cannot write correct, concise and considerate code on your first attempt. This is why you should revisit old code in a recurring manner. If you followed advice number one and brought your tests in place, you can apply every refactoring of the book’s catalog and still be sure that you rather fixed this part instead of breaking it. Constantly reviewing and refactoring your code has the additional advantage of a code base that gets more proficient alongside yourself. There are no “dark regions” (the code to never be read or touched again, because it hurts) if you light them up every now and then. This will additionally slow you down when you start out, but put you on afterburner when you realize that you can rescue any code from rotting by applying the refactoring super-powers that you gained through pratice. It’s an investment again, aiming at midterm return of investment.

3. Refrain from clever solutions

The project of this tale had several aspects that the developer thought were “clever”. The only thing with “clever” is that it’s a swearword in software programming. Remember the clever introduction of wildcard runtime classloading to provide a “plugin mechanism”? Pure poison if you ever wanted your API to be stable and documented, just like a plugin interface should be. Magic numbers throughout your code? Of course you are smart enough to handle this little extra obfuscation. Except when you aren’t. You aren’t sure how exception handling works? Be clever and just “empty catch Exception” everywhere the compiler points you to. In this project, the developer knew this couldn’t be the right solution. Yet, he never reviewed the code when he one day knew how to handle exceptions in a meaningful manner. Let me rest my case by stating that if you write your code as clever as you can handle it, you won’t be able to read it soon, as reading code is harder than writing it.

Summary

Over the course of this tale, you learned a lot about a failed project. In this article, I tried to give you some advice (in the form of three basic rules) on how this failure could probably have been avoided. Of course, the advice isn’t complete. There is much more you could do to improve yourself and your project. Perhaps the best self-training program for developer skills is the Clean Code Developer Initiative (it’s mostly german text yet, so here is an english blog post about it), based upon the book “Clean Code” by Robert C. Martin (Uncle Bob).

Invest in the future of your project and stay clean.