Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Hands-On Design Patterns with Kotlin
Hands-On Design Patterns with Kotlin

Hands-On Design Patterns with Kotlin: Build scalable applications using traditional, reactive, and concurrent design patterns in Kotlin

By Alexey Soshin
€28.99 €19.99
Book Jun 2018 310 pages 1st Edition
eBook
€28.99 €19.99
Print
€37.99
Subscription
€14.99 Monthly
eBook
€28.99 €19.99
Print
€37.99
Subscription
€14.99 Monthly

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now

Product Details


Publication date : Jun 15, 2018
Length 310 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781788998017
Vendor :
JetBrains
Category :
Table of content icon View table of contents Preview book icon Preview Book

Hands-On Design Patterns with Kotlin

Getting Started with Kotlin

In this chapter, we'll cover basic Kotlin syntax, and discuss what design patterns are good for and why they should be used in Kotlin.

The goal of this chapter is not to cover the entire language vocabulary, but to get you familiar with some basic concepts and idioms. The following chapters will slowly expose you to more language features as they become relevant to the design patterns we'll discuss.

In this chapter, we will cover the following topics:

  • Basic language syntax and features
  • Introduction to design patterns

Basic language syntax and features

Whether you come from Java, C#, Scala or any other statically typed programming language, you'll find Kotlin syntax quite familiar. This is not by coincidence, but to make the transfer to this new language as smooth as possible for those with previous experience in other languages. Besides that familiarity, Kotlin brings a vast amount of features, such as better type safety. As we move ahead, you'll notice that all of them are attempting to solve real-world problems. That pragmatic approach is very consistent across the language. For example, one of the strongest sides of Kotlin is complete Java interoperability. You can have Java and Kotlin classes alongside each other, and freely use any library that is available in Java for a Kotlin project.

To summarize, the goals of language are as follows:

  • Pragmatism
  • Having clear syntax
  • Being type-safe
  • Interoperability

The first chapter will discuss how these goals are achieved.

Multi-paradigm

Some of the major paradigms in programming languages are procedural, object-oriented, and functional paradigms.

Being practical, Kotlin allows for any of these paradigms. It has classes and inheritance, coming from the object-oriented approach. It has higher-order functions from functional programming. But you don't have to wrap everything in classes if you don't want to. You can structure your entire code as just a set of procedures and structs. You will see how all these approaches come together, as different examples will use different paradigms to solve the problems discussed.

Code structure

The first thing you'll need to do when you start programming in Kotlin is create a new file. Kotlin's extension is usually .kt.

Unlike Java, there's no strong relationship between the filename and class name. You can put as many public classes in your file as you want, as long as the classes are related to one another and your file doesn't grow too long to read.

No semicolons

In Java, every line of code must be terminated with a semicolon:

System.out.println("Hello"); //<- This is a semicolon
System.out.println("World"); //<- I still see you, semicolon

But Kotlin is a pragmatic language. So, instead, it infers during compilation where it should put the semicolons:

println("Hello") //<- No semicolon here
println("World") //<- Not here

Most of the time, you won't need to put semicolons in your code. They're considered optional.

Naming conventions

As a convention, if your file contains a single class, name your file the same as your class.

If your file contains more than one class, then the filename should describe the common purpose of those classes. Use CamelCase when naming your files, as per the Kotlin Coding Conventions: https://kotlinlang.org/docs/reference/coding-conventions.html#naming-rules.

Actually, you don't have to write your code in a file for simple snippets. You can also play with the language online: try http://kotlinlang.org/ or use REPL and interactive shell after installing Kotlin and running kotlinc.

Packages

It wouldn't be convenient to have all your classes and functions in the same folder or under the same namespace. That's the reason Kotlin, similar to many other languages, uses the notion of a package.

Like Java, Kotlin uses packages:

package me.soshin.controllers

If you're mixing Java and Kotlin, Kotlin files should follow Java package rules.

In purely Kotlin projects, common package prefixes can be omitted from the folder structure. For example, if all your projects are under the me.soshin package, place your controllers in the /controllers folder and not in the /me/soshin/controllers folder like Java does.

Types

We'll start with the Kotlin type system, and compare it to what Java provides.

The Java examples are for familiarity, and not to prove that Kotlin is superior to Java in any way.

Type inference

Let's define a simple string in Java:

String s = "Hello World";

We defined that s is of type String. But why? Isn't it obvious at this point?

Kotlin provides us with type inference:

val s = "Hello World"

Now, the compiler will decide what type of variable should be used. Unlike interpreted languages (such as JavaScript, Groovy, or Ruby), the type of variable is defined only once. This will not work:

var s = "I'm a string"
s = 1 // s is a String

You may wonder why we've used one var and one val to define the variables. We'll explain it shortly.

val versus var

In Java, variables can be declared final. Final variables can be assigned only once:

final String s = "Hi";
s = "Bye"; // Doesn't work

Kotlin urges you to use immutable data as much as possible. Final variables in Kotlin are simply val:

val s = "Hi"
s = "Bye" // Doesn't work

If you do have a case in which you would like to reassign a variable, use var instead:

var s = "Hi"
s = "Bye" // Works now

Comparison

We were taught very early in Java that comparing objects using == won't produce the expected results, since it tests for reference equality, and we need to use equals() for that.

JVM does string interning to prevent that in some basic cases, so for the sake of the example we'll use new String() to avoid that:

String s1 = "ABC";
String s2 = new String(s1);

System.out.println(s1 == s2); // false

Kotlin translates == to equals():

val s1 = "ABC"
val s2 = String(s1.toCharArray())

println(s1 == s2) // true

If you do want to check for reference equality, use ===:

println(s1 === s2) // false

Null safety

Probably the most notorious exception in the Java world is NullPointerException.

The reason behind this exception is that every object in Java can be null. The code here shows us why:

String s = "Hello";
...
s = null;
System.out.println(s.length); // Causes NullPointerException

In this case, marking s as final would prevent the exception.

But what about this one:

public class Printer {    
public static void printLength(final String s) {
System.out.println(s.length);
}
}

From anywhere in the code it's still possible to pass null:

Printer.printLength(null); // Again, NullPointerException

Since Java 8, there's been an optional construct:

if (optional.isPresent()) {
System.out.println(optional.get());
}

In a more functional style:

optional.ifPresent(System.out::println);

But... it doesn't solve our problem. We can still pass null instead of the proper Optional.empty() and crash the program.

Kotlin checks it even earlier—during compile time:

val s : String = null // Won't compile

Let's go back to our printLength() function:

fun printLength(s: String) {
println(s.length)
}

Calling this function with null won't compile any more:

printLength(null) // Null can not be a value of a non-null type String

If you specifically want your type to be able to receive nulls, you'll need to mark it as nullable using the question mark:

val notSoSafe : String? = null

Declaring functions

Everything is an object in Java. If you have a method that doesn't rely on any state, it still must be wrapped by a class. You're probably familiar with a lot of Util classes in Java that only have static methods, and their only purpose is to satisfy the language requirements and bundle those methods together.

In Kotlin, a function can be declared outside of a class instead of the following code:

public class MyFirstClass {

public static void main(String[] args) {
System.out.println("Hello world");
}
}

It's enough to have:

fun main(args: Array<String>) {
println("Hello, world!")
}

Functions declared outside of any class are already static.

Many examples in this book assume that the code we provide is wrapped in the main function. If you don't see a signature of the function, it probably should be:
fun main(args: Array<String>).

The keyword to declare a function is fun. The argument type comes after the argument name, and not before. And if the function doesn't return anything, the return type can be omitted completely.

What if you do want to declare the return type? Again, it will come after the function declaration:

fun getGreeting(): String {
return "Hello, world!"
}

fun main(args: Array<String>) {
println(getGreeting())
}

There are lots of other topics regarding function declarations, such as default and named arguments, default parameters, and variable numbers of arguments. We'll introduce them in the following chapters, with relevant examples.

Control flow

One could say that control flow is the bread and butter of writing programs. We'll start with two conditional expressions: if and when.

Using the if expression

Previously it was noted that Kotin likes variables to be assigned only once. And it also doesn't like nulls so much. You probably wondered how that would ever work out in the real world. In Java, constructs such as this are quite common:

public String getUnixSocketPolling(boolean isBsd) {
String value = null;
if (isBsd) {
value = "kqueue";
}
else {
value = "epoll";
}

return value;
}

Of course, this is an oversimplified situation, but still, you have a variable that at some point absolutely must be null, right?

In Java, if is just a statement and doesn't return anything. On the contrary, in Kotlin, if is an expression, meaning it returns a value:

fun getUnixSocketPolling(isBsd : Boolean) : String {
val value = if (isBsd) {
"kqueue"
} else {
"epoll"
}
return value
}

If you are familiar with Java, you can easily read this code. This function receives a Boolean (which cannot be null), and returns a string (and never a null). But since it is an expression, it can return a result. And the result is assigned to our variable only once.

We can simplify it even further:

  1. The return type could be inferred
  2. The return as the last line can be omitted
  3. A simple if expression can be written in one line

So, our final result in Kotlin will look like this:

fun getUnixSocketPolling(isBsd : Boolean) = if (isBsd) "kqueue" else "epoll"

Single line functions in Kotlin are very cool and pragmatic. But you should make sure that somebody else other than you can understand what they do. Use with care.

Using the when expression

What if (no pun intended) we want to have more conditions in our if statement?

In Java, we use the switch statement. In Kotlin, there's a when expression, which is a lot more powerful, since it can embed some other Kotlin features.

Let's create a method that's based on the amount of money that will give cause to suggest a nice birthday gift:

fun suggestGift(amount : Int) : String {
return when (amount) {
in (0..10) -> "a book"
in (10..100) -> "a guitar"
else -> if (amount < 0) "no gift" else "anything!"
}
}

As you can see, when also supports a range of values. The default case is covered by the else block. In the following examples, we will elaborate on even more powerful ways to use this expression.

As a general rule, use when if you have more than two conditions. Use if for simple checks.

String interpolation

What if we would like to actually print those results?

First, as you may have already noticed, in one of the examples above, Kotlin provides a nifty println() standard function that wraps the bulkier System.out.println() from Java.

But, more importantly, as in many other modern languages, Kotlin supports string interpolation using the ${} syntax. Following on from the example before:

println("I would suggest: ${suggestGift(10)} ")

The preceding code would print:

I would suggest: a book

If you're interpolating a variable, and not a function, curly braces could be omitted:

val gift = suggestGift(100)
println("I would suggest: $gift ")

This would print the following output:

I would suggest: a guitar

Classes and inheritance

Although Kotlin is multi-paradigm, it has a strong affinity to the Java programming language, which is based on classes. Keeping Java and JVM interoperability in mind, it's no wonder that Kotlin also has the notion of classes and classical inheritance.

Classes

To declare a class, we use a class keyword, exactly like in Java:

class Player {
}

There's no new keyword in Kotlin. The instantiation of a class simply looks like this:

// Kotlin figured out you want to create a new player
val p = Player()

If the class has no body, as in this simple example, we can omit the curly brackets:

class Player // Totally fine

Inheritance

Exactly like in Java, abstract classes are marked by abstract and interfaces by the interface keyword:

abstract class AbstractDungeonMaster {
abstract val gameName: String

fun startGame() {
println("Game $gameName has started!")
}
}

interface Dragon

As in Java 8, interfaces in Kotlin can have a default implementation of functions, as long as they don't rely on any state:

interface Greeter {
fun sayHello() {
println("Hello")
}
}

There are no inherits and implements keywords in Kotlin. Instead, both the name of an abstract class and all the names of the interfaces that class implements are put after a colon:

class DungeonMaster: Greeter, AbstractDungeonMaster() {
override val gameName: String
get() = "Dungeon of the Beholder"
}

We can still distinguish the abstract class by the parenthesis that comes after its name, and there can still be only one abstract class, as there are no multiple inheritances in Kotlin.

Our DungeonMaster has access to both functions from Greeter and AbstractDungeonMaster:

val p = DungeonMaster()
p.sayHello() // From Greeter interface
p.startGame() // From AbstractDungeonMaster abstract class

Calling the preceding code, it will print the following output:

Hello
Game Dungeon of the Beholder has started!

Constructors

Our DungeonMaster looks a bit awkward now, since it can proclaim the start of only one game. Let's add a non-empty constructor to our abstract class to fix that:

abstract class AbstractDungeonMaster(private val gameName : String) {
fun startGame() {
println("Game $gameName has started!")
}
}

Now, our DungeonMaster must receive the name of the game and pass it to the abstract class:

open class DungeonMaster(gameName: String):
Greeter, AbstractDungeonMaster(gameName)

What if we wanted to extend DungeonMaster by having an EvilDungeonMaster?

In Java, all classes can be extended, unless they're marked final. In Kotlin, no class can be extended, unless it's marked open. The same goes for functions in abstract classes. That's the reason why we declared DungeonMaster as open in the first place.

We'll change AbstractDungeonMaster a bit again to give more power to the evil ruler:

open fun startGame() {
// Everything else stays the same
}

Now, we add the following to our EvilDungeonMaster implementation:

class EvilDungeonMaster(private val awfulGame: String) : DungeonMaster(awfulGame) {
override fun sayHello() {
println("Prepare to die! Muwahaha!!!")
}

override fun startGame() {
println("$awfulGame will be your last!")
}
}

Whereas in Java, @Override is an optional annotation, in Kotlin it is a mandatory keyword.

You cannot hide supertype methods, and code that doesn't use override explicitly won't compile.

Properties

In Java, we are used to the concept of getters and setters. A typical class may look something like this:

public class Person {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

// More methods come here
}

If we want to get a person's name, we call getName(). If we want to change it, we call setName(). That's quite simple.

If we want to set the name only once, during object instantiation, we can specify the non-default constructor and remove the setter as follows:

public class ImmutablePerson {
private String name;

public ImmutablePerson(String name) {
this.name = name;
}

public String getName() {
return name;
}
}

All this dates back to the beginning of Java, somewhere around '95.

But if you've worked with C#, for example, you're probably familiar with the idea of properties. To understand them, let's go to the first example and change it a bit:

public class PublicPerson {
public String name;
}

Reading a person's name is not much shorter: p.name.

Also, changing the name is much more intuitive: p.name = "Alex";.

But by doing so, we lost a lot of control over our object. We cannot make PublicPerson immutable. If we want everybody to be able to read the person's name, they'll also be able to change it at any point in time. And what if later we decide that all names must be uppercase? With setter, we could do that. But not with the public field.

Properties provide a solution for all those problems:

class Person() {
var name : String = ""
}

This may look the same as the Java example, with all its problems. But actually, behind the scenes, it's compiled to a getter and setter pair, just like the first example.

And since properties in Kotlin are translated into getters and setters, we can also control their behavior:

class Person {
var name : String = ""
set(value) {
field = value.toUpperCase()
}
}

Note that we don't need to check that value is null. The String type simply cannot receive nulls.

Coming from Java, it may seem intuitive to use the following assignment: this.name = value.toUpperCase(). But, in Kotlin, this will create a circular dependency. Instead, there's a field identifier that we're using, which is provided automatically.

Data classes

Remember how Kotlin is all about productiveness? One of the most common tasks for Java developers is to create another Plain Old Java Object (POJO). If you're not familiar with POJO, it is basically an object that only has getters, setters, and an implementation of equals or hashCode methods.

This task is so common that Kotlin has it built into the language:

data class User (val username : String, val password : String)

This will generate a class with two getters and no setters (note the val part), which will also implement equals, hashCode, and clone functions in the correct way.

The introduction of data classes is one of the biggest improvements in reducing the amount of boilerplate in the language.

More control flow – loops

Now let's discuss another common control structure—a loop. Loops are a very natural construct for most developers. Without loops, it would be very hard to repeat the same block of code more than once (although we will discuss how to do that without loops in later chapters).

The for loop

The for loop in Java, which prints each character of a string on a new line, may look something like this:

final String word = "Word";
for (int i = 0; i < word.length; i++) {

}

The same loop in Kotlin is:

val word = "Word";
for (i in 0..(word.length-1)) {
println(word[i])
}

Note that while the usual for loop in Java is exclusive (it excludes the last index by definition, unless specified otherwise), the for loop over ranges in Kotlin is inclusive. That's the reason we have to subtract one from the length to prevent overflow (string index out of range): (word.length-1).

If you want to avoid that, you can use the until function:

val word = "Word";
for (i in 0 until word.length) {
println(word[i])
}

Unlike some other languages, reversing the range indexes won't work:

val word = "Word";
for (i in (word.length-1)..0) {
println(word[i])
} // Doesn't print anything

If your intention is to print the word in reverse order, for example, use the downTo function:

val word = "Word";
for (i in (word.length-1) downTo 0) {
println(word[i])
}

It will print the following output:

d
r
o
W

It may seem confusing that until and downTo are called functions, although they look more like operators. This is another interesting Kotlin feature called infix call, which will be discussed later on.

For-each loop

Of course, if you're a bit familiar with Java, you may argue that the previous code could be improved by using a for-each construct instead:

final String word = "Word";

for (Character c : word.toCharArray()) {
System.out.println(c);
}

The same in Kotlin would be:

val word = "Word"

for (c in word) {
println(c)
}

While loop

There are no changes to the while loop functionality, so we'll cover them very briefly:

var x = 0
while (x < 10) {
x++
println(x)
}

This will print numbers from 1 to 10. Note that we are forced to define x as var. In the following chapters, we'll discuss much more idiomatic ways to do this.

The lesser used do while loop is also present in the language:

var x = 5
do {
println(x)
x--
} while (x > 0)

Extension functions

You may have noticed from the previous examples that String in Kotlin has some methods that its Java counterpart is lacking, such as reversed(). How is that achieved, if it's the same String type as in Java and, as we know, String in Java cannot be extended by any other class, since it's declared final?

If you look at the source code, you'll find the following:

public inline fun String.reversed(): String {
return (this as CharSequence).reversed().toString()
}

This feature is called an extension function, and it also exists in some other languages, such as C# or Groovy.

To extend a class without inheriting from it, we prefix the function name, reversed in our example, with a class name we want to extend.

Do note that the extension function cannot override the member function. The inline keyword will be discussed in later chapters.

Introduction to design patterns

Now that we are a bit familiar with basic Kotlin syntax, we can move on to discuss what design patterns are all about.

What are design patterns?

There are different misconceptions surrounding design patterns. In general, they are as follows:

  • Missing language features
  • Not necessary in dynamic language
  • Relevant only to object-oriented languages
  • Relevant only to enterprises

But actually, design patterns are just a proven way to solve a common problem. As a concept, they are not limited to a specific programming language (Java), nor to a family of languages (C-family, for example), nor are they limited to programming in general. You may have even heard of design patterns in software architecture, which discuss how different systems can efficiently communicate with each other. There are service-oriented architectural patterns, which you may know as Service-Oriented Architecture (SOA), and microservice design patterns that evolved from SOA and emerged over the past few years. The future will, for sure, bring us even more design pattern families.

Even in the physical world, outside software development, we're surrounded by design patterns and commonly accepted solutions to a certain problem. Let's look at an example.

Design patterns in real life

Did you ride an elevator lately? Was there a mirror on the wall of the elevator? Why is that?

How did you feel when you last rode an elevator that had no mirror and no glass walls?

The main reason we commonly have mirrors in our elevators is to solve a common problem. Riding in an elevator is boring. We could put in a picture. But a picture would also get boring after a while, if you rode the same elevator at least twice a day. Cheap, but not much of an improvement.

We could put in a TV screen, as some do. But it makes the elevator more expensive. And it also requires a lot of maintenance. We need to put some content on the screen, to make it not too repetitive. So either there's a person whose responsibility is to renew the content once in a while, or a third-party company that does it for us. We'll also have to handle different problems that may occur with screen hardware and the software behind it. Seeing the "Blue Screen of Death" is amusing, of course, but only mildly.

Some architects even go for putting elevator shafts on the building exterior, and making part of the walls transparent. This may provide some exciting views. But this solution also requires maintenance (dirty windows don't make for the best view), and a lot of architectural planning.

So, we put in a mirror. You get to watch an attractive person even if you ride alone. Some studies indicate that we find ourselves more attractive than we are, anyway. Maybe you get a chance to review your appearances one last time before that important meeting. Mirrors visually expand the visual space and make the entire trip less claustrophobic, or less awkward, if it's the start of a day and the elevator is really crowded.

Design process

Let's try and understand what we did just now.

We didn't invent mirrors in elevators. We've seen them thousands of times. But we formalized the problem (riding in an elevator is boring) and discussed alternative solutions (TV screens, glass walls) and the benefits of the commonly used solution (solves the problem, easy to implement). That's what design patterns are all about.

The basic steps of the design process are:

  1. Define exactly what the current problem is.
  2. Consider different alternatives, based on the pros and cons.
  3. Choose the solution that solves the problem, while best fitting your specific constraints.

Why use design patterns in Kotlin?

Kotlin comes to solve the real-world problems of today. In the following chapters, we will discuss both Design Patterns first introduced by the Gang of Four back in '94, as well as design patterns that emerged from the functional programming paradigm.

You'll find that some of the design patterns are so common or useful that they're already built into the language as reserved keywords or standard functions. Some of them will need to combine a set of language features. And some are not so useful any more, since the world has moved forward, and they're being replaced by some other patterns.

But in any case, familiarity with design patterns and best practices expands your "developer toolbox" and creates shared vocabulary between you and your colleagues.

Summary

So, in this chapter, we covered the main goals of the Kotlin programming language.

We went through the variables that are defined, such as val, var, null safety, and type inference. We observed how program flow is controlled by commands such as if, when, for, and while, and we also took a look at the different keywords used to define classes and interfaces: class, interface, data, and abstract class. We learned how to construct new classes and how we inherit from interfaces and implement classes. And finally, we learned what design patterns are good for, and why we need them in Kotlin.

In the next chapter, we'll start discussing the first of the three design pattern families: creation patterns.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Understand traditional GOF design patterns to apply generic solutions
  • Shift from OOP to FP; covering reactive and concurrent patterns in a step-by-step manner
  • Choose the best microservices architecture and MVC for your development environment

Description

Design patterns enable you as a developer to speed up the development process by providing you with proven development paradigms. Reusing design patterns helps prevent complex issues that can cause major problems, improves your code base, promotes code reuse, and makes an architecture more robust. The mission of this book is to ease the adoption of design patterns in Kotlin and provide good practices for programmers. The book begins by showing you the practical aspects of smarter coding in Kotlin, explaining the basic Kotlin syntax and the impact of design patterns. From there, the book provides an in-depth explanation of the classical design patterns of creational, structural, and behavioral families, before heading into functional programming. It then takes you through reactive and concurrent patterns, teaching you about using streams, threads, and coroutines to write better code along the way By the end of the book, you will be able to efficiently address common problems faced while developing applications and be comfortable working on scalable and maintainable projects of any size.

What you will learn

• Get to grips with Kotlin principles, including its strengths and weaknesses • Understand classical design patterns in Kotlin • Explore functional programming using built-in features of Kotlin • Solve real-world problems using reactive and concurrent design patterns • Use threads and coroutines to simplify concurrent code flow • Understand antipatterns to write clean Kotlin code, avoiding common pitfalls • Learn about the design considerations necessary while choosing between architectures

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now

Product Details


Publication date : Jun 15, 2018
Length 310 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781788998017
Vendor :
JetBrains
Category :

Table of Contents

13 Chapters
Preface Chevron down icon Chevron up icon
Getting Started with Kotlin Chevron down icon Chevron up icon
Working with Creational Patterns Chevron down icon Chevron up icon
Understanding Structural Patterns Chevron down icon Chevron up icon
Getting Familiar with Behavioral Patterns Chevron down icon Chevron up icon
Functional Programming Chevron down icon Chevron up icon
Streaming Your Data Chevron down icon Chevron up icon
Staying Reactive Chevron down icon Chevron up icon
Threads and Coroutines Chevron down icon Chevron up icon
Designed for Concurrency Chevron down icon Chevron up icon
Idioms and Anti-Patterns Chevron down icon Chevron up icon
Reactive Microservices with Kotlin Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Filter icon Filter
Top Reviews
Rating distribution
Empty star icon Empty star icon Empty star icon Empty star icon Empty star icon 0
(0 Ratings)
5 star 0%
4 star 0%
3 star 0%
2 star 0%
1 star 0%

Filter reviews by


No reviews found
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.