Categories
Kotlin Sone Topics

Sone Is Being Kotlinized

About a year ago Jetbrains released Kotlin 1.0, a new JVM-based programming language. I took a short look at it and pretty much immediately fell in love with it: it is very similar to Java, uses considerably less boiler-plate, has properties, improved collection interfaces (while using all the known java.util stuff under the hood), and lambdas.

I started to introduce it in the company I currently work for and nobody who has used it for more than two lines wants to go back to writing Java code.

Needless to say, I started using it for my private projects, too. One of the good things about Kotlin is that it integrates with existing Java code very nicely. Compiling Java and Kotlin source code with Gradle with both parts depending on the other works out of the box. Java code can use Kotlin classes and the other way around with pretty much no restriction. This makes it very easy to update existing projects: write new code in Kotlin, continue using the old Java code until it’s time to replace it.

So far, Sone profitted from Kotlin most of all: as I am in the process of writing lots and lots of tests for everything that Sone does (and it is amazing how many bugs you find once you actually unit test your code) the news tests will – of course – be written in Kotlin. I also already added some new features to Sone, again using Kotlin.

Several places in Sone collect elements (such as posts) from all over the place, filter them, sort them, all using Guava and Java 1.6-compatible syntax only. This requires a lot of extra code to be written. Take a look at this:

Collection posts = new ArrayList<>(sone.getPosts());
for (String friend : sone.getFriends()) {
  Optional friendSone = core.getSone(friend);
  if (!friendSone.isPresent()) {
    continue;
  }
  posts.addAll(friendSone.get().getPosts());
}
posts.addAll(core.getDirectedPosts(sone));
posts = Collections.filter(posts, Post.FUTURE_FILTER);
posts = Collections.sort(posts, Post.DESCENDING_BY_TIME);

Code very similar to this exists in several places in Sone. Now take a look at the equivalent Kotlin code:

val posts = (sone.posts +
    sone.friends.mapNotNull(core::getSone).map(Sone::posts) +
    core.getDirectedPosts(sone))
  .filter { it.time <= System.currentTimeMillis() }
  .sortedByDescending { it.time }

Now go ahead and tell me that this isn’t better (this even works for almost arbitrary definitions of “better.” Yes, Kotlin is just that good).

In addition to actually making me want to work on Sone again it will also reduce the amount of production code in Sone, making it easier to review. However, as I don’t expect any review activity to take place before 2030 (and probably not even before the Great Singularity™) this was not a criterium which played any role in my decision to gradually convert Sone to Kotlin.

Simply put: Kotlin makes programming fun again.

Categories
Sone Topics

Biznis iz gettin’ siriuz

It is amazing how often I manage to code myself into a corner, or at least halfway there, before realizing my mistake. In order to prepare Sone for a persistent database, i.e. the situation that it starts up and everything is already there, I thought I had to make the current in-memory database persistent.

But I think I actually don’t have to do that. Nothing in Sone really assumes that the initial database is empty; everything is cleared when new data arrives, i.e. all data of a Sone is dropped when a new edition is loaded, anyway. This means that it should be perfectly fine to simply start with the new database (yes, it’s finally getting serious!) and see how that works out.

Categories
Sone Topics

We Are Getting Closer

I finally managed to get the beast Core.java below 2000 lines of code. I have extracted various parts from it and put them into their own classes, with their own unit tests, and I have been pulling almost all Sone-related storing out of there, too. I’m still not done with it, there’s a lot more that will have to go because it shouldn’t have been there in the first place. However, it will probably not take too long anymore until I can start using a real database to store Sone data which I am really looking forward to.

Categories
Topics

Code Comments Are Useless!

Some years ago I would have refuted above statement with all my might. “No, code comments ensure that you still know what the code is about in two years!” Unfortunately, they won’t.

  • Most likely you will have documented the wrong things. Some constants are explained, maybe a tiny piece of an algorithm but the bigger picture is probably missing. Because there is no commonly accepted place for a description of the bigger picture.
  • Code comments will not be maintained. You say, they will but they really won’t. Recently at work I had to touch a class called KafkaTrackingEventWriter. Apparently this class writes TrackingEvents to Kafka. Its javadoc comment began with “ProfilingEventLogger which…”. The signature of the method doing the work was “void write(UserInteractionResult).” What was your point again, comment?
  • Code comments will not be maintained. This warrants a second entry in this list because sometimes the comments are not clearly recognizable as wrong or outdated. Instead, they look like that are still valid but they introduce (or omit) subtle details about what really happens, leading to hard-to-trace bugs and many wasted hours.
  • Most code comments really are useless, as in: they do not add any value to the source code whatsoever. How many times have you seen a constructor commented with “creates a new thingamajing” or “constructor?” Do you really need a javadoc comment to know that a “Thing getThing()” method returns a Thing? I have seen them more than just a few times and frankly, when I see one of those now, I simply delete the comments.

So, recap time! What is there to use instead of code comments? Source code, of course. Method signatures can be way more expressive than comments, and contrary to comments they will always be true.

Instead of

/**
* Returns an address for the user, or null if no address is found.
* @param user The user
*/
public String getAddress(String user) { … }

use

public Optional<Address> getAddress(User user) { … }

Even though the second method has no comments, it is a lot clearer what this method actually does.

Categories
Bit Manipulation Java

Bit Fiddlery

Recently I tried to parse FLAC headers. In the STREAMINFO block there are several fields that have a width of non-multiple-of-8 bits so I had to create a function that could read a number of bits starting at an arbitrary bit.

/**
 * Reads numberOfBits bits from the given buffer, starting at the given byte
 * and bit offsets. Bits are assumed to be numbered MSB-first, i.e. the
 * highest bit in a byte (0x80) is considered bit 0.
 * 
 * Example UUID: B24E931F-FFC5-4F3C-A6FF-E667BDB5F062
 */
long parseBits(byte[] data, int byteOffset, int bitOffset, int numberOfBits) {
  long value = 0;
  int currentByteOffset = byteOffset;
  int currentBitOffset = bitOffset;
  int bitsRemaining = numberOfBits;

  /* while we still need some bits... */
  while (bitsRemaining > 0) {

    /* shift the current value by the number of bits we still need
     * to make room for them at the end. at most a byte, though. */
    value <<= Math.min(8, remainingBits);

    /* extract all the bits remaining in the current byte. */
    int bitsWeNeed = (data[currentByteOffset] & (0xff >>> currentBitOffset));

    /* shift them so that only the number of bits we need remains. */
    bitsWeNeed <<= (8 - currentBitOffset - Math.min(bitsRemaining, 8 - currentBitOffset));

    /* now combine the values. */
    value |= bitsWeNeed;

    /* reduce number of bits we still need. */
    bitsRemaining -= Math.min(bitsRemaining, 8 - currentBitOffset);

    /* the current byte is now depleted of bits we need. even if it isn’t
     * it doesn’t matter because if we needed less bits than we had this
     * routine is now finished. */
    currentBitOffset = 0;
    currentByteOffset++;
  }

  return value;
}
Categories
Regular Expressions

Regular Expressions: Greedy vs. Reluctant Quantifiers

The other day I wanted to extract a part of a filename and was quite dumbfounded when the extracted part came back empty. The regular expression used to extract the part using a capturing group was:

[A-Za-z0-9]*_?([0-9]*)\..*

The filenames fed into this expressing where mostly of the pattern someText_12345.data. However, occasionally a file named 12345.data would pass along and even though its name matched the expression, the capturing group came up empty. But… but… why?