Facebook Google Plus Twitter LinkedIn YouTube RSS Menu Search Resource - BlogResource - WebinarResource - ReportResource - Eventicons_066 icons_067icons_068icons_069icons_070

Conversational Kotlin: A Look at the Benefits of Readable Code

In the latest blog from [email protected], we explore how the goal of readable code can help engineering teams minimize errors and expedite software updates.

It’s probably a safe assumption that most software engineers, on multiple occasions, have opened an old code base and had to divine the intentions of the author. This can lead to much head-scratching (and, sometimes, mumbled expletives). But it doesn’t have to be that way, and a strong focus on code readability is the key.

Of all the qualities code can be judged on, readability may be the most important and the hardest to automate because evaluation is at least partially subjective. Consider the idea of pseudocode, an informal description of algorithmic rules that more closely resemble English than any particular programming language. It can be used to quickly discuss ideas and designs without needing specific syntax. Here’s an example for a simple algorithm to calculate the average test score for a class:

1 - Simple algorithm to calculate average class test score

Across all levels of technical skill, pseudocode is a generally well-understood, common language for describing how a problem can be solved. How closely actual code resembles pseudocode is one way to measure readability. Obviously, specific language syntax will impose some limits, or expose some freedoms. 

For those using the functional programming paradigm, the concept of point-free style (aka tacit programming) may be familiar. You might see some JavaScript like this in a video game store application:

2 - Sample JavaScript from video game store application

Composing functions without explicit arguments, so that the output of one is the implicit input of the next, can result in pleasantly readable code. In this article, I’d like to show an example of how Kotlin’s extension functions can facilitate the same improved readability.

We use Kotlin extensively at Tenable. Much of our product runs in the Java virtual machine (JVM), so interoperability with Java and Groovy were important. Kotlin is a more modern and concise language with numerous features at the language and compiler levels that make it preferable to its predecessors, yet still similar enough to Java that learning it is easy.

A Real-World Example: Normalizing Vulnerability Scan Results

Within Tenable.io, we do a lot of stream processing. The power of the tools we build for our customers comes directly from the data flowing through those streams. For the sake of this example, I will use the stream within Tenable.io which processes results from vulnerability scanners. A rough approximation of this workflow looks something like this:

Rough approximation of TenableIO stream processing

Each scan result contains information about the scan host which was discernible by the sensor, as shown here in an example from our hypothetical customer “Stark Industries”:

3 - Hypothetical scan result for Stark Industries

The goal of the scan normalization application consuming the stream of scan results is twofold. First, it provides the required data to downstream processors which build specialized data stores for APIs, dashboards and reports. Second, it limits resource demands by reducing the volume of data sent through the “pipeline.” To achieve those goals, the application needs to transform and aggregate the data in the input stream of scan results, then output a second stream of normalized scan host findings. 

For our application, there are a few relatively simple steps. As each item in the stream is processed, it is mapped from the data model of the input stream to the data model of the output stream. Whenever consecutive records appear in the stream for the same plugin, on the same port of the same scan host, they are grouped together. For each group of records (most of which are groups of one), a single record is compiled which contains the concatenated output of all the individual records in the group. If the final size of the output text is larger than 1MB, the output is stored externally, and the final item has its output value replaced with the URI of the stored resource.

Pseudocoding a simple algorithm design for the application might look something like this:

4 - Sample pseudocode for scan application

Improving Code Readability With Kotlin Extensions

At Tenable, we often use reactive programming. Continuing with the real-world example, you will see use of the Flux class, which is basically a streaming collection of records of the templated type. The first pass at implementing this logic without the use of extension functions looked something like this:

5 - Flux class logic for streaming record collection

Each function in the chain corresponds to one of the steps in the algorithm. The first step takes a stream of ScanResult records and outputs a stream of NormalizedHostFinding records. The second step buffers the stream and outputs a stream of pairs, where each pair consists of a key (including the common scan host, plugin, and port), and a collection of the NormalizedHostFinding records which have that key. The third step consumes that stream of pairs and again outputs a stream of single NormalizedHostFinding records by concatenating the output of all records in the collection. The last step outputs the same stream it received, sometimes moving the output to an external location before passing through the NormalizedHostFinding record.

The code above is not overly complex, but with the goal of improving readability, it could be refactored to appear more like the high-level pseudocode above. That can be achieved by introducing four extension functions, one for each step’s output stream type. Kotlin extensions are great as they allow you to add methods to a class without having to inherit or use design patterns such as Decorator:

6 - Snapshot of four Kotlin extensions

Adding these extensions then allows our main function to be rewritten as:

7 - Final view of readable streaming code

A noticeable improvement, and with not too much extra effort. In general, using descriptive names for functions instead of lambdas may seem like overkill, but can go a long way.

As I’m sure many can attest, digging into new code can be overwhelming. Sometimes, even our own code can seem foreign after too much time has passed. With readability as a goal instead of an afterthought, we can reduce barriers to productivity and even prevent mistakes due to misunderstandings.

Are you an engineer looking for your next career opportunity? Visit our Tenable Careers page to see which open engineering positions might be right for you.

Subscribe to the Tenable Blog

Subscribe
Try for Free Buy Now

Try Tenable.io

FREE FOR 30 DAYS

Enjoy full access to a modern, cloud-based vulnerability management platform that enables you to see and track all of your assets with unmatched accuracy. Sign up now.

Buy Tenable.io

Enjoy full access to a modern, cloud-based vulnerability management platform that enables you to see and track all of your assets with unmatched accuracy. Purchase your annual subscription today.

65 assets

Choose Your Subscription Option:

Buy Now
Try for Free Buy Now

Try Nessus Professional Free

FREE FOR 7 DAYS

Nessus® is the most comprehensive vulnerability scanner on the market today. Nessus Professional will help automate the vulnerability scanning process, save time in your compliance cycles and allow you to engage your IT team.

Buy Nessus Professional

Nessus® is the most comprehensive vulnerability scanner on the market today. Nessus Professional will help automate the vulnerability scanning process, save time in your compliance cycles and allow you to engage your IT team.

Buy a multi-year license and save. Add Advanced Support for access to phone, community and chat support 24 hours a day, 365 days a year. Full details here.

Try for Free Buy Now

Try Tenable.io Web Application Scanning

FREE FOR 30 DAYS

Enjoy full access to our latest web application scanning offering designed for modern applications as part of the Tenable.io platform. Safely scan your entire online portfolio for vulnerabilities with a high degree of accuracy without heavy manual effort or disruption to critical web applications. Sign up now.

Buy Tenable.io Web Application Scanning

Enjoy full access to a modern, cloud-based vulnerability management platform that enables you to see and track all of your assets with unmatched accuracy. Purchase your annual subscription today.

5 FQDNs

$3,578

Buy Now

Try for Free Contact Sales

Try Tenable.io Container Security

FREE FOR 30 DAYS

Enjoy full access to the only container security offering integrated into a vulnerability management platform. Monitor container images for vulnerabilities, malware and policy violations. Integrate with continuous integration and continuous deployment (CI/CD) systems to support DevOps practices, strengthen security and support enterprise policy compliance.

Buy Tenable.io Container Security

Tenable.io Container Security seamlessly and securely enables DevOps processes by providing visibility into the security of container images – including vulnerabilities, malware and policy violations – through integration with the build process.

Get a Demo of Tenable.sc

Please fill out the form below with your contact information and a sales representative will contact you shortly to schedule a demo. You may also include a short comment (limited to 255 characters). Please note that fields with asterisks (*) are mandatory.

Try for Free Contact Sales

Try Tenable Lumin

FREE FOR 30 DAYS

Visualize and explore your Cyber Exposure, track risk reduction over time and benchmark against your peers with Tenable Lumin.

Buy Tenable Lumin

Contact a Sales Representative to see how Lumin can help you gain insight across your entire organization and manage cyber risk.

Request a demo of Tenable.ot

Get the Operational Technology Security You Need.
Reduce the Risk You Don’t.