Go Pattern: Sorting a slice on multiple keys

Hi 👋

In this article I want to highlight a simple pattern for sorting a slice in Go on multiple keys.

Given the following structure, let’s say we want to sort it in ascending order after Version, Generation and Time.

type TheStruct struct {
	Generation int
	Time       int
	Version    int
}

The way we sort slices in Go is by using the sort interface or one of the sort.Slice functions. To sort the slice after the above criteria we’ll call slice.Sort with the following function.

	sort.Slice(structs, func(i, j int) bool {
		iv, jv := structs[i], structs[j]
		switch {
		case iv.Version != jv.Version:
			return iv.Version < jv.Version
		case iv.Generation != jv.Generation:
			return iv.Generation < jv.Generation
		default:
			return iv.Time < jv.Time
		}
	})

The slice will be sorted after the following fields: Version, Generation and Time. The trick is the switch statement and the case expression case iv.Version != jv.Version followed by the statement return iv.Version < jv.Version.

You can use this pattern whenever you want to sort slices over multiple fields in Go.

Thanks for reading! 🍻

Source Code

package main

import (
	"fmt"
	"sort"
)

type TheStruct struct {
	Generation int
	Time       int
	Version    int
}

func main() {
	var structs = []TheStruct{
		{
			Generation: 1,
			Time:       150,
			Version:    0,
		},
		{
			Generation: 1,
			Time:       200,
			Version:    0,
		},
		{
			Generation: 1,
			Time:       200,
			Version:    2,
		},
		{
			Generation: 1,
			Time:       500,
			Version:    0,
		},
		{
			Generation: 1,
			Time:       100,
			Version:    0,
		},
		{
			Generation: 1,
			Time:       400,
			Version:    0,
		},
		{
			Generation: 2,
			Time:       400,
			Version:    0,
		},
		{
			Generation: 2,
			Time:       100,
			Version:    2,
		},
		{
			Generation: 1,
			Time:       300,
			Version:    0,
		},
	}

	fmt.Printf("%v\n", structs)

	sort.Slice(structs, func(i, j int) bool {
		iv, jv := structs[i], structs[j]
		switch {
		case iv.Version != jv.Version:
			return iv.Version < jv.Version
		case iv.Generation != jv.Generation:
			return iv.Generation < jv.Generation
		default:
			return iv.Time < jv.Time
		}
	})
	fmt.Printf("%v\n", structs)

}

Output

[{1 150 0} {1 200 0} {1 200 2} {1 500 0} {1 100 0} {1 400 0} {2 400 0} {2 100 2} {1 300 0}]
[{1 100 0} {1 150 0} {1 200 0} {1 300 0} {1 400 0} {1 500 0} {2 400 0} {1 200 2} {2 100 2}]

Also, special thanks to RP.💖

How I got my PR merged into Apache Flink

Hi 👋

This is a short story on how I got my pull request merged into Apache Flink.

It started with the need to set CPU and Memory limits to Flink jobs running under Kubernetes.

The first thing I did was to join the user mailing list and ask around if someone has encountered the issue and if there’s a solution to it. The people from the mailing list were very friendly and they pointed me to an existing ticket on the Flink jira board, which was exactly what I needed.

To speed things up, I decided to implement the ticket by myself. I wrote on the mailing list that I want to implement FLINK-15648 and started signing the Apache individual contributor license agreement.

After sending the signed document via email, I cloned the Flink project from GitHub and imported it into my IntelliJ IDE. Flink has some great documentation on how to setup your IDE and import the project.

Lastly, I’ve implemented the feature and submitted the PR flink/pull/17098. The first time I forgot to generate the code docs and I’ve got a CI error. After the error was fixed, the PR was merged. It did not speed things up as I initially thought since it was merged into Flink 1.15. Nonetheless, It was a smooth and fun process and the code review that I’ve received was also well done.

I hope your experience contributing to open-source software will be as fun as mine was.

Thanks for reading and happy hacking!

Constructor Injection and Null Object Design Patterns

The Constructor Injection design pattern is a pattern that helps you declare all the required dependencies of a class in it’s constructor.

This is useful because it helps you decouple the code, you can specify an interface instead of a concrete type, remember, program to an interface.

Also, in the constructor it is easier to guard against null objects. The calling code doesn’t have to worry about null exceptions every time it uses a dependency.

Avoid providing defaults when using this pattern, as this will couple the code with a concrete type. When a dependency is not needed, use the Null Object pattern.

We’re going to pickup from the last article and show you how you can modify the application to use the constructor injection and null object design patterns.

The class graph will look like this:

In order to demonstrate this pattern I will introduce a new class MessageTranslator.

class MessageTranslator:
    def __init__(self, translator: Translator, printer: Printer):
        if not translator:
            raise ValueError("Translator cannot be None.")
        if not printer:
            raise ValueError("Printer cannot be None.")

        self._translator = translator
        self._printer = printer

    def translate(self, message):
        return self._translator.translate(message)

    def print(self, message):
        self._printer.print(message)

And modify the Application code to use it:

class Application:
    def __init__(self):
        self._input_listener: InputListener = ConsoleInputListener("< ")

    def start(self):
        print("starting application.")
        message_translator = MessageTranslator(RomanianTranslator(), ConsolePrinter(">"))
        while True:
            user_in = Message(self._input_listener.get_input())
            if str(user_in) == "exit":
                exit(0)

            translated_message = message_translator.translate(user_in)
            message_translator.print(translated_message)

That’s it! You’ve used the constructor injection pattern.

Now, if don’t want to print the translated message into the console we can’t just pass a null Printer, that would raise an exception.

We need use the null object pattern to implement a Printer that does nothing.

class VoidPrinter(Printer):
    def print(self, message):
        pass

If we modify the Application code to use our VoidPrinter, the output would be:

starting application.
 < hello Dev
 < 

Thanks for reading! As always, the full code can be found on my Github.

Composition Root Pattern: How to Write Modular Software

The composition root is a design pattern which helps you structure a software application by implementing a class that builds all the other classes.

In this example we will examine this pattern in Python.

Here’s the object graph of the classes that we’re going to implement:

I have designed a sample application that we’re going to use. It contains three components: ConsoleInputListener, ConsolePrinter and RomanianTranslator and a value object class: Message.

The classes are described as follows:

  • Application: The composition root, glues all the classes together.
  • ConsoleInputListener: Component, it reads string from the standard input.
  • ConsolePrinter: Component, it prints to the standard output.
  • RomanianTranslator: Component, it translates English words to Romanian.
  • Message: Value object, it encapsulates the message string.

Program to an interface not an implementation

Before implementing the Application component, I’m going to define the interfaces for the ConsoleInputListener, ConsolePrinter and RomanianTranslator. I’m going to call them InputListener, Printer and Translator for simplicity.

The reason I’m defining interfaces* is because I want to be able to swap the objects that the Application class references. In Python variables don’t constrain me to any type, but if I’m going to implement other objects, I’d like to have a template so it will help me reduce the number of mistakes that I can make.

Python doesn’t have support for interfaces so I’m going to use abstract classes:

class Printer(metaclass=abc.ABCMeta):
    def print(self, message):
        raise NotImplementedError("print is not implemented")

class InputListener(metaclass=abc.ABCMeta):
    def get_input(self) -> str:
        raise NotImplementedError("get_input is not implemented!")

class Translator(metaclass=abc.ABCMeta):
    def translate(self, message: Message) -> Message:
        raise NotImplementedError("translate must be implemented!")

Every class that extends my abstract classes must implement it’s abstract methods:

class ConsolePrinter(Printer):
    def __init__(self, prefix: str):
        self._prefix = prefix

    def print(self, message: Message):
        print(self._prefix, message)

class ConsoleInputListener(InputListener):
    def __init__(self, prompt: str):
        self._prompt = prompt

    def get_input(self) -> str:
        return input(self._prompt)

class RomanianTranslator(Translator):
    def translate(self, message: Message) -> Message:
        words_map = {"hello": "salut"}
        message_words = str(message).split(" ")

        for index, word in enumerate(message_words):
            if word.lower() in words_map.keys():
                message_words[index] = words_map[word]

        return Message(" ".join(message_words))

The Message class, for the sake of completeness only holds a string.

class Message:
    def __init__(self, message):
        self._message = message

    def __str__(self):
        return self._message

And finally, the Application class will glue all the components together and instantiate them:

from input_listener import InputListener, ConsoleInputListener
from message import Message
from printer import Printer, ConsolePrinter
from translator import Translator, RomanianTranslator


class Application:
    def __init__(self):
        self._printer: Printer = ConsolePrinter(">")
        self._translator: Translator = RomanianTranslator()
        self._input_listener: InputListener = ConsoleInputListener("< ")

    def start(self):
        print("starting application.")
        while True:
            user_in = Message(self._input_listener.get_input())
            if str(user_in) == "exit":
                exit(0)

            self._printer.print(self._translator.translate(user_in))

The main method will just run the Application:

from application import Application


def main():
    app = Application()
    app.start()


if __name__ == '__main__':
    main()

Running the application would output:

 starting application.
 < hello Denis!
 > salut Denis! 

Now, most real world applications aren’t this simple, the reason we went through all this code in order to implement a simple hello world is the following: Imagine that you have 10 translators: English, French, German… and two Printers: Console and File.

You could modify the application code to take in two parameters: translator and printer use the arguments to instantiate the correct translator and printer without needing to change the other classes. You can add as many printers, translators and input listeners as you wish. That’s a huge benefit.

If you were to inline all the code in a single class, adding more translations and more printing options would have been very painful and frustrating.

I hope my article gave you some insight into the Composition Root pattern, if I made any mistake please feel free to correct me. 🙂

The full code is on my Github.

Thanks for reading!