The modern Web
The Web has changed a lot since HTML5 made its appearance. We are witnessing a gradual shift from a classic full server-side web development to a new architectural asset that moves much of the application logic to the client side.
The general objective is to deliver rich internet applications (RIA) with a desktop-like user experience. Think about web applications such as Gmail or Facebook. If you maximize your browser, they look like full desktop applications in terms of usability, UI effects, responsiveness, and richness.
Usually, solution architecture is quite simple, a rich and complex user interface on the client side, some application services on the server side. The technology scenario is also very straightforward. On the client side, HTML5, JavaScript, and CSS3 are the emerging options. They are replacing older plugin technologies such as Adobe Flash and Microsoft Silverlight. On the server side, HTTP RESTful services are widely adopted because of their implementation simplicity and standardization across a large variety of programming languages.
This is the main technology trend. Maybe it's not the best technological choice, but it has many advantages in terms of simplicity, integration, and user device penetration.
Widespread device diffusion is undoubtedly one of the most important key success factors of the magic trio, HTML5, JavaScript, and CSS3. In fact, we can assert that almost every device with a modern web browser (PC, tablet, or smartphone) is able to access and deliver an HTML5 application to the user.
In other words, this is why we are here. There are millions of devices out there that allow end users to access our web applications, and we need to assure a reliable interaction for them. Think about home banking web sites. If you access your bank account, you won't feel very comfortable if a money transfer fails because of an application defect. Maybe because developers forgot a critical data validation or didn't properly handle a remote service error, you don't know if your transfer has been accepted or not.
Web applications are growing in complexity, not just because of modern web technologies, but also because of marketing strategies, product placements, or simple market competition. In this scenario, tightly related to the visibility and reputation of a company, we cannot approve a delivery plan that doesn't provide some kind of testing strategy.
Once we establish that testing is a pillar of our solution, we need to understand which is the best way to proceed in terms of software architecture and development. In this regard, it's very important to determine the very basic design principles that allow a proper approach to unit testing. In fact, even though HTML5 is a recent achievement, HTML and JavaScript are technologies that have been in use for quite some time.
The problem here is that many developers tend to approach modern web development in the same old way. This is a grave mistake because back in time, client-side JavaScript development was a underrated and mostly confined to simple UI graphic management.
Client-side development is historically driven by libraries such as Prototype, jQuery, and Dojo, whose primary feature is DOM (HTML Document Object Model or HTML markup) management. They can work in small web applications, but as soon as these grow in complexity, the codebase starts to become unmanageable and unmaintainable. We can't think that we can continue to develop JavaScript in the same way we did 10 years ago. In those days, we only had to apply some of the UI transformations dynamically. Today, we have to deliver full working applications.
We need a better design, but most of all we need to reconsider the client-side JavaScript development and apply the advanced design patterns and principles.
Coming back to the context of this book, a new development approach is essential if one of our objectives is a testable codebase. In fact, once we decide that we want to test our solution, we need to write testable code.
Does this sound silly? Well… not at all. We can't simply say that we want to test our code. We must ensure that it is possible. Not all code is testable.
Roy Osherove in his book, The Art of Unit Testing, gives the following definition:
"A unit test is a piece of a code (usually a method) that invokes another piece of code and checks the correctness of some assumptions afterward. If the assumptions turn out to be wrong, the unit test has failed. A unit is a method or function."
Martin Fowler also writes about unit testing and the concept of isolation (http://martinfowler.com/bliki/UnitTest.html):
"A more important distinction is whether the unit you're testing should be isolated from its collaborators. Imagine you're testing an order class's price method. The price method needs to invoke some functions on the product and customer classes. If you follow the principle of collaborator isolation you don't want to use the real product or customer classes here, because a fault in the customer class would cause the order class's tests to fail. Instead you use TestDoubles for the collaborators."
These definitions of unit testing talk about code that verifies other code isolating individual parts of a program. It's clear that we need to provide at least these basic characteristics to our code if we want to test it. In this book, we are going to suggest some useful design principles, but we won't focus on software development methodologies (for example, Extreme Programming, Waterfall, Agile, and others).