Thursday, 10 April 2025

VoxxedDays Amsterdam - Roundup

How to survive as a developer in the exponential age of AI - Sander Hoogendoorn

Technical Debt

Ward Cunningham said it as follows:

The danger occurs when the debt is not repaid. Every minute spent on code that is not quite right for the programming task of the moment counts as interest on that debt.

Entire engineeering organizations can be bought to a stand-still under the debt load of an unfactored implementation, object-oriented or otherwise.

Shipping first-time code is like going into debt.

A little debt speeds development so long as it is paid back promptly with refactoring.

Have you gone MADR? - Johan Hutting

Short blurb on Javadoc. Markdown now suppported in new Java versions.

Also was very interested in the new @snippet javadoc tag.

See for more information on MADR at https://adr.github.io/madr/

MADR stands for Markdown Architectural Decision Records

Bring the Action: Using GraalVM in Production - Alina Yurenko

Nice deep dive about the different things they're working on.

There's a list of libraries that have some sort of support regarding metadata at https://github.com/oracle/graalvm-reachability-metadata.

Quotes

A code generation tool that gets you 80-90% of the way there is like a boat that takes you 80-90% of the way.

You'll need to be a strong swimmer.

Jason Gorman

If debugging is the process of removing bugs, then programming must be the process of putting them in.

Edsger W. Dijkstra

References

VoxxedDays Amsterdam
https://amsterdam.voxxeddays.com/
MyBlog - Voxxed days amsterdam 2025
https://randomthoughtsonjavaprogramming.blogspot.com/2025/04/voxxed-days-amsterdam-2025.html

Thursday, 27 March 2025

Using different JDBC drivers

So I had the problem that I needed to connect to both Oracle databases as well as Postgres database.

And just including the dependencies in my Maven was not enough.

One of the drivers gets overwritten by another driver in the service provider mechanism.

At first I tried to register them by hand (which works):

DriverManager.registerDriver(new org.postgresql.Driver());
DriverManager.registerDriver(new OracleDriver()); return DriverManager.getConnection(url, user, password);

Or, you could do the extreme magic thing1 2:

Class.forName("org.postgresql.Driver");
Class.forName("oracle.jdbc.driver.OracleDriver"); return DriverManager.getConnection(url, user, password);

Which causes both drivers to run a static block registering themselves on the DriverManager in the same fashion as my code on top.

All this, because the service provider mechanism that automatically loads the JDBC driver, only allows one Driver to be registered3.

References

[1] StackOverflow - What is the difference between "Class.forName()" and "Class.forName().newInstance()"?
https://stackoverflow.com/questions/2092659/what-is-the-difference-between-class-forname-and-class-forname-newinstanc/2093236#2093236
[2] Baeldung - Loading JDBC Drivers
https://www.baeldung.com/java-jdbc-loading-drivers
[3] Baeldung - Java Service Provider Interface
https://www.baeldung.com/java-spi

Saturday, 15 March 2025

Git: recovering a dropped commit

So I was working, and I accidentally dropped one commit too many.

Oh dear.

So I thought, would there be a possibility of getting this one back? And I was quite surprised that there was.

A quick google search later, I found the information I put in the References below.

git reflog

The reflog or "Reference logs" contain a record when the tips of branches or other references were updated in the local repository. From my imperfect knowledge, it sounds like a database transaction log.

With it you can pinpoint the exact point in the records where your change/branche/commit was still there and reset the head "hard" to this SHA value.

git reset --hard d6b66766a9a

Bear in mind that the reflog is only available locally in your git repo, and it will get cleaned of old reflog entries in due time.

References

Rewind Blog - How to Restore a Deleted Branch or Commit with Git Reflog
https://rewind.com/blog/how-to-restore-deleted-branch-commit-git-reflog/
git - git-reflog - Manage reflog information
https://git-scm.com/docs/git-reflog

Tuesday, 4 March 2025

Kotlin Operator Overloading

So my colleague mentioned operator overloading, and how much fun it is.

So I wrote a little test.

package org.mrbear.kotlin.operators
import org.assertj.core.api.Assertions.assertThat
import org.mrbear.kotlin.AddressFactory
import org.mrbear.kotlin.Person
import org.mrbear.kotlin.PersonFactory
import org.testng.annotations.Test
class OperatorOverloadingTest {
@Test
fun testStandardInOperator() {
val list = listOf("A", "B", "C")
assertThat("A" in list).isTrue()
assertThat("D" in list).isFalse()
val str = "MRBEAR"
assertThat("E" in str).isTrue()
assertThat("H" in str).isFalse()
}
@Test
fun testCustomInOperator() {
val addressBook =
AddressBook(listOf(PersonFactory.alexanderGrahamnBell, PersonFactory.mrBear, PersonFactory.lordKelvin))
assertThat("Kelvin" in addressBook).isTrue()
assertThat("Mr. Bear" in addressBook).isFalse()
assertThat(PersonFactory.alexanderGrahamnBell in addressBook).isTrue()
assertThat(PersonFactory.smith in addressBook).isFalse()
}
@Test
fun testCustomNotInOperator() {
val addressBook =
AddressBook(listOf(PersonFactory.alexanderGrahamnBell, PersonFactory.mrBear, PersonFactory.lordKelvin))
assertThat(PersonFactory.alexanderGrahamnBell notIn addressBook).isFalse()
assertThat(PersonFactory.smith notIn addressBook).isTrue()
}
@Test
fun testCustomNotOperator() {
assertThat(PersonFactory.alexanderGrahamnBell.not()).isEqualTo(Person("notAlexander", "Graham", "Bell", 55, AddressFactory.addressInAmerica))
assertThat(!PersonFactory.alexanderGrahamnBell).isEqualTo(Person("notAlexander", "Graham", "Bell", 55, AddressFactory.addressInAmerica))
}
}
operator fun Person.not(): Person =
Person("not${this.firstName}", this.middleName, this.lastName, this.age, this.address)
infix fun Person.notIn(addressBook: AddressBook): Boolean = !(this in addressBook)
class AddressBook(private val listOf: List<Person>) {
operator fun contains(lastName: String): Boolean {
return listOf.map { it.lastName.uppercase() }.contains(lastName.uppercase())
}
operator fun contains(person: Person): Boolean {
return listOf.contains(person)
}
}

It works pretty good, but for infix functions it has a very high "syntactic sugar" and less about "real" operator overloading.

Also, the reference page in [1] indicates that for Infix functions, the precedence has fixed rules that do not (always) conform to precedence that we would assume.

My colleague told me that a number of infix functions were created for QueryDSL, so we could write a semblance of SQL in Kotlin, but the precedence tends to screw things up.

We removed these infix functions from our source code again.

So, use sparingly and only when it makes sense. For example if it makes your code a magnitude easier to read/reason about and preferable with as small a scope as possible.

References

[1] KotlinLang - Functions
https://kotlinlang.org/docs/functions.html#function-scope
Baeldung - Operator Overloading in Kotlin
https://www.baeldung.com/kotlin/operator-overloading
Baeldung - Infix Functions in Kotlin
https://www.baeldung.com/kotlin/infix-functions

Thursday, 20 February 2025

Kotlin: listOf() versus emptyList()

So I noticed that Kotlin tends to have several ways of doing the same thing1. Sometimes these are actually identical, sometimes there are subtle differences.

That makes things hard for me.

Let's take this trivial example.

@Test
fun testEmpty() {
val emptyList: List<String> = listOf()
val anotherEmptyList: List<String> = emptyList()
assertThat(emptyList).isEmpty()
assertThat(anotherEmptyList).isEmpty()
assertThat(emptyList).isEqualTo(anotherEmptyList);
assertThat(emptyList).isSameAs(anotherEmptyList);
}
view raw EmpyTest.kt hosted with ❤ by GitHub

There is no difference. The one thing you could mention is that emptyList() more accurately conveys what you are trying to do.

There's something similar in Java. Collections.emptyList() versus List.of(). The comments on [2] seems to be very interesting.

In Java one could argue that List.of() is new, so should be used. And we could assume that the Language Architects in Java wouldn't add a List.of() for no reason.

References

[1] Kotlinlanguage Reference - emptyList
https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/empty-list.html
[2] StackOverflow - List.of() or Collections.emptyList()
https://stackoverflow.com/questions/39400238/list-of-or-collections-emptylist

Thursday, 6 February 2025

Java - Behaviour of Equals in Collections

I just thought I'd write some things down that I already know, but sometimes it's nice to see this proven.

It's a very very beginner Java subject, but people won't fault me for blogging about it.

It might be of some use to somebody.

public class EqualsTest {
public enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY}
/**
* Sets in Java are un-ordered. Two sets are equal if they contain the same elements.
*/
@Test
public void testEqualsSet() {
Set<Day> weekDays = Set.of(Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY, Day.THURSDAY, Day.FRIDAY);
Set<Day> otherWeekDays = Set.of(Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY, Day.FRIDAY, Day.THURSDAY);
Set<Day> weekendDays = Set.of(Day.SUNDAY, Day.SATURDAY);
Set<Day> otherweekendDays = new HashSet<>(Set.of(Day.SATURDAY, Day.SUNDAY));
assertThat(weekDays.equals(weekendDays)).isFalse();
assertThat(weekDays.equals(otherWeekDays)).isTrue();
assertThat(weekendDays.equals(otherweekendDays)).isTrue();
}
/**
* Lists in Java are Ordered. A different ordering, means two lists are not equal.
*/
@Test
public void testEqualsList() {
List<Day> weekDays = List.of(Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY, Day.THURSDAY, Day.FRIDAY);
List<Day> otherWeekDays = List.of(Day.TUESDAY, Day.WEDNESDAY, Day.THURSDAY, Day.FRIDAY, Day.MONDAY);
List<Day> weekendDays = List.of(Day.SATURDAY, Day.SUNDAY);
List<Day> otherweekendDays = List.of(Day.SUNDAY, Day.SATURDAY);
assertThat(weekDays.equals(weekendDays)).isFalse();
assertThat(weekDays.equals(otherWeekDays)).isFalse();
assertThat(weekendDays.equals(otherweekendDays)).isFalse();
}
/**
* So, what happens if we use TreeSets, that are Ordered?
*/
@Test
public void testEqualsTreeSet() {
Set<Day> weekDays = new TreeSet<>(Set.of(Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY, Day.THURSDAY, Day.FRIDAY));
Set<Day> otherWeekDays = new TreeSet<>(Set.of(Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY, Day.FRIDAY, Day.THURSDAY));
Set<Day> weekendDays = new TreeSet<>(Set.of(Day.SUNDAY, Day.SATURDAY));
Set<Day> otherweekendDays = new TreeSet<>(new HashSet<>(Set.of(Day.SATURDAY, Day.SUNDAY)));
assertThat(weekDays.equals(weekendDays)).isFalse();
assertThat(weekDays.equals(otherWeekDays)).isTrue();
assertThat(weekendDays.equals(otherweekendDays)).isTrue();
}
}
view raw EqualsTest.java hosted with ❤ by GitHub