How RxJS works and why it matters

Posted on December 21st, 2020

For Java developers, JavaScript seems like an easy language to work with. It looks sort of like Java and just works. However, the more we work with JavaScript, the more complicated and convoluted it can become.

At some point your application will need to deal with events. The more events you have, the more code you’ll need to handle it. As the complexity increases, your code can start to look like a jungle of encasing curly braces. 

That’s just fun for anyone – especially for another dev that might end up working on it or even worse – future you in three months’ time.

This is where RxJS comes in. 

What is RxJS?

RxJS is an extremely popular JavaScript library that makes composing asynchronous and event-based programs easier through observable sequencing. What does this actually mean?

Let’s begin with the simple button click event.

Implementing RxJS observables

Consider a button. This button will get clicked on at some point to do something. The HTML looks something like this:

 <button type="button">click me</button>

The supporting JavaScript looks something like this:

 var button = document.querySelector('button');
 ​button
  .addEventListener('click',
                    (event) => console.log('it works'));

Though this looks simple, dealing with events can quickly become a minefield. You can abstract it out into its own function, but that creates more code. While it’s easy to say that we should be writing less to achieve clean and elegant code? The structures need to support it as well.

Vanilla JavaScript rarely achieves this, so RxJS is introduced. RxJS comes with an object called Observable. Within this Observable object, you can create a container for your ‘observing’ item. It then pipelines your item into a subscriber that does something when the conditions of the subscription are met.

For example, the equivalent of an addEventListener method in RxJS is fromEvent. The equivalent RxJS code for the JavaScript above can look something like this:

 var button = document.querySelector('button');
 ​
 Rx.Observable
  .fromEvent(button, 'click')
  .subscribe(event => console.log('clicked'))

Though this can look like more code, it clearly separates out the different parts of the logic. 

For example, if we wanted to prevent a click spam on our button and limit it to one accepted event every 2 seconds, in vanilla JavaScript it may look something like this:

 var button = document.querySelector('button');
 var rate = 2000;
 var lastClick = Date.now() - rate;
 ​
 button
  .addEventListener('click',
                    () => {
   if (Date.now() - lastClick >= rate){
     console.log('Clicked');
     lastClick = Date.now();
  }
 });

In this instance, you will need somewhere to set the rate, track the last click, and create the logic that will achieve your expected output. In contrast, if we wanted to achieve the same thing in RxJS, it would look something like this:

 var button = document.querySelector('button');
 ​
 Rx.Observable
  .fromEvent(button, 'click')
  .throttleTime(1000)
  .subscribe(event => console.log('Clicked'))

Despite having the same effect, the RxJS version is much clearer to understand. Why? because all the necessary information is structured in a funnel-like pipeline that guides you through a code story. This way you can read it in a linear fashion. So mentally it will make more sense than trying to track down the pieces and solve the mystery.

Unpacking RxJS event management

Generally speaking, RxJS is an event management system. This little-big JavaScript library reconfigures how you compose your code and groups logical data together to make it easier to mentally digest and trace.

By design, RxJS has a core type called an Observable object. This Observable has 4 main functions and they are creating, subscribing, executing and disposing of the observed thing.

Using the example previously displayed above, our thing is frontEvent(button, 'click'). Our button is the object we’re concerned with and the click is the instance event we want to target. subscribe is an object that executes the observable

For RxJS, subscribe is always required to be attached to an observable. You can also unsubscribe from an observable. This means you can cancel any ongoing observable executions instigated by subscribe.

For example, you might have something that calls an external API every 10 seconds for updates but you want this to stop when a user clicks on a button. You can do this by attaching unsubscribe to the observable.

Observers

An observer is a set of callbacks that tracks the progress of the delivered values by the observable. It lets you decide what happens during each state and what to do if an error occurs. These progress updates are called notifications and they are next, error, and complete. An RxJS observer object usually looks something like this:

 const observer = {
  next: x => console.log('Observer got a next value: ' + x),
  error: err => console.error('Observer got an error: ' + err),
  complete: () => console.log('Observer got a complete notification'),
 };

You can put whatever you want as your logic in place of console.log(). Using the observer can look something like this:

 observable.subscribe(observer);

Operators

RxJS operators are functions that let you do something to the value passed through by the observable before it gets subscribed. In our RxJS example in the previous section, throttleTime() is an example of an operator. It lets you add a condition to the observed event.

However, this isn’t the only operator available.

In RxJS, observable isn’t the only Observable type. A Subject is a special type of Observable that lets you multicast several Observables at the same time. In order to do this, you subscribe to the same subject as many times as you want to create multiple instances of the Observable inside the subject.

For example, inside your app, you might have something like this:

 ...
 import { Subject } from 'rxjs';
 ...
 ​
 const subjectExample = new Subject<number>();
 subjectExample.subscribe({
  next: (v) => console.log(`cat goes: ${v}`)
 });
 subjectExample.subscribe({
  next: (v) => console.log(`dog goes: ${v}`)
 });
 subject.next('meow');
 subject.next('woof');
 // Logs:
 // cat goes: meow
 // dog goes: meow
 // cat goes: woof
 // dog goes: woof

In the code above, you’ve called the single subject that contains two observable objects.

Scheduler

An RxJS scheduler controls when a subscription starts, and when notifications get delivered. It’s similar to a store of queued tasks based on priorities. It also gives your subscriber an execution context that lets the subscriber know when it’s time to execute its code. 

For example, you might want to wait for another callback or things like animation frames to complete before moving onto the next part of the code.

The scheduler runs on a virtual clock and you can set it to begin the subscription right away by using .now().

Who needs RxJS?

Why does using RxJS matter for your code? It’s because reading code shouldn’t be akin to figuring out a mystery novel. It is one of the reasons RxJS is also heavily used in Angular. If you are using the framework by Google, understanding how RxJS works can also help you uncover Angular’s event handling strengths.

The major advantage of using RxJS is that it lets you control the event flows through what you assign to the observable. The library comes with an extensive set of pre-made operators that you can instantly use, cutting down on the time needed to manually write out each logical step required to achieve a particular effect.

RxJS cuts down on the amount of code you need to write whilst simplifying the process significantly through pre-made and bite-sized operators. It also creates a clear and predictable structure to how events are handled, leaving little room for rogue code to slip through, especially during testing.

Groovy Script 101: Commonly used syntax reference guide

Posted on December 9th, 2020

Groovy has been around on the Java scene since 2003. With over a decade’s worth of history, development and experience, it is a Java syntax compatible object oriented programming language that compiles into JVM bytecode.

In a way, Groovy can be viewed as a flavor of Java without being actual Java. This is because it works on the Java platform in a native capacity. Because of the way it works, it interoperates nicely with Java code and its associated libraries. Most valid Java code also translates to valid Groovy code.

Groovy is designed to be both a programming and scripting language. This means that unlike Java, which needs to be compiled, Groovy can be used in conjunction to provide on the spot programmatic processes that doesn’t require a lot of server side heavy-lifting.

Constraints are Groovy. Java is my bread-n-butter, but when… | by Marko  Milicevic | Medium

The biggest difference between Groovy and Java code is that Groovy is more compact, with less syntax requirements and therefore making it appealing to many developers. It also means that many Java developers going into Groovy will find the process of picking it up super simple. Why? Because fundamentally, most object-oriented based programming languages tend to follow the same ideas. This shared ideology makes it easy for developers to jump between Java and Groovy.

This piece will go over how to do 7 most common things that we encounter when writing code. They are the foundation and general building blocks of any program and often crop up in some form within an object-oriented based thinking.

1. Installing Groovy

You can install Groovy via your package manager. Alternatively, you can install groovy from their website.

Groovy files are saved with .groovy extension.

To execute files in the command line, you can do so using groovy. For example:

 groovy index.groovy

To run Groovy Shell, you groovysh in the command line.

2. List and maps

A list is also commonly known as an array. It stores objects sequentially and can be accessed via integer indices. In Groovy, a list looks something like this:

 def shoppingList = ["flour", "eggs", "banana", "bread"]
 ​
 println shopingList[2]
 //will give "banana"
 ​
 shoppingList.remove("flour")
 shoppingList.add("milk")
 ​
 println shoppingList[2]
 //will give bread

A map holds a key-pair value based list where you can attach data to a custom named key. Rather than calling values based on integer based keys, this lets you use the custom named key instead.

 def productDetails = [
  "name": "banana",
  "type": "fruit",
  "price": 2.99,
  "unit": "kg",
  "color": "yellow"
 ]
 ​
 println productDetails["name"];
 ​
 productDetails["price"] = 5.99

We can also add lists into maps like this:

 def toDoList = [
  "monday": ["water plants", "laundry"],
  "tuesday": ["assignment due", "feed cat"]
 ]
 ​
 toDoList['wednesday'] = ["clean kitchen", "get groceries"]
 ​
 println toDoList['wenesday'][1]

3. Conditionals

The most basic conditionals are if else statements. The result is a boolean that determines which block of code to execute next. An if else statement in Groovy looks like this:

 def myString = "I am allergic to cats."
 ​
 if(myString.contains("allergic")){
    println myString
 } else {
    println "all clear!"
 }

You can also do the expressions that evaluates to a boolean within the if statement. For example:

 def myString = "I am allergic to cats."
 ​
 if(myString.contains("allergic") && myString.contains("cats")){
    println myString
 } else {
    println "all clear!"
 }

&& and || operators are conditionals known as ‘and’ and ‘or’. The statement needs to evaluate to true in order to proceed, or it goes down to the else block.

Another condition you can use to give your if else statement options beyond just the two is to use the else if option.

For example:

 def myString = "I am allergic to cats."
 ​
 if(myString.contains("allergic") && myString.contains("cats")){
    println "ahchooo! blasted cats!"
 } else if(myString.contains("allergic") && myString.contains("dogs")){
    println "oh no! not dogs!"
 } else{
    println "all clear!"
 }

4. Loops

A loop is a set of code that we want to repeat under certain circumstances. Three common types of loops are: while, collection iteration, and recursion.

Let’s begin with the first of the three: the while loop.

A while loop runs through a set of execution statements until the condition is satisfied. It accepts an argument to determine the validity of the boolean evaluation.

Writing a while loop in Groovy looks something like this:

 def counter = 0;
 ​
 while(counter < 10){
  counter = counter +1
  println "just counting..." + counter
 }
 ​
 println "all done!"

A collection iteration is when you work through a list, iterating it until the list is exhausted. To do this, you use the each method like this:

 def children = ["James", "Albus", "Lily"];
 ​
 println "The children's names are:"
 children.each { child ->
    println child
 }

You can also iterate through maps like this:

 def families = [
  "Potter": ["James", "Albus", "Lily"],
  "Weasley": ["Rose", "Hugo"],
  "Lupin": ["Edward"]
 ]
 ​
 families.each{ family, child ->
  println "The children of the " + family + " family are " + children.join(', ')
 }

And finally, we have recursions. A recursion is a function that calls itself when the conditions are met. For example, here is a function that calls itself.

 def fibonnaci(n) {
  if(n <= 2) {
    return 1
  } else {
    return fibonnaci(n - 1) + fibonnaci(n - 2)
  }
 }
 ​
 println fibonnaci(4)
 println fibonnaci(5)

5. Writing JSON

You can write lists and do things to it. But what we really want is to turn this data into something more universally accessible – that is, make it into valid JSON.

Groovy includes simple classes for writing to JSON. All you have to do is import JsonBuilder and use on the list map you want to transform.

 import groovy.json.JsonBuilder
 ​
 def families = [
  "Potter": ["James", "Albus", "Lily"],
  "Weasley": ["Rose", "Hugo"],
  "Lupin": ["Edward"]
 ]
 ​
 new File('familyMembers.json') << new JsonBuilder(families).toPrettyString()

The new File() will create a new file object that we assign our transformed families JSON to.

6. Reading JSON

JSON is the most popular method of moving structured data between different applications and networks. Let’s pretend we get given a JSON file containing all a giant list of inventory information.

 import groovy.json.*
 ​
 def inventoryListFile = new File('products.json')
 def inventory = new JsonSlurper().parseText(inventoryListFile.text)
 ​
 println inventory['banana']

The JsonSlurper lets you create a new instance and parseText method allows you to pass texts into your file, allowing you to modify and do what you want with the data set.

7. HTTP requests

An isolated application that doesn’t communicate with anything isn’t much use in this day and age. there’s a lot of data that gets transferred over the Internet and to do this, we need the ability to create HTTP requests.

Here’s a scaffold of how you’d write it.

 @Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7' )
 ​
 import groovyx.net.http.HTTPBuilder
 import groovy.json.JsonBuilder
 ​
 new HTTPBuilder('https://en.wikipedia.org/w/api.php').get(
   'query': [
     'action': 'opensearch',
     'search': 'Harry Potter'
  ]
 ) { resp, json ->
   if(resp.status == 200) {
     def responseFile = new File('potter.json')
     responseFile.text =  new JsonBuilder(json).toPrettyString()
  } else {
     println 'Uh oh. Something went wrong:('
  }
 }

Final thoughts

I hope you found this reference helpful. It’s a quick cheat sheet style list of commonly used things you’d find in programming, but in a Groovy flavor.

If you’re coming from a Java background, everything should feel almost at home. If you’re coming from a JavaScript environment, the elements of Groovy are generally identifiable.

The fundamentals of programming are still the same, no matter where you go. Most of the time, once you learn one language, the ideas are transferable and all you have to do is learn the syntax.

From what you can see above, the ideas are mostly the same. So in theory, you can potentially close your eyes and pretend it’s Java or JavaScript but with a few differences in syntax and how certain things are run.

But for the scope of this piece, the content presented here should be enough to get you started on your next Groovy based project.

Unit testing vs. integration testing

Posted on December 1st, 2020

It’s hard to understate the importance of testing in software development. In fact, testing products before release is critical no matter what type of product you’re developing. No one wants a defective product, no matter how feature-rich or innovative. And no one wants to be woken in the middle of the night to fix a line of code that just cost the organization thousands.

So it’s no wonder that there are countless methodologies and approaches to testing and quality assurance of products and services. When it comes to software testing, having a well-planned and thorough testing strategy throughout the software development cycle is important

Why software testing matters

Though many prefer the “code fast, break things” approach, having a testing strategy and process are something you should develop and adopt long before your software meets the clumsy hands of end-users. This is especially true when the development of a single piece of software is divided among numerous developers or teams of developers.

Making sure it all works in tandem without any components breaking the functionality of others apart is no easy task. It requires different kinds of tests, performed by different stake-holders in the process at different stages of development.

Two of the most commonly used types of tests used in software development today are unit tests and integration tests.

In this post, we’ll define what each is, who is responsible for it, how it is performed and when. In addition, we’ll compare the two side-by-side and discuss the importance of using both.

What is unit testing?

Unit testing is a type of software testing that is applied to individual units of code, also known as modules or components. Unit tests are usually written and conducted by developers to ensure the code functions as expected and is ready to be included in the project codebase. They are the first tests to be run on any code throughout the development lifecycle.

Fairly basic and narrow, unit tests do not take into account any dependencies like database, network or other software components. Since unit testing only checks for basic functionality, then nonfunctional and coverage issues, bugs are never logged. Instead, they are fixed by the developer before ever getting near the codebase.

Why do you need to perform unit testing

Testing each function, procedure, component and method individually may sound like a hassle. However, it helps to reduce the costs of bug fixes later on. Not only does it help prevent bugs in the software codebase, but it also promotes good coding hygiene. By running unit tests, developers can learn from their mistakes almost immediately.

Moreover, since it is the very first level of testing? Having good unit tests leads to a significant reduction in time and effort needed from developers and testers to find and fix bugs down the road to production. The sooner you catch bugs – the better. And this is the earliest test that can.

What is integration testing?

Integration testing is a type of software testing that is intended to check and verify that different modules and components of the software work together as expected when combined. Integration tests are traditionally performed by testers using test stubs and test drivers.

Complex and fairly difficult to set up (in most cases), integration tests aim to locate and expose errors and issues in the interaction and integration of code modules. These modules, that were individually tested through unit tests previously, are then checked for faults in integration between them.

In integration testing, the code is tested using real dependencies like hardware, network, database and others. Issues encountered are then logged as bugs.

Why you need to perform integration testing

Being as complex and tricky as it is to test compatibility between multiple components, it’s almost unavoidable. The product you deliver is not just a collection of functions and variable names that compile. You’re creating a system or application that needs to work in a holistic way, without any hidden hindrances.

A single function or component may work just fine as a unit in testing. However, running integration tests can help you uncover numerous bugs that result from incompatibility between components that work just fine on their own. Such issues include data exchange bottlenecks, erroneous function calling and unexpected hardware issues on user devices.

Unit testing vs integration testing: side by side comparison

To better understand the similarities and differences, let’s look at unit testing and integration testing side by side.

Unit testingIntegration testing
FunctionalityTesting a single component (unit) for bugsTesting interoperability between multiple components (units)
TargetModulesInterfaces
Owner / conductorDeveloper writing the codeTester
SpeedQuickSlow
ComplexityLowHigh
Scope & dependenciesNarrow scope, ignoring external dependenciesBroad scope, considering all relevant external dependencies
MaintenanceLowHigh
Stage in development lifecycleEarly – as soon as a piece of code is completedPerformed after individual units are tested, and before testing the system in full (system testing)
Code proficiency requiredHighMedium
CostLowHigh
TypesSingle typeDivided into different types: Top-down Integration, Bottom-Up Integration, etc.

Why you need to perform both unit testing and integration testing

Consider a puzzle. No matter how perfectly polished and accurately cut each piece is, if they don’t fit together as expected and intended, they are worthless. On the other hand, poorly printed or cut (or missing) pieces will leave you with an incomplete creation as well.

When it comes to software development operations? Understanding and employing the various tests in the development lifecycle is key to an efficient and headache-free DevOps experience.

So as you orchestrate the phases of testing and quality assurance through your CI/CD pipelines, remember that at the end of the day, you’re the one putting the puzzle together for deployment to end users.