Java vs .NET
Before we explore the differences between .NET and Java, let’s first find out why they exist at all. If we cast our mind back to the early days of computing, programming was a very difficult task. There were many different computers with wildly different architectures. (Soviet computer Сетунь even used ternary system instead of the binary system!) Computing power was expensive, so it was up to the programmers to produce the bytes that make up the machine instructions of the program they were creating. It was tedious and error-prone work. The symbolic instruction languages set out to help. Instead of 35434f4445 (5CODE in ASCII) the programmers could write xor%eax,$0x45444f43 in the symbolic instruction language (in this example, we have instructions for the Intel 80386 and later processors). Take my word for it: the second form is much more understandable! In addition to being able to use instruction mnemonics, the symbolic instruction languages brought symbols for variables.
The compilers for the symbolic instruction languages (called assemblers) were able to translate the instruction mnemonics to the processor opcodes and to translate the variables to memory addresses in the opcodes. Unfortunately, large systems comprise billions of such instructions. To allow the programmers to create such large systems, we had to have higher-level languages that insulated us from the technical details. A shining example is the C language, which is still widely used today. It allows us to think about the problem we’re solving rather than how to express the problem in symbolic instructions or machine code.
Then came object-oriented programming. These languages brought even more abstraction. Whereas in C, we would call functions that operate on data structures, in OOP, we have objects that include their data and behaviour. An example of object-oriented language is C++ or Object Pascal. Both are still very much alive today. So, why was there the need for .NET and Java? All languages before Java and .NET compile the source code (at higher and higher levels of abstraction) straight down to the machine code that the processor could execute. Therefore, it is very difficult for anything other than the processor to understand the compiled code. Furthermore, the programmer is responsible for managing resources like the allocated memory. Memory management sounds quite easy: if you allocate memory, you must free it. It becomes much more difficult when the program flow becomes complex and it becomes unclear which bit of code should be responsible for freeing a block of memory received from some other code.
This is the main productivity boost of so-called managed runtimes: Java and .NET. In a managed runtime, the computer takes care of managing memory. This doesn’t prevent memory issues completely though as it’s up to the programmer to ensure no object references exist that will prevent the memory from being reclaimed when the garbage collector runs. The second productivity boost comes from the ability to examine the compiled code from within the running code. This may seem useless at first: why would we need to examine code we’ve written, after all? The productivity boost comes from examination of code we have not written—it allows us to create frameworks that examine applications’ code and can take care of most of the tedious and repetitive programming tasks.
Now that we’ve established that Java and .NET both brought an immense productivity boost, because they allowed us to work with objects without having to worry about the memory management and because they allowed us to introspect the compiled code. The question is now: “What is better: Java or .NET?”…
And The Winner Is…
Well there is no winner. It is more important to be able to create elegant software, a task that is achievable in Java as well as in .NET. Let’s review what elegant software looks like. Elegant software is easy to change and it is well tested. The natural consequence of these two requirements is that elegant software is made up of sharply defined components that use established design patterns of object-oriented programming, and perhaps takes advantage of the aspect-oriented programming; the components’ dependencies are not tangled and flow in only one direction throughout the system. Just as importantly, to compliment elegant software, you have a good continuous integration system and you regularly inspect the code quality. If we scale these requirements across entire organisations (with many projects), we need to add code re-use between projects. This further reinforces the need for sharply defined, loosely coupled, independent, testable and tested code.
In other words, if you can produce such software in Java, use Java! The switch to .NET would bring immense disruption, not because you’d have to learn C#, for example, but because you would have to learn the details of the platform and adopt tools of the new platform. Similarly, if you are producing excellent quality .NET code, then switching to Java will not bring any productivity boost: just like the Dukes switching to .NET, you’d have to learn everything there is to know in the Java world.
If you have skills in both platforms, then keep both platforms. Attempts to unify everything under one platform (with hope of lowering costs, improving performance, consolidating the infrastructure) rarely work. Not because of the limitations of the technologies, but because of underestimating the complexity of such task. If, however, you must decide then you need to decide on merit and merit alone. Do not be forced into accepting Java only because there are many open source libraries. Do not accept .NET because “we already have Windows, so it makes sense!”
So, does that mean that you should just stick with what you know, be it Java or C#? Absolutely not! Many have fallen into the trap of thinking (or even saying!) that “everything that can be invented has been invented”.
The Java and .NET platforms are not going to disappear in the next few years. This is good news for your investment in the .NET or Java infrastructure. There are, however, new languages emerging on both platforms. The most notable ones are the pure object-oriented languages like Groovy on Java, representatives of the functional programming languages (F# on .NET, Scala and Clojure on Java). Finally, both platforms now include interpreters and compilers for existing languages, for example, there are Python and Ruby interpreters.
This allows you to choose the appropriate language for the problem you’re trying to solve. If you need to develop a domain-specific language, you may consider using F# on .NET. On the Java platform, pick Groovy and its AST transformations. If you are solving a computationally intensive problem that can be easily mapped, computed by parts and then reduced, the functional languages would be ideal candidates.
The only saving grace, in the fast pace of today’s programming world, is being open minded and having the ability and aptitude to learn new concepts; even ones that are completely alien to you. If you accept that only the best tools can produce excellent results and that you need many different tools to complete a task, then it is natural to accept that only the best development practices combined with the appropriate languages produce excellent software.
The NCC Technical Guidelines #6 – Java vs. .NET from which this article is extracted sets out to help you in making strategic decisions over several years. You can read the full unabridged version at: www.ncc.co.uk/javavsdotnet