Monday, July 11, 2022

Code: Kotlin First Impressions

Introduction
Kotlin is one of the newest and most popular JVM languages and it might be one of my new favorite languages. Disclaimer: I haven't written much production-ready code in it yet.

As a JVM language like Scala, Groovy, and Clojure; Kotlin tries to take the portability of the Java Virtual Machine and familiarity of the Java language while improving upon its archaic design with the conciseness and power of modern programming languages. Simply put: it's Java but better—for real this time!

Scala was my favorite attempt at improving Java, but I was pretty unhappy with the build system. Since Kotlin is written by JetBrains, an IDE company, compiler and IDE support is first-class. You can even use JetBrains' IntelliJ to output Kotlin code to Java, and vice versa. For this reason alone, it is easy to pick up for Java developers.

Improvements on Java 8
So what does Kotlin improve upon? Firstly, Java's verbosity. Compare a hello world program in Java:

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

and in Kotlin:

fun main() {
    println("Hello world!")
}

The first thing to note is that no class definition is required. You can simply add top-level functions. Kotlin is a functional language, so a function definition is required, but the public access modifier is implied. Top-level functions are always static. And type inference also applies to functions, so no void is required here. Just fun to mark that it's a function. In the actual function itself, println is a top-level function, so no need to qualify the function with a package and class. Lastly, no semicolons.

This is not some neat trick about hello world programs, the rest of the language is written to be concise. Record classes (data classes), raw strings, type inference, default function parameter values, string interpolation, collection builders, array slices, range operators, and null safety operators all help make your code very concise and efficient. If you don't know what those mean take the following Kotlin code:

fun doSomething(param: String = "default") {
  val stringTemplate = "$param ${1 + 2} String"

  val nums = (0..20).toList() // A list of integers from 0 to 20
  println(nums.slice(1..5 step 2)) // Prints "[1, 3, 5]"

  val newStr: String? = getStringOrNull()
  println(newStr?.length) // Prints length or "null" if string is null

  val neverNull = getStringOrNull2() ?: "" // Converts nulls to ""

  val regex = """\w+@gmail\.com"""
}

Doing this in Java 8 without special libraries would be like:

public static void doSomething() {
  doSomething(null);
}

public static void doSomething(String param) {

  param = (param == null) ? "default" : param;
  String stringTemplate = String.format("%s %d String", param, (1 + 2));

  List<Integer> nums = IntStream.rangeClosed(0, 20).boxed()
      .collect(Collectors.toList()); // It's either this or a for loop

  // A for loop is simpler than the stream version
  List<Integer> slicedList = new ArrayList<>();

  for (int i = 1; i <= 5; i += 2) {
    slicedList.add(nums.get(i));
  }
  System.out.println(slicedList); // Prints "[1, 3, 5]"

  String newStr = getStringOrNull();

  System.out.println((newStr == null) ? null : newStr.length());

  // We need two lines for this, unless we call the function twice
  String intermediateVar = getStringOrNull2();
  String neverNull = (intermediateVar == null) ? "" : intermediateVar;

  String regex = "\\w+@gmail\\.com"; // We must escape special characters
}

Or at least that's my interpretation. With Java 8 streams, there are a few functions to create and manipulate collections. You can also short circuit nullable objects with Optional.ofNullable([nullable]).orElse([default]), but I prefer the ternary operator in Java.

Another great feature is destructuring declarations. In Python, you can return multiple values. In Kotlin, we get half of that feature by being able to "destructure" a returned value into multiple variables:

  val (name, age) = person
  for ((key, value) in map) {
    // stuff
  }

Lastly, it is interoperable with Java. You can call Java code from Kotlin and you can even call Kotlin code from Java. One of Java's biggest strengths is the massive set of libraries you can use. These libraries are available, too, in Kotlin.

Drawbacks
Sounds too good to exist? Well, Kotlin has some drawbacks. I probably will come up with more after using the language for a while, but for right now, the drawbacks are minimal.

For one, variable type declarations follow the variable name as in var a:Int. For many of us, we started programming in C, C++, or Java where variable types come before the variable name. I disliked this seemingly arbitrary change until it was explained to me.

When declaring a variable, the variable's name is the most important aspect. When your language has type inference, the type isn't always written. This means variables declarations are generally aligned well, regardless of type declaration or lack thereof. This alignment is maintained for variables (val or var) and functions (fun).

val a = 1   // Infers type from value
val b: Int  // No value to infer type
var c: String = "String" // Optionally specify type
// Infer return type of single-expression function
fun sum(arg1: Int, arg2: Int) = arg1 + arg2

Notice that the val/var/fun keywords are all aligned vertically, as are the names. So while this name-type order will take some getting used to, it's not a bad thing. Pretty much all modern languages (Go, Rust, Swift, Scala, Nim, and Python) use it.

One issue that I dislike is the amount of scope functions. let, run, with, apply, and also are all ways to call a block of code with a temporary scope and each is used slightly differently. This seems like overkill and I don't imagine I'll ever memorize which is which. You don't want to have too many ways to do the same thing in a language, as it makes reading and reviewing code difficult.

Overall, it seems like a very fun, concise language and an upgrade to Java.

Kotlin vs Newer Versions of Java
JetBrains 2021 Developer Study


Having said that, Java has progressed quite past version 8. Java 8 is still the most popular version, according to a JetBrains survey, being used by 72% of Java programmers (users were allowed to select multiple versions). SNYK's survey results says Java 11 slightly outweighs Java 8 with both being around 61%. In either case, the higher versions of Java have little use with both companies saying Java 15 use is around 13%.


SNYK 2021 Developer Study

Java 19 will drop in September, but for a company looking for stability should probably stick with Java 17, as it is will still be the most recent version with Long-Term Support from Oracle. So what does Java 17 add to the language that Java 8 and Java 11 users may be unfamiliar with? I will describe some of the notable language updates, ignoring preview features and compiler and JVM enhancements.

Java 9 to 11 updates:

  • 9: Project Jigsaw: Modular system
    Introduces a module system to the language to define exports and dependencies.
  • 9: Private methods in interfaces
  • 9: Actual immutable collections
    Allows things like Set.of(item1, item2).
  • 10: Type inference
    Introduces var keyword.
  • 10: Root certificates.
    Allows TLS out of the box.
  • 11: HttpClient
    A replacement for HttpUrlConnection.
  • 11: More String and Files methods
    New methods like String::lines and Files::readString.
Java 12 to 17 updates:
  • 12: New methods in String, Files, and Collectors
  • 12: A number formatter
  • 14: Switch expressions
    Makes switch expressions much less verbose.
  • 15: Text blocks
    Allows setting Strings to nicely-formatted multiline blocks of text without inserting pesky "\n".
  • 16: Records
    Allows the creation of data classes with default getters and setters in essentially one line.
  • 16: Pattern matching for instanceof
    Decreases verbosity by allowing the declaration of a variable in an instanceof expression.
  • 17: Sealed classes
    Increases control over class inheritance.
Most of this article was written with Java 8 in mind. It's fair to say that Java has come a long way since then and Java now has more syntactic sugar. Specifically, type inference, text blocks (multiline strings), and records (data classes). However, even these new features are weaker than their Kotlin equivalents:
  • Type inference only applies to local variables, not top-level variables or lambda expressions
  • Text blocks aren't raw strings and will still process escape sequences (i.e. you still have to escape all of your backslashes). Writing regex in Java still sucks.
  • A record cannot contain any private instance variables. Admittedly, this is a tiny disadvantage.
Even the work that has been done to modernize Java doesn't bring it up to par with Kotlin. That's why I'm excited to start using Kotlin.

Monday, May 2, 2022

Code: Java Generics: Bounded Wildcards

Java wildcards are the kind of fun that make you want to bathe with your toaster. But they're not so bad if you can remember the simple rules, which come with practice. Say we have three generic lists, one of some random class, one of its superclass, and another of a subclass of the original class:

List<Number> ln;
List<Integer> li;
List<Object> lo;

Then, using wildcards, we can create some wildcard lists. One that uses "extends" of the original class, and the other that uses "super" of the original class.

List<? extends Number> numProducer;
List<? super Number> numConsumer;

Can you remember which of the top 3 lists can be assigned to these two wildcard lists? Don't forget PECS: Producer-extends, Consume-super.

// same type
numProducer = ln;
numConsumer = ln;

// subtype
numProducer = li;
// numConsumer = li; // doesn't compile: Integer isn't a superclass of Number

// supertype
// numProducer = lo; // doesn't compile: Object doesn't extend Number
numConsumer = lo;

Remember that ? extends Number and ? super Number can both be set to an object of type Number. If you remembered that, this was probably an easy exercise. The Java compiler prevents you from making class casting mistakes, so 
you can't set a super to a subclass and you can't set an extends to a superclass.

This might seem weird. If you can set numConsumer to a List<Number>, why can't you set it to List<Integer>? Every Integer is a Number, so any operation you could perform with an item from numConsumer should work. But don't think of numConsumer as a random collection of Numbers and other instances of Number's superclasses. Instead, remember the entire point of writing a lower-bounded wildcard is that the unknown type is indeed known at compile time and we want to restrict the type to only Number and Number's superclasses. Why might we want to do this? Abstraction.

The reason for restricting numProducer to subclasses of Number is even more obvious. If we set numProducer to a list of Objects, we might try to perform numeric operations on a list containing Strings, or Sets, or other non-Numbers.

You really shouldn't be setting any wildcard values directly anyway. They're usually used as method parameters and you simply get things out of (produce) or put things into (consume) your wildcard object. Like in:
public Number addThese(List<? extends Number> addends) {
Number sum = 0;
for (Number n : addends) {
sum = addTwoNumbers(sum, n);
}
return sum;
}
Notice that we're getting the value out of our producer. What type of objects can we get out of wildcard producers and consumers, and what type of objects can we put in to each?

Getting objects out:

Number num1 = numProducer.get(0);
// Number num2 = numConsumer.get(0); // doesn't compile; could return non-Number
// Integer int1 = numProducer.get(0); // doesn't compile; could return non-Integer
// Integer int2 = numConsumer.get(0); // doesn't compile; could return non-Integer
Object obj1 = numProducer.get(0);
Object obj2 = numConsumer.get(0); // Fine only because everything is an Object 

The last line only works because I couldn't think of 3 levels of classes where the parent class wasn't Object. If we used a different super class, an implicit cast from a consumer to its parent class wouldn't work:

// First create two wildcard Integer lists, then get an object from them
List<? extends Integer> intProducer = ...;
List<? super Integer> intConsumer = ...;
// Number numA = intConsumer.get(0); // doesn't compile; could return non-Number
Number numB = intProducer.get(0); // just to show this still works

This makes sense. We can only set value to its type or a subtype of its type. So only a producer can properly use getter methods like get() and only for its type or a superclass of its type. Consumers can't use getter methods (unless you implicitly cast to Object). So if producers can be informally thought of as read-only, consumers are write-only.

Putting objects in:

numConsumer.add(ln.get(0));
// numProducer.add(ln.get(0)); // doesn't compile; producer might be set to diff subtype
numConsumer.add(li.get(0));
// numProducer.add(li.get(0)); // doesn't compile; might be set to subtype
//numConsumer.add(lo.get(0)); // doesn't compile: might be set to subtype
// numProducer.add(lo.get(0)); // doesn't compile: Object doesn't extend Number

This time, it's only the consumer that can add any type of Number or Number subclasses. None of the producer calls work because whatever type the producer is set to, it could be incompatible with what it's getting.

Note that some of these examples would work if you added explicit casts.

Now, for reference, here's a cheat sheet with compilable code.

Thursday, April 7, 2022

Software Engineering: RAED for Permissions

 In any given important software being used by many people, access control is an important part of security. For example, I have the proper permissions to edit this blog and you do not.

But there's many ways to implement access control. For example, Unix-like file systems generally have read-write-execute permissions. A user, group, or "other" can each have a combination of permissions to read, write, or execute a file. An admin might use the chmod command to edit a user's permissions.

Windows implements file access control differently. There are permissions such as "Full control", "Modify", "Read & execute", and just "Read" that can be allowed or denied to a user or group.

Windows File Permissions

CRUD is another way permissions might be implemented. A user can be allowed to create, read, update, or delete files or other types of data in any combination.

At my last job I was tasked with coming up with an authorization system for our microservices. Rather than use some framework for authorization, I decided to build our own. I was replacing WordPress permissions, which were similar to CRUD. For any given type of page, a user might be allowed any combination of the creation, reading, updating, or deleting permissions, depending on what an admin had checked. For example, our online magazine had CRUD permissions. All of our customers could read the magazine. Specific content creators could create new articles and upload them. Editors could update anyone's articles to fix grammar, spelling, or links. Finally, admins could delete articles.

Designing permissions was important. We didn't want to give a user the wrong set of permissions, otherwise they might be allowed to delete important data. Or, with insufficient permissions, they might not be able to do their job.

I decided to use something I had previously created: RAED, a superior access control design for general-use permissions.

RAED stands for read-add-edit-delete and is a set of eclipsing permissions to be used with file systems, RESTful APIs, or anything else that requires access control. It's basically CRUD, but much better.

Other permissions become confusing when certain combinations are used. For example, what does it mean when you can write something, but you cannot read something? When would you be allowed to delete data without being able to update it?

With RAED, there is no confusion because if you have one level of permission, you have all of the permissions below (or to the left of) it. If you can add, then you can read. If you can edit, then you can read and add. And finally, if you have the delete permission, you also have the read, add, and edit permissions for that particular thing. For any given permission level, just makes sense to have the lower permission level. When will a user need to delete data, but should be forbidden from reading or editing that same data?

RAED is simpler to display. Instead of four sets of radio buttons (Allow/Deny) in CRUD, you have five radio buttons (the first one being no permissions). Example:

Database Permission:

RAED doesn't work for all access control systems and permissions, for example, when you only need a simple binary Yes/No for Can-Upload-Photo-Permission or similar. However, if this meets your needs, I highly encourage you use RAED.

Wednesday, March 23, 2022

Security: Choosing and Storing Passwords

Best: Password Manager
It's 2022. Everybody should be using a password manager to store and randomly generate different complex passwords for each website they use. There's a lot of good options on this front. Even the simple password managers built into your browser work pretty well. For most people, using Google Chrome, Mozilla Firefox, or iCloud Keychain is sufficient.

If you want to use a third party for whatever reason, LastPass served me well, although the free tier only allows you to store passwords on one device: mobile or desktop. I am now using 1Password, which is almost perfection, although it costs $3 per month.

I could write a whole article about which password manager is best, but the important thing is to use one. They generate secure passwords instantly, obviate the need to remember more than one password, store your passwords in a secure location, seamlessly sync mobile and desktop (except LastPass free tier), and tell you how secure each password is. Many password managers have other features like reporting to you when a password was found in a breach, informing you of your reused passwords, and keeping a history of used passwords.

But if you must, I'll list some other options.

How Hackers Crack Passwords
Before we get into how to generate a fancy hard-to-guess passwords, let's talk about why we're doing this and not just using "Password1!" for all your passwords.

The first way a hacker might get access to your account is to just guess your password. If it's just your name backwards, that's easy enough to guess. In fact, that was the password to my brother's electronic organizer in the 1990s (don't tell him I cracked it!). Similarly, hackers know to guess "password", "123456789", "qwerty" and other similar easy passwords.

Assuming the website you're using has good security (uses good hashes, with salt, etc.) another way a hacker might try to guess your password is to reuse one of your passwords from a website with bad security. For example, until a few months ago I still had an email account at excite.com, which had an insecure login page. That means anyone with basic hacking skills could steal my username and password for that site. Obviously, no one uses Excite for anything important anymore, but people do reuse passwords from site to site. If I reused my Excite password elsewhere, I'd be begging to be hacked at those other sites.

Lastly, a hacker might crack your password by simply trying all possibilities aka brute force. If the website you're using doesn't have very good security, a hacker can try different passwords rapidly. In fact, hackers can try a billion different passwords per second. Here's a chart showing how the speed of a cracking password is related to password complexity.

Chart from Hive Systems

This is why many websites require a password of at least 8 characters that must comprise uppercase letters, lowercase letters, numbers and symbols.

Next Best: Hidden, Secured Password Documents
As we have shown in the previous section, passwords should not be guessable, should not be reused across different sites, should have at least 8 characters, and should be composed of different types of characters.

The next best option to using a password manager is to generate these passwords yourself and keep them in a secure location. There are plenty of password generators on the Internet (ahem). The question is: how will you store your passwords securely? Your passwords are surely too complex to remember. You should also have access from your computer as well as from your phone.

For a while, I stored all my password in a text document that I uploaded to a mobile app. I changed the extension on the text document, so it wouldn't open in a word processor. The mobile app (IDrive) was secured with a password, so no one could open it without knowing one of my passwords.

This was a decent way to store my passwords, but was cumbersome and meant I had to manually sync my passwords by uploading my password file every time I changed or added a password. For those of you who don't like or trust password managers, this might work.

Perhaps Instead: Easy-to-Remember Passwords
There are several easy to guess password ideas:

In an ideal world you could simply remember your passwords using these hacks.

Actually...
But you won't. Memorable passwords won't work. The average person has 100 passwords, and whether you use the password generator or something super memorable, it doesn't matter: you simply won't remember all of your passwords. Secured storage is key and you can't get better storage than a password manager, as mentioned above. If you're very meticulous and organized, maybe you might not need a password manager, and instead can do something like I mentioned above with a hidden text file uploaded to the cloud.

But chances are you're not going to do that. You're going to have a Microsoft Word document or a physical notepad full of your passwords. And that's fine if no one ever will have physical access to your machine. But that won't fly at a professional workplace, on shared computers, or on a laptop owned by someone who travels a lot.

For most people in the modern world, a password manager is a necessity.