Kotlin

https://kotlinlang.org/docs/home.html

Kotlin usage feedback

Learning

There are lots of tutorials out there, here are the ones that we read:

Obviously, we leverage AI to help us understand and review our kotlin code:

The good

Function / Method definition

In kotlin, function declarations are more natural and readable because we list the parameters (inputs) first, then the return type (output). This matches how we think: “Given these inputs, what output do I produce?“. In java, the return type comes first, which can feel less intuitive.

Optional<User> findById(UserId userId);
fun findById(userId: UserId): User?

Lenient trailing commas

kotlin allows trailing commas when listing arguments in function calls, collections, and class constructors. This means you can safely add a comma after the last item, which is especially useful when adding or removing lines.

Subscription(
    id = SubscriptionId.create(),
    owner = providerSubscription.owner,
    beneficiaries = beneficiaries,
)

java does not allow trailing commas… only in array initializers.

Safe call operator

https://kotlinlang.org/docs/null-safety.html#safe-call-operator

The safe call operator ?. allows you to handle nullability safely in a shorter form. Instead of throwing an NullPointerException, if the object is null, the ?. operator simply returns null:

val a: String? = null
print(a?.length) // null instead of NPE

Safe calls are useful for chaining calls.

val name = alice?.department?.head?.name

In java, there are no such things:

String name = alice != null && alice.getDepartment() != null && alice.getDepartment().getHead() != null
    ? alice.getDepartment().getHead().getName()
    : null;
 
// or with `if/else`
String name = null;
if (
    alice != null
    && alice.getDepartment() != null
    && alice.getDepartment().getHead() != null
) {
    name = head.getName();
}

The ruby version is similar to kotlin:

name = alice&.department&.head&.name

Elvis operator

https://kotlinlang.org/docs/null-safety.html#elvis-operator

When working with nullable type, you can provide an alternative value if it’s null, for example:

fun displayName(user: User?): String {
    return user?.name ?: "Guest"
}

It can seamlessly be used with the safe operator, e.g. in an authentication service where we would want to extract the JWT and parse the user id from it:

fun getJwtToken(): String?
fun extractUserId(token: String): String?
 
fun getCurrentEndUserResult(): AuthResult {
    return getJwtToken()
        ?.let { token -> extractUserId(token) }
        ?.let { userId -> AuthResult.Success(EndUser.from(userId)) }
        ?: AuthResult.Error("Absent or invalid or unauthenticated JWT")
}

The java version would be:

Optional<String> getJwtToken();
Optional<String> extractUserId(String token);
 
AuthResult getCurrentEndUserResult() {
    return getJwtToken()
        .flatMap(token -> extractUserId(token))
        .map(userId -> new AuthResult.Success(EndUser.from(userId)))
        .orElseGet(() -> new AuthResult.Error("Absent or invalid or unauthenticated JWT"));
}

It’s basically the same, but we have to wrap the String into a container in order to have something monadic. That means, if we are dealing with a library that gives an API that returns null and not Optional, then to simulate such behavior, you have to wrap into an Optional, which is not really nice:

// Is this:
var foo = Optional.ofNullable(anApiThatReturnsNull())
  .orElse("something else");
 
// better than this?
var foo = anApiThatReturnsNull()
if (foo == null) foo = "something else"

Moreover, to ensure the compiler knows if we are dealing with null instances, we have to add tools, like JSpecify, whereas in kotlin, it’s native.

The ruby version would be:

def get_current_end_user_result
  get_jwt_token
      &.then { |token| extract_user_id(token) }
      &.then { |user_id| AuthResult::Success.new(EndUser.from(user_id)) }
    || AuthResult::Error.new("Absent or invalid or unauthenticated JWT")
end

Here’s another example where the elvis operator really shines:

We have a class that loads some configuration based on priority: user config takes precedence, then application and then default config.

class ConfigManager(
    private val userConfig: Config?,
    private val appConfig: Config?,
    private val defaultConfig: Config
) {
    fun getTimeout(): Int {
        return userConfig?.timeout
            ?: appConfig?.timeout
            ?: defaultConfig.timeout
            ?: 30_000
    }
 
    fun getDatabaseUrl(): String {
        return System.getenv("DB_URL")
            ?: userConfig?.dbUrl
            ?: appConfig?.dbUrl
            ?: "jdbc:h2:mem:test"
    }
}

The kotlin version is quickly readable and we can understand what’s going on at a glance.

Here’s the java version:

public class ConfigManager {
    private Config userConfig;
    private Config appConfig;
    private Config defaultConfig;
 
    public int getTimeout() {
        if (userConfig != null && userConfig.getTimeout() != null) {
            return userConfig.getTimeout();
        }
        if (appConfig != null && appConfig.getTimeout() != null) {
            return appConfig.getTimeout();
        }
        if (defaultConfig.getTimeout() != null) {
            return defaultConfig.getTimeout();
        }
        return 30_000;
    }
 
    // Or with Optional (still verbose and note necessarily more readable)
    public String getDatabaseUrl() {
        return Optional.ofNullable(System.getenv("DB_URL"))
            .orElse(Optional.ofNullable(userConfig)
                .map(Config::getDbUrl)
                .orElse(Optional.ofNullable(appConfig)
                    .map(Config::getDbUrl)
                    .orElse("jdbc:h2:mem:test")));
    }
}

It’s more verbose and less readable than the kotlin’s version.

The ruby version is similar to kotlin, but without the type safety:

class ConfigManager
  def initialize(user_config, app_config, default_config)
    @user_config = user_config
    @app_config = app_config
    @default_config = default_config
  end
 
  def timeout
    @user_config&.timeout
      || @app_config&.timeout
      || @default_config&.timeout
      || 30_000
  end
 
  def database_url
    ENV['DB_URL']
      || @user_config&.db_url
      || @app_config&.db_url
      || 'sqlite://memory'
  end
end

Named parameter & default values

Named parameters and default values make function calls more readable and flexible. You can specify parameter names when calling functions, making the code self-documenting, and provide default values to avoid method overloading.

fun createUser(
    name: String,
    email: String,
    age: Int = 0,
    isActive: Boolean = true,
    role: String = "user"
) {
    // ...
}
 
// Usage with named parameters (order doesn't matter)
createUser(email = "john@example.com", name = "John Doe", age = 25)
 
// Mix of positional and named parameters
createUser("Jane Doe", "jane@example.com", role = "admin")
 
// Only required parameters
createUser("Bob", "bob@example.com")

This eliminates the need for multiple constructor/method overloads and makes function calls much clearer, especially when dealing with boolean parameters or multiple optional parameters.

transferMoney(
    from = sourceAccount,
    to = destinationAccount,
    amount = 1000.0,
    includeFees = true,
    async = false
)

In java, you’d need multiple method overloads or use builder patterns:

// Java: multiple overloads needed
public void transferMoney(Account from, Account to, double amount) {
    transferMoney(from, to, amount, true, false);
}
 
public void transferMoney(Account from, Account to, double amount, boolean includeFees) {
    transferMoney(from, to, amount, includeFees, false);
}
 
public void transferMoney(Account from, Account to, double amount, boolean includeFees, boolean async) {
    // ...
}
 
// Usage is unclear without IDE help
transferMoney(sourceAccount, destinationAccount, 1000.0, true, false);
 
// Or using builder pattern (more verbose)
TransferRequest.builder()
    .from(sourceAccount)
    .to(destinationAccount)
    .amount(1000.0)
    .includeFees(true)
    .async(false)
    .build()
    .execute();

The ruby version supports keyword arguments similarly to kotlin:

def create_user(name:, email:, age: 0, active: true, role: 'user')
  # ...
end
 
# Usage with keyword arguments
create_user(email: 'john@example.com', name: 'John Doe', age: 25)
 
# Required parameters only
create_user(name: 'Bob', email: 'bob@example.com')

However, ruby lacks compile-time type checking, so you might discover parameter type mismatches at runtime, while kotlin catches these at compile time.

Equality

https://kotlinlang.org/docs/equality.html

Kotlin distinguishes between structural equality (==) and referential equality (===).

  • == checks if two objects have the same value (calls equals() under the hood).
  • === checks if two references point to the same object (identity).
val a = "hello"
val b = "hello"
val c = a
 
println(a == b)  // true (structural equality)
println(a === b) // false (not necessarily the same reference)
println(a === c) // true (same reference)

For data classes, == compares all properties by value automatically:

data class User(val name: String, val age: Int)
val u1 = User("Alice", 30)
val u2 = User("Alice", 30)
println(u1 == u2) // true

In java, you must override equals() and hashCode() for value comparison, and it’s easy to make mistakes (e.g., using == for objects compares references, not values). Kotlin’s approach is safer and less error-prone.

it: implicit name of a single parameter

https://kotlinlang.org/docs/lambdas.html#it-implicit-name-of-a-single-parameter

It’s very common for a lambda expression to have only one parameter. If the compiler can parse the signature without any parameters, the parameter does not need to be declared and -> can be omitted and the parameter will be implicitly declared under the name it:

val numbers = listOf(1, 2, 3, 4)
val doubled = numbers.map { it * 2 } // 'it' refers to each element
println(doubled) // [2, 4, 6, 8]
 
val firstEven = numbers.find { it % 2 == 0 }
println(firstEven) // 2

In java, lambda parameters must always be named explicitly:

var numbers = List.of(1, 2, 3, 4);
var doubled = numbers.stream().map(n -> n * 2).toList();
System.out.println(doubled);
 
var firstEven = numbers.stream()
    .filter(n -> n % 2 == 0)
    .findFirst();
System.out.println(firstEven);

Since ruby 3.4, it also exists:

numbers = [1, 2, 3, 4]
doubled = numbers.map { it * 2 }
puts doubled.inspect # [2, 4, 6, 8]
 
first_even = numbers.find { it.even? }
puts first_even # 2

Data class copy

https://kotlinlang.org/docs/data-classes.html#copying

data class User(val name: String, val age: UInt) {}
 
val alice = User(name = "Alice", age = 24u)
val olderAlice = alice.copy(age = 48u)

java does not have native feature for copying and updating immutable objects. Instead, we typically rely on design patterns such as the builder pattern or use third-party libraries like Lombok to achieve similar functionality:

@Builder(toBuilder = true)
public record User(String name, String age) {}
 
var alice = new User("Alice", 24);
var olderAlice = alice.toBuilder().age(48).build();

In ruby, you can use the native Struct and dup to copy and update fields:

User = Struct.new(:name, :age)
 
alice = User.new(name: "Alice", age: 24)
older_alice = alice.dup.tap { it.age = 48 }

String template

https://kotlinlang.org/docs/strings.html#string-templates

Kotlin supports string templates, allowing you to embed variables and expressions directly in strings using the $ symbol:

val name = "Alice"
val age = 24
println("Hello, $name! You are $age years old.")
println("Next year, you will be ${age + 1}.")

In Java, string interpolation is not supported. You must use concatenation or String.format:

String name = "Alice";
int age = 24;
System.out.println("Hello, " + name + "! You are " + age + " years old.");
System.out.println(String.format("Next year, you will be %d.", age + 1));

In Ruby, string interpolation uses #{} inside double-quoted strings:

name = "Alice"
age = 24
puts "Hello, #{name}! You are #{age} years old."
puts "Next year, you will be #{age + 1}."

Operator overloading

https://kotlinlang.org/docs/operator-overloading.html#unary-operations

kotlin lets the possibility to override predefined symbolic representation (like + or *).

This led to a more readable code:

if (amount < BigDecimal.ZERO)

instead of in java:

if (amount.compareTo(BigDecimal.ZERO) < 0)

Another aspect of the operator overloading is the invoke operator which allows objects to be called as functions. By implementing the operator fun invoke() function, you can make instances of a class callable with parentheses syntax, enabling function-like behavior for objects.

enum class SubscriptionDomainErrors(private val messageTemplate: String) {
    INVALID_ACCOUNT_ID("Account id '%s' must be a positive"),
    // ...
    ;
 
    operator fun invoke(vararg args: Any): DomainError = SubscriptionDomainError(String.format(messageTemplate, *args), name)
}
 
// then it's called directly with parentheses:
if (value <= 0) throw DomainException(INVALID_ACCOUNT_ID(value))

Syntactic sugar

let

https://kotlinlang.org/docs/scope-functions.html#let

Execute if not null:

val user = User(name = "Alice", age = 24)
val doubleAge = user?.let { it.age * 2 }

Java version (using Optional):

User user = new User("Alice", 24);
Integer doubleAge = Optional.ofNullable(user).map(u -> u.getAge() * 2).orElse(null);

Ruby version:

user = User.new(name: "Alice", age: 24)
double_age = user&.age&.*(2)

collection.firstOrNull

https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/first-or-null.html

Returns the first element matching the given predicate, or null if no such element is found.

val numbers = listOf(1, 2, 3)
val firstEven = numbers.firstOrNull { it % 2 == 0 } // 2
val firstNegative = numbers.firstOrNull { it < 0 } // null

The java version is more verbose:

List<Integer> numbers = Arrays.asList(1, 2, 3);
Integer firstEven = numbers.stream()
    .filter(n -> n % 2 == 0)
    .findFirst()
    .orElse(null);
Integer firstNegative = numbers.stream()
    .filter(n -> n < 0)
    .findFirst()
    .orElse(null);

The ruby version is similar to kotlin:

numbers = [1, 2, 3]
first_even = numbers.find { it.even? }
first_negative = numbers.find { it < 0 }

collection.associateBy

https://kotlinlang.org/docs/collection-transformations.html#associate

Association transformations allow building maps from the collection elements and certain values associated with them. In different association types, the elements can be either keys or values in the association map.

data class User(val id: Int, val name: String)
 
val users = listOf(User(1, "Alice"), User(2, "Bob"))
val userMap = users.associateBy { it.id }
// userMap: {1=User(id=1, name=Alice), 2=User(id=2, name=Bob)}

The java version:

record User(int id, String name) {}
 
var users = List.of(new User(1, "Alice"), new User(2, "Bob"));
var userMap = users.stream().collect(Collectors.toMap(User::id, Function.identity()));

The ruby version:

User = Struct.new(:id, :name)
users = [User.new(1, "Alice"), User.new(2, "Bob")]
user_map = users.to_h { |u| [u.id, u] }
# user_map: {1=>#<struct User id=1, name="Alice">, 2=>#<struct User id=2, name="Bob">}

These methods make collection manipulation concise and expressive in kotlin, compared to more verbose approaches in Java.

Single-expression function

https://kotlinlang.org/docs/idioms.html#single-expression-functions

fun displayName(user: User?): String {
    return user?.name ?: "Guest"
}
 
// can be more concise
 
fun displayName(user: User?): String = user?.name ?: "Guest"

It can also be used with other idioms:

fun currentEndUser(): EndUser = when (val result = getCurrentEndUserResult()) {
    is AuthResult.Success -> result.user
    is AuthResult.Error -> throw AccessDeniedException(result.message)
}

takeIf

https://kotlinlang.org/docs/scope-functions.html#takeif-and-takeunless

When called on an object along with a predicate, takeIf returns this object if it satisfies the given predicate. Otherwise, it returns null. So, takeIf is a filtering function for a single object.

fun extractUserId(): Long? {
    return tokenAttributes[ATTRIBUTE_USERID]
        ?.toString()
        ?.toLongOrNull()
        ?.takeIf { it > 0 }
}

The java version is more verbose:

Long extractUserId() {
    var attributes = getTokenAttributes().get(ATTRIBUTE_USERID);
    if (attributes == null) return null
 
    try {
        var userId = Long.parseLong(v.toString());
        return userId > 0 ? userId : null;
    } catch (NumberFormatException ignored) {
        return null;
    }
}

The ruby version is similar to kotlin:

def extract_user_id
  token_attributes[ATTRIBUTE_USERID]
    &.to_s
    &.to_i
    &.then { it > 0 ? it : nil }
end

also

https://kotlinlang.org/docs/scope-functions.html#also

also is useful for performing some actions that take the context object as an argument. You can read it as ” and also do the following with the object. ”

// subscriptions: List<Subscription>
// providerSubscriptionIds: List<ProviderSubscriptionId>
val missingSubscriptions = subscriptions
    .filter { it.providerSubscriptionId !in providerSubscriptionIds }
    .map {
        it.unsubscribeAsDeleted().also { s ->
            logger.warn("Subscription ${s.id} unsubscribed as deleted as the provider did not contain this subscription.")
        }
    }

In java:

var missingSubscriptions = subscriptions.stream()
    .filter(not(sub -> providerSubscriptionIds.contains(sub.getProviderSubscriptionId())))
    .map(sub -> {
        Subscription s = sub.unsubscribeAsDeleted();
        logger.warn("Subscription " + s.getId() + " unsubscribed as deleted as the provider did not contain this subscription.");
        return s;
    })
    .toList();

And the ruby version:

missing_subscriptions = subscriptions
  .reject { |sub| provider_subscription_ids.include?(sub.provider_subscription_id) }
  .map do |sub|
    s = sub.unsubscribe_as_deleted
    logger.warn("Subscription #{s.id} unsubscribed as deleted as the provider did not contain this subscription.")
    s
  end

with

https://kotlinlang.org/docs/scope-functions.html#with

with can be useful for calling functions on the context objects when you don’t need to use the returned result. with can be read as “with this object, do the following.”

with(reloadedRevenueCatWebhook(webhookAppUserId)) {
    assertThat(appUserId).isEqualTo(webhookAppUserId)
    assertThat(body).isEqualTo(jacksonObjectMapper().readTree(payload))
    assertThat(createdAt).isNotNull
}
 
// instead of
val webhook = reloadedRevenueCatWebhook(webhookAppUserId)
assertThat(webhook.appUserId).isEqualTo(webhookAppUserId)
assertThat(webhook.body).isEqualTo(jacksonObjectMapper().readTree(payload))
assertThat(webhook.createdAt).isNotNull

backtick method name

https://kotlinlang.org/docs/coding-conventions.html#names-for-test-methods

In kotlin, it’s possible to define method name with spaces using backticks:

fun `correct arguments`(description: String, executable: Executable) { /** **/ }

This allows to have expressive test method names.

Extension function

https://kotlinlang.org/docs/idioms.html#extension-functions

This lets you add new functions to existing classes without modifying their source code.

// Extending the JwtAuthenticationToken class with a new method "extractUserId":
private fun JwtAuthenticationToken.extractUserId(): Long? =
    tokenAttributes[ATTRIBUTE_USERID]
        ?.toString()
        ?.toLongOrNull()
        ?.takeIf { it > 0 }

In java, we would have to create a helper function.

In ruby, we can also extend new methods:

class JwtAuthenticationToken
  def extract_user_id
    token_attributes[ATTRIBUTE_USERID]
      &.to_s
      &.to_i
      &.then { it > 0 ? it : nil }
  end
end

The unexpected

Build

I expected a slower build time, but I was pleasantly surprised that there were almost no build time overhead.

Multi-line string in parameterized tests

We are using JUnit Jupiter ParameterizedTest whenever we can, to test with multiple different values.

For example, we can have the following test:

class AccountIdTest {
    @ParameterizedTest
    @CsvSource(useHeadersInDisplayName = true, delimiterString = "->", textBlock = """
        id  -> expected error message
        0   -> Account id '0' must be a positive
        -1  -> Account id '-1' must be a positive
        -42 -> Account id '-42' must be a positive
        """)
    fun `invalid arguments`(id: Long, expectedErrorMessage: String) {
        // ..
    }
}

The test will fails because of:

org.junit.jupiter.api.extension.ParameterResolutionException: Error converting parameter at index 0: Cannot convert null to primitive value of type long

The issue here is that:

  • the text block must be a constant (so not possible to use the String.trimIndent method)
  • the test method is indented
  • with an IDE, when pressing Enter, the cursor will not be at the first column of the row, but at some indented columns
    // The cursor | is placed with some indentation by default (the number of indentation depends on the IDE).
    @CsvSource(useHeadersInDisplayName = true, delimiterString = "->", textBlock = """
        |

So the last line of:

    @CsvSource(useHeadersInDisplayName = true, delimiterString = "->", textBlock = """
        id  -> expected error message
        0   -> Account id '0' must be a positive
        -1  -> Account id '-1' must be a positive
        -42 -> Account id '-42' must be a positive
        """)

is also interpreted to be used in the test, so it’s trying to inject a null value, hence the error.

In java, there’s no problem, as it seems to skip this last line.

So the mitigation is either removing the last line:

    @CsvSource(useHeadersInDisplayName = true, delimiterString = "->", textBlock = """
        id  -> expected error message
        0   -> Account id '0' must be a positive
        -1  -> Account id '-1' must be a positive
        -42 -> Account id '-42' must be a positive""")

or remove the margin:

    @CsvSource(useHeadersInDisplayName = true, delimiterString = "->", textBlock = """
id  -> expected error message
0   -> Account id '0' must be a positive
-1  -> Account id '-1' must be a positive
-42 -> Account id '-42' must be a positive
""")

Superset primitives

kotlin has defined some of their own primitives like:

  • kotlin.time.Duration
  • kotlin.collections.List
  • kotlin.collections.Map
  • kotlin.Function

It can be confusing to choose which class to use (java or kotlin, although default to kotlin might be a good choice as they offer more features).

The bad

LSP

There are some LSP out there:

Unfortunately, both are not usable for large multi-modules maven projects…

So I could not use my favorite editor nvim to code in kotlin efficiently. So go back to Jetbrain product, which I already used before, and their ideavim plugin is great.

Static methods and companion object

https://kotlinlang.org/docs/object-declarations.html#companion-objects

Companion objects allow you to define class-level functions and properties. This makes it easy to create factory methods, hold constants, and access shared utilities.

An object declaration inside a class can be marked with the companion keyword:

class MyClass {
    companion object {
        fun create(): MyClass = MyClass()
        fun greet(name: String): String = "Hello, $name"
    }
}
 
val a = MyClass.create()
print(MyClass.greet("Alice"))

In ruby, it’s equivalent of self:

class MyClass
  class << self
    def create
      new
    end
 
    def greet(name)
      "Hello, #{name}"
    end
  end
end
 
var a = MyClass.create
puts MyClass.greet("Alice")

The issue is that when using JUnit Jupiter parameterized tests, the @MethodSource which allows us to refer to one or more factory methods of the test class or external classes. But it requires the factory method to be static.

In java:

@ParameterizedTest
@MethodSource("invalidArgumentsProvider")
void incorrectArguments(PatientId patientId, AccountId accountId, String expectedErrorMessage) {
    // ...
}
 
private static Stream<Arguments> invalidArgumentsProvider() {
    return Stream.of(
        Arguments.of(null, new AccountId(123), "patient id is mandatory"),
        Arguments.of(new PatientId("patient1"), null, "account id is mandatory")
    );
}

The equivalent in kotlin would be:

@ParameterizedTest
@MethodSource("invalidArgumentsProvider")
fun incorrectArguments(patientId: PatientId, accountId: AccountId, expectedErrorMessage: String) {
    // ...
}
 
companion object {
    @JvmStatic
    fun invalidArgumentsProvider(): String<Arguments> = Stream.of(
        Arguments.of(null, new AccountId(123), "patient id is mandatory"),
        Arguments.of(new PatientId("patient1"), null, "account id is mandatory")
    );
}

The issue comes where we have multiple ParameterizedTest in the same test file.

As we can only have one companion object per class, all the static factory methods must be grouped together, whereas in java, we can co-locate the static factory method besides the test, which makes the test more readable, and have less code jumping.

Things I want to experiment

On Kotlin DSL

https://kotlinlang.org/docs/api-guidelines-readability.html#use-dsls

It’s possible to create DSL to improve readability in kotlin.

@DslMarker
annotation class HtmlTagMarker
 
@HtmlTagMarker
class Html {
    private val children = mutableListOf<String>()
    fun body(block: Body.() -> Unit) {
        val body = Body().apply(block)
        children.add(body.render())
    }
    fun render() = "<html>\n${children.joinToString("\n")}\n</html>"
}
 
@HtmlTagMarker
class Body {
    private val children = mutableListOf<String>()
    fun p(text: String) {
        children.add("<p>$text</p>")
    }
    fun render() = "<body>\n${children.joinToString("\n")}\n</body>"
}
 
// Usage:
val html = Html().apply {
    body {
        p("Welcome to Kotlin DSLs!")
        p("They are powerful and readable.")
    }
}.render()
 
println(html)

It might be more interesting for libraries instead of apps.

Asynchronous programming

https://kotlinlang.org/docs/async-programming.html

Troubleshooting

If you are getting the following issue where a global constant or a function are failing intellij compilation:

Kotlin: Overload resolution ambiguity between candidates:
val FOOBAR: Int
val FOOBAR: Int

It seems to be an issue with Kotlin incremental compilation. So I had to deactivate it with “Settings > Build, Execution, Deployment > Compiler > Kotlin comppiler” then uncheck “Enable incremental compilation”.


  • side do the kotlin koan tutorial