Java

Java has been a mainstay for connecting legacy enterprise systems to highly dynamic web interfaces, giving it broad use in the enterprise world. It has the backing of a lot of major corporations and is heavily used in their stack. Companies that use Java include:

  • Intel
  • LinkedIn
  • Uber
  • Spotify
  • EBay
  • Netflix
  • Airbnb
  • Google
  • Minecraft

JavaScript

At the same time, JavaScript appears to be a natural disrupter popping up in various places. While it was born to serve the client side application needs within a browser, JavaScript traveled to the server and desktop through Node.js and is clearly here to stay. Excellent UI frameworks – like Angular.js – can work synergistically with any kind of back-end implementation.

A good number of mobile hybrid application frameworks have entered the market. They are cross-platform so they will work on many different mobile devices without recompiling. They look exactly like native applications and tie into accelerometers, touch screens and the rest of the gamut of hardware available on mobile devices. A number of game engines, such as Unity 3D, now support JavaScript scripting for customization of the game play.

The Developer’s Perspective

Compiled vs. Interpreted

This is an important nuance of the language that has sizable amount of implications for developers. In the olden days, interpreted language meant slower performance, which is (for the most part) no longer the case. But performance aside, there is one essential distinction in the workflow when code is run and tested.

Compiled languages like Java will check the code of an entire project while optimizing and converting scribbles into byte code that can be read by the Java Virtual Machine (JVM) at a later date. It will catch a healthy amount of syntactical errors and alert coders to that effect at the compile time. From that point on, the coder will be operating with a compressed package of byte codes like Java Archive (JAR) or Web Archive (WAR) in case of a web application. This package then can be executed by a virtual machine or a web container that will open it, load it in memory, find an entry point, and bring it to live on somebody’s desktop or server. This does not prevent you from making programming logic errors, but at the very least you have an opportunity to correct all of the syntactical errors right out of the gate.

Security of the intellectual property is also an issue that is solved by many compiled languages. Java compilation does not intrinsically protect your code from decompilation, but there are ways of protecting your output outlined in various resources on the Internet.

Interpreted languages like JavaScript will read through your source code at run time and interpret it as they go. These days there is little negative connotation to this. Interpreters have become so fast and powerful that the performance hit from the action of interpretation is barely noticeable. The fact that any additional code can be loaded and evaluated at runtime makes this simultaneously a very powerful and a very convoluted proposition. On the one hand, this feature provides for many “creative” solutions and dynamic manipulations of the existing code base. On the other hand, this promotes a culture of shortcuts, “duct taping,” clever code and obscure solutions. It takes a great deal of organizational culture and discipline to build and maintain large projects in JavaScript.

As for security of intellectual property, there is really no good way to obfuscate or encrypt your code well enough to make it executable yet inaccessible. This applies specifically to anything you would deploy to users’ computer or run in a web browser. There are “minifiers,” “uglyfiers” and other obfuscation packages, but none of them will scramble your code enough to be ultimately unreadable. The reason for it is that your code needs to be readable in its original form by the interpreter at the time of execution. So while the obfuscation package can get rid of all spaces, carriage returns and tabs, turn local scope variables to one character names and generally make it look like a chunk of mess, it has to keep a lot of original elements in.

Strongly Typed vs. Dynamically Typed

Java – a strongly typed language – locks all of its variables into a particular type. If you define an object of a particular type or create a variable of a set primitive type, that variable is locked into its identity. You will know about any mismatches at compile time. You will not be able to produce byte codes or execute your code until you fix the issue. There is limited flexibility in this matter achieved through polymorphism and every class being automatically derived from an ominous Object class. That is still however very restrictive and a subject for a different conversation. There is a lot of value in this constraint as it forces good coding habits and requires that intentions align throughout any Java project.

The possible negative to this language feature is a good deal of ceremony around strong typing. Since new public methods and properties for any object need to be a part of a public interface you often have to define those elements throughout the inheritance tree. This complicates expansion of various object definitions throughout the development process. This makes prototyping harder and potentially slows down rapid development at the early stages of product creation.

Dynamic typing that is featured in JavaScript is a beast to face. On the one hand, it lets you build cities in the sky as you float through the air. It lets you define variables, data structures, objects, functions and arrays in line, at the place where you need them. This makes for some rather precarious looking code, but allows for everything to be put in place at the scene. You get to define the structure of an object right within your context. This is something that you are allowed to do and something that is frequently done; however it is not required by the language.

The primary downside of dynamic typing is uncertainty of what your variable actually contains at any given moment. You literally will not be able to tell for sure if a variable you are working with is pointing to a kitten, a whale, a bowl of petunias, or a house that you are actually looking for. If you assign the wrong content to variable somewhere else in the code, you will not discover it until a nonsensical line actually gets executed. Your code will only blow up when you will try to execute “open the door” just to realize that you are actually holding a kitten. At this point, it is kind of late to be informed that a kitten does not support the “open the door” method. There are many methods to remedy the situation. You can actually define specific types and check for those types as well as properties and functions related to particular objects before using them. That, however, adds an overhead that is freely handled by statically typed languages. You can also use TypeScript, which is a precompiled augmentation to JavaScript that introduces strong typing to the language and acts similarly to a compiler from that standpoint.

Object Oriented Programming

Both Java and JavaScript are object oriented languages. While Java necessitates use of objects throughout the codebase, JavaScript is considerably more forgiving, allowing for simple linear programming without the use of objects. Both languages allow for inheritance and polymorphism – the main staples of Object Oriented Design. JavaScript is quite a bit more awkward about it due to the dynamic nature of the language and a relatively complex syntax that is required to express such constructs.

Functional Programming

This is a very strong and interesting paradigm in software development that is elegantly supported in JavaScript. Functions in this language are the first-class citizens. They are treated like objects, can be passed into other functions and can carry member variables of their own if necessary. Having such flexibility allows for some very interesting solutions and design patterns that are only available to languages that support functional programming.

Java has its own, albeit limited, answer to functional programming. Java introduces lambdas in Java 1.8 (“Java 8”), which are a great powerful way to filter and manipulate collections of data. That being said the applicability of lambdas is very much restricted to data manipulation and does not step much beyond that.

Libraries and Frameworks

Many languages are defined by the suite of libraries that are available for them. Those libraries make or break the language, no matter the capabilities. The most elaborate, flexible and well thought-out language in the world pales in comparison to a language with wide support and braintrust.

On this subject matter, both of the languages are a pretty even match. Java had recently suffered a blow in the browser as Google dropped Java support from Chrome, citing lack of security. That being said, Java has a very strong presence in the device market – Android based and otherwise. Java has a very strong presence in server side web development, especially with Spring framework and specifically its MVC offering. JavaScript, however, comes in close on its tails with Node.js being a strong server side web solution and AngularJS coming in as a fully client side MVVM offering. Both of the languages carry strong support for the vast majority of data stores of every kind: SQL databases, NoSQL document stores, block data cloud stores, queues, etc. A variety of graphical libraries have been developed for Java and later ported to JavaScript like Processing that has been ported to p5.js with full featured support.

Developer’s Workflow

Development Environments

In addition to library support, Integrated Development Environments (IDEs) can make or break the language. A good IDE helps developers to rapidly traverse through the code base. It also has to have helpful assistants like Intellisense (inline lookup similar to Google suggested search terms), context highlighting, error highlighting (underline code that needs correction before it is compiled or sent for interpretation), and refactor assist tools.

Java has a good plethora of offerings such as Eclipse, NetBeans, and IntelliJ IDEA. Some of the tools are free while others are reasonably priced for the value that they offer. Just like Java, all of these tools run on a variety of platforms.

JavaScript is supported by most text editors, as well as the aforementioned IDEs. Text editors favored by the author are: Notepad ++ for PC, Sublime Text for Linux and Brackets for Mac. Many of these solutions support a way to host your JavaScript application, while others simply rely on Grunt to host your solution and update on file change. Excellent debugging tools are available in most popular web browsers with Google Chrome developer tools presently being in the lead and FireFox’s Firebug plugin following in close second.

Either one of these toolsets is very strong and full featured; however, Java has a bit better “canary in the coal mine” IDE warning support in part due to its strong typed nature. In addition, common JavaScript development toolset might prove to be challenging for a junior developer to configure and master from the onset.

Test Tools

Testing, and unit testing in particular, is a very strong and essential part of the software development process. In dynamically typed languages like JavaScript, unit testing can essentially take the place of compile time type checking. When all the functionality is properly exercised, it will let the developer quickly determine if she is trying to execute the “open the door” method on a kitten.

In the testing realm, JavaScript comes in strong with Jasmin, Mocha and QUnit. Other frameworks utilized by projects like AngularJS are Karma and Protractor.

Java sports a great deal of tools – many well-integrated with IDEs – which is great for test development. JUnit is one of those frameworks. You can review individual test results in a dedicated window in an IDE of your choice, and you can click through and debug each individual unit test. If configured with Maven, the system will also run all of your unit tests each time you compile your project.

Build and Delivery Automation

This toolset mostly comes at the final stages of software development cycle. It is of interest to developers as it governs portability of the code base between computers of various developers on the team as well as continuous testing and delivery of the software in the test and production environments.

Individual developers can enjoy Bower for library retrieval and Grunt for build management and execution on the JavaScript side. With some configuration, Bower will automatically pull new library packages for you if they were introduced to the project by other developers and you do not have them installed. Grunt will process your JavaScript and other resources into an execute folder, run obfuscation on your source code if necessary, and launch or refresh your content in a web server.

On the Java side, Maven will perform most of the aforementioned things. Maven integrates with most Java IDEs and makes developer’s lives considerably easier.

As for development and production server delivery, the majority of Continuous Integration tools will support both stacks seamlessly.

Conclusion

While you ultimately need to know both of the aforementioned stacks, you are better off starting with a strongly typed, compiled language that comes with an easy-to-configure, fully integrated IDE. Strong typing and compilation will let you focus on developing proper coding habits, while a mostly auto-configured development environment will get you writing, testing, running, and – most importantly – delivering your code quickly. Experience with JavaScript is unavoidable as you wander into web development, but it is healthier to start your growth as a software developer with a strong object-oriented foundation. Learn one of the foundational languages, then let your mind take you in any direction that you find interesting and exciting, because ultimately this is what it is all about.