2023/12/04

@sebi_io and I will be pair programming #AdventOfCode day 4 in #Kotlin later today šŸ‘‰ https://www.youtube.com/watch?v=I0nCFMDkPNo Come join us live! Nothing is scripted but hopefully, there will be some refactoring šŸ™ƒ

2023/12/02

Short-lived pull requests are fine from the CI point of view. But if they’re so short, why bother with the PR bureaucracy? What about reviewing commits and fixing anything that’s wrong? Maybe even talk to the author of the code šŸ™ˆ

2023/12/01

This is your regular reminder that long-lived pull requests are missing the whole point of CI. Great video by @davefarley77 šŸ‘‰ https://www.youtube.com/watch?v=v4Ijkq6Myfc

2023/11/29

In case you missed it, there is a new book by @kentbeck Tidy First?: A Personal Exercise in Empirical Software Design 🄳

2023/11/28

When using Result/Either type in #Kotlin, it can be tricky to make sure they are always handled. Could we please get annotations to mark types that cannot be ignored? AFAIK this functionality has been in #Rust for years! See https://youtrack.jetbrains.com/issue/KT-12719

2023/11/26

Do you know any good resources (blogposts, tutorials, katas or videos) about using Result/Either types in #Kotlin?

=== Answers ===

2023/11/25

If you are/were at the #devfestberlin2023 today, you can find the slides and code from my talk here https://github.com/dkandalov/gilded-rose.

2023/11/24

Fundamentally, #Kotlin coroutines is compiler transforming code into a state machine. They are in stdlib, e.g. Sequence builder. Nothing to do with async. And there are async coroutines in kotlinx.coroutines built on top. Both are ā€œcoroutinesā€. Obviously, not so obvious.

2023/11/22

I wish #Kotlin stdlib had Flow-like API with onStart/onComplete/catch/etc. for Sequence/Iterable. And maybe cancellation by making them AutoClosable (?) šŸ™ˆšŸ¤” (I’m sure there are some good discussions on youtrack, slack and Kotlin forum.)

2023/11/21

How wrong is it to use #Kotlin Flow with this? 😬

fun runOnTheCurrentThread(block: suspend () -> Unit) = block.startCoroutine(NoOp) object NoOp : Continuation<Unit> { override val context = EmptyCoroutineContext override fun resumeWith(result: Result<Unit>) {} }

=== Reply from Simon Vergauwen ===

Pretty bad, because context preservation breaks with EmptyCC. Otherwise it’d be similar to GlobalScope.launch(NonCancellable + Dipsatchers.Default) { }.

2023/11/20

Another idea is to have more terms than just ā€œtech debt.ā€ For example, distinguish it from ā€œtech underinvestmentā€ as suggested by @natpryce. Maybe a separate term for code ageing, when code becomes obsolete because of programming language and technology changes.

2023/11/19

It’s unfortunate that ā€œtechnical debtā€ is the only widespread term we have. Maybe ā€œtechnical shortcutsā€ is a bit more descriptive and less metaphorical šŸ¤” I also like a bit more opinionated ā€œunsuitable codeā€ by @lukesleeman.

2023/11/18

Another deceitful metaphor is technical debt. The problem is that it implies the predictability of debt. In practice, it’s often a trap with no clear way out (like piling up pieces in Tetris). Compounded by the sunken cost fallacy, the ā€œdebtā€ is even less likely to be untangled.

2023/11/16

In case anyone needs a podcast recommendation, Troubleshooting Agile is one of my all-time favourite and probably not very well-known podcasts. Thank you, Jeffrey Fredrick and Douglas Squirrel, for producing great content! See also https://agileconversations.com

2023/11/15

Another annoyingly bad metaphor is #git blame. It doesn’t explain how the tool works and suggests harmful behaviour. Even worse, the command itself is too surface-level and not good at finding commit with the actual change šŸ™„ (I mostly use ā€œShow History for Selectionā€ in #IntelliJ)

2023/11/14

On the topic of wrong metaphors, I’m still annoyed that most #git projects used a tree-branching metaphor mixed with master/slave, and when there was a chance to change the ā€œindustry standardā€, most went for ā€œmainā€ (maybe related to pipes 🤷) instead of ā€œtrunkā€ šŸ˜’

2023/11/12

In case you happen to be in Berlin in a couple of weeks, I’ll be at GDG DevFest presenting the Gilded Rose refactoring kata. Come say hi. I’m also happy to pair on the kata and maybe record it (as I used to do pre-pandemic).

2023/11/11

Old startup idea: ā€œTwitterā€ for codebases where you could follow/like/reply to functions/classes/files/branches/people. A similar thing suggested by Kent Beck: https://tidyfirst.substack.com/p/idea-codefeed. Does anyone want to do a proof-of-concept? Maybe in #Kotlin? KMP? šŸ˜±šŸ™ˆ

2023/11/10

Somewhat surprisingly, the ā€œunimportant implementation detailsā€ like using ā€œeventually {…}ā€ in tests can have a cascading effect via slow CI/deployment on software design, people behaviour, and organisation overall. Similarly, a slow compiler/IDE is never about time.

2023/11/09

Another possible side effect of slow CI/deployment is over engineering. Some of it is a rational response to not being able to fix things quickly. Some, I suspect, is keeping yourself entertained which is then post-rationalised to be necessary.

2023/11/07

Working in an environment with slow CI/deployment, it’s not impossible to be upset when someone breaks deployed software and it takes hours to fix. So, if you’re not careful, this creates peer pressure on the team, and maybe you get a bit of pressure from yourself.

2023/11/06

Slow CI builds increase the time it takes to fix things after deployment. At the same time, larger code changes (encouraged by slow CI) are more likely to have problems. That creates a higher stake environment in which you really don’t want to make a mistake šŸ˜“

2023/11/05

The problem with slow CI is not just the time it takes but also the behaviours it encourages. Waiting a couple of hours for a minor change seems like a waste, so it’s tempting to batch up a few changes or do something else in parallel, which increases work-in-progress.

2023/11/04

Overall, eventually {...} in tests is a code smell, similar to delay(5.seconds) waiting for the clock to move forward. There are ways to avoid it, and it’s ultimately your choice. Continuous integration is not supposed to be ā€œcontinuousā€ because the build takes 24 hours.

2023/11/03

To be fair to projects with eventually {...} in tests, it can be hard to control concurrency or change design with tech decisions made a while ago and the code tied to a framework that does its own thing. You just end up copy-pasting eventually in the name of consistency 😿

2023/11/02

There is no magic avoiding eventually {...} in tests. The basic answer is to have control over concurrency (like controlling time with the Clock). If it’s the code you can modify, then change its design. If it’s an external technology, wrap it in a minimal API and use a fake.

2023/11/01

Another problem with eventually {...} is that it’s easy to sprinkle tests with it but can be really hard to remove because the design won’t let you control concurrency and it’s hard to refactor with the build being slow and flaky. It’s a trap! šŸ˜’ #testing #rant

2023/10/31

The reason why using eventually {...} in tests is not a good idea is that it will make your build slow and non-deterministic. Retries will slow down passing tests, timeouts will make failures even slower, and failure messages will read like ā€œsomething didn’t happen on timeā€ 🤷

2023/10/30

If you use something like eventually {...} function all over the tests (which retries with timeout the lambda until it succeeds), the chances are you’re doing it wrong. Ideally, refactor concurrency you’re waiting for out of the core logic and test concurrent things separately.

2023/10/29

To be clear, I suggest projectional editor for #Kotlin/#Java not just for formatting, but for overall code layout and how we experience working with codebases. For example, ā€œnavigationā€ could show functions next to each other, or maybe hide private fields or some ā€œobviousā€ types.

2023/10/27

Since it’s nearly impossible to ā€œwinā€ any code style/formatting argument, could we have a projectional editor for #Kotlin/#Java, e.g. as an IntelliJ plugin please. It has to be clever though to project into the ā€œcurrent code styleā€ in text format 🧐

2023/10/26

I wonder how much code layout (let’s say just within a file) affects how we think about programs. Is there any research? šŸ¤”šŸ”¬ What if changing the layout could shift overall project design to be less data centric for example?

2023/10/25

Thinking about details first/last in #Kotlin classes, the default style is neither. It seems to be guided by object initialisation and execution order (init fields, invoke constructor, public/private functions). As a reader you’re supposed to play the role of a computer I guess 🤷

2023/10/24

Timeless question: define details first or last? In particular, in a #Kotlin file should data classes used in an interface be defined before or after the interface? If details last, then shouldn’t all fields/properties be at the bottom of the class? Do you, should you care?

=== Reply from Jordan Stewart ===

Most important thing first. Probably not quite right, I like to think of it as similar to writing’s ā€œinverted pyramidā€ — https://en.m.wikipedia.org/wiki/Inverted_pyramid_(journalism)

=== The hill I’m happy to join Chris Oldwood on ===

2023/10/23

This is a somewhat obvious thing to say but if you use randomly generated objects in tests, you really need to have a seed. Otherwise, it’s a lot of fun with not very reproducible failures and builds. Also don’t assume that two random values are not equal šŸ™ˆ

2023/10/22

Thinking about namespace pollution in #Kotlin via extension functions, is funĀ Iterable<T>.foldResult()Ā {...} a good idea? The problem is that foldResult will appear in the auto-completion list for any Iterable even if it’s not using Result type šŸ¤” https://github.com/fork-handles/…iterables.kt

2023/10/20

In #kotest tests are just functions. So they can be extracted into other extension functions like this:

fun FunSpec.someTests() { test("1") {...} test("2") {...} }

Clever but the problem is that you can’t run just one test from IDE šŸ˜’ Use abstract class instead? #UXfail

2023/10/19

Back to #kotest rants. Because kotest has ā€œbuilt in coroutine support at every levelā€ when an assertion fails, you can’t navigate to the matcher source code from the stack trace (Kotlin coroutines are stackless). So good luck if the error message is not very clear.

2023/10/18

Random #IntelliJ tip. You can select multiple items in lists/trees and apply action to all of them. E.g. select files in project view, press enter and all selected files will be open. The same works with find/show usages. Or abstract function can be implemented on all classes by using ā€œselect allā€ via ctrl/cmd+A, then ā€œenterā€ šŸ‘Œ

2023/10/17

The reason lambda flavours in #Kotlin could be useful (e.g. with different/combined background colour in IDE) is that the meaning of indentation is diluted by ā€œboringā€ let/apply/…, parameters on separate lines, nested functions, etc. Also .map() on collections vs Result type 😵

2023/10/16

I wonder if #Kotlin contracts could capture lambda flavours and maybe visualise them in IDE šŸ¤” E.g. let runs lambda once, ?.let maybe once, forEach many times, executor.submit{} runs on a different thread later. (Also haven’t heard much about contracts for a while.)

2023/10/15

To be fair, with ?: extracted into a function and using let with reference is an interesting alternative to if/else. Thanks to @natpryce for suggestion.

fun Int?.toJson(): JsonNode = this?.let(::IntNode).orNullNode() fun JsonNode?.orNullNode(): JsonNode = this ?: NullNode.instance

=== Reply from @natpryce ===

Nice. And to avoid duplicating logic, you could define:

fun <T : Any> T?.toJson(toNode: (T) -> JsonNode): JsonNode = this?.let(toNode).orNullNode()

And then define:

fun Int?.toJson() = toJson(::IntNode) … etc …

2023/10/14

Which of these Kotlin one-liners do you prefer?

fun Int?.toJson() = if (this != null) IntNode(this) else NullNode.instance

or

fun Int?.toJson() = this?.let { IntNode(it) } ?: NullNode.instance

I’m in favour of if/else, ?.let is overrated and can be against the ā€œgrainā€ of Kotlin šŸ˜¬šŸ™ˆ

2023/10/13

In case you haven’t seen it yet, here is a perfect Friday video content: The Art of Code by Dylan Beattie (the classic recording at NDC London).

2023/10/12

This is your regular reminder that pull requests are a waste in a typical company environment. PRs make you cosplay continuous integration instead of actually doing it. See this blog post by Benji Weber for details https://benjiweber.co.uk/blog/2020/02.

2023/10/11

Would you rather have a feature/tool which depends on some non-public API (and can break in the future without notice) or not have the feature/tool at all? I’d choose the first option. Also in my experience some public APIs end up as volatile as internal ones šŸ¤·šŸ¤”

2023/10/10

#IntelliJ tip for #Kotlin. You can search for class default constructor (instead of class usages) by positioning cursor before the paren ā€œ(ā€œ. Like this class Foo|(val n: Int) and invoke ā€œShow Usagesā€ action. I found it by chance. Wish it was more discoverable though 🧐

2023/10/07

What about namespace ā€œpollutionā€ by extension functions in #Kotlin? E.g. a library with funĀ Any?.print() (yes, it’s a #kotest #rant again) will add print() to code completion popup for all objects. Sure, IDE can deprioritise it, but maybe don’t do it in the first place?

2023/10/06

More #kotest #rants… shouldHaveSize() is helpful enough to print the whole (actual) list when sizes don’t match. Good idea unless the list contains large data classes. Good luck scrolling around Gradle output for the failure message. OTOH, it could be symptom of a bad test šŸ¤”

2023/10/05

Another #kotest #rant is that most of its matchers don’t show diff window in IntelliJ with JUnit5 runner. It tries but most matchers throw AssertionError (no diff) and some AssertionFailedError (has diff) šŸ¤·šŸ˜’ Makes you wonder if kotest authors actually use it via IntelliJ.

2023/10/04

Kotest has eventually() function which retries lambda until it succeeds or times out. Not the best idea to use it across all tests in the first place, but in addition kotest prints stack trace from the first and the last failure, so you end up scrolling down šŸ¤¦ā€ #kotest #rant

2023/10/03

Thinking about comments I’m definitely in the camp of avoiding comments in the code unless it’s really necessary. It’s better to have a good variable/function name or a test case to explain a subtle detail. This includes test case names which look like wordy comments šŸ™ˆ

2023/10/02

If you care about how the source code is formatted, how variables/functions/etc. are named, then it might be worth caring as much about comments. Re-read them after writing, use spell checker and maybe start comments with a capital letter (as if it was a sentence because it is)?

2023/10/01

Another interesting idea is to have stack traces with granularity down to expression/statement instead of just line number. They might need to be aware of the testing library to trace creation of matchers, etc. Not easy to implement for #Kotlin on the JVM and even harder for Kotlin multiplatform šŸ™ˆ

2023/09/30

In many environments where we run tests (locally, CI pipelines) we have access to the source code. When a test fails, why not use it to show code of the failed line/paragraph before the failure message? šŸ¤”

As couple people have pointed out there is https://github.com/laech/java-stacksrc. I haven’t tried it yet, but it looks promising.

2023/09/29

The History of Cursor Keys https://www.youtube.com/watch?v=BytowtVycc0 Fun to see all the crazy cursor keys layouts from the past. Although for software development I really prefer alt+IJKL, see https://github.com/dkandalov/ijkl-shortcuts-plugin Everything else is suboptimal! šŸ™ˆ

2023/09/28

Most assertion libraries (in #Kotlin and other languages) reimplement language features (not, or, and, equals etc) and standard library (contains, isEmpty, etc). I wish there was more effort to make tools like https://github.com/bnorm/kotlin-power-assert work really well.

2023/09/27

To be fair, the previous example could use matcher composition where beSuccess() is not an expression (it will be type-safe with #Kotlin contracts). Thanks to @sf105 for pointing that out.

val items = listOf(...) storage.upload(items) should beSuccess() storage.listAll() should (beSuccess() and equalTo(items))

2023/09/26

A better example of Result.expectSuccess() used as an expression. If Result is treated like checked exception, it should be ok to handle it in any part of the test šŸ¤”

val items = listOf(...) storage.upload(items).expectSuccess() storage.listAll().expectSuccess() shouldEqual items

2023/09/25

Thinking about the example with Result.expectSuccess() a bit more complete test might look like this:

val expected = random<Foo>() val actual = Foo.parse(expected.toJson()).expectSuccess() actual equalTo expected

Which pushes one of the assertions into the ā€œwhenā€ step šŸ¤”

2023/09/24

I wish more #Kotlin assertion libraries had assertion functions as expressions so that they could be chained. For example:

result.expectSuccess() equalTo 123 httpResponse.expectStatus(OK).body.equalTo("{some json}")

2023/09/23

This is your regular reminder that pull requests is a waste when working with people you know and trust (e.g. same company). Here is a more detailed reasoning by @d_stepanovic https://vimeo.com/842233600 (thanks to @quii for the link) #pullrequest #programming #softwareengineering #coding

2023/09/22

You might have noticed that most meetings and conferences follow the same pattern of one person talking and everyone else listening. (Ok, maybe enterprise ā€œagileā€ made standups and retros more widespread.) But is it the only way for a group of people to collaborate or share information? Not at all! Welcome Liberating Structures šŸ‘‰ https://www.liberatingstructures.com/ls-me

2023/09/21

Random #IntelliJ tip. There is ā€œShow Gradle Daemonsā€ action which shows daemons with pid, status, etc. and lets you stop them. It’s not in any menu, but you can invoke it via ā€œFind Actionā€ (cmd+shift+A or ctrl+shift+A). As with most tips it’s probably a UX failure… I mean an opportunity for improvement šŸ™ˆ

2023/09/20

Here is another basic function I wish was in #Kotlin stdlib

inline fun <T : Any, R> T?.ifNotNull(f: (T) -> R): R? = this?.let(f)

This is really just ?.let but I think ifNotNull follows the Kotlin way by being more explicit.

2023/09/19

Not many people consider this but CONSTANTS DON’T NEED TO BE UPPERCASE. They’re not the most important thing in the code and don’t need the emphasis (e.g. unlike mutable global variables). The convention dates back to the early days of C and the need to distinguish symbolic constants defined as macros from variables šŸ‘‰ https://accu.org/journals/overload/22/121/wakely_1923 It’s never too late to stop the cargo cult! Can we have it in #Kotlin 2.0 please? šŸ˜…

2023/09/18

One of the basic functions I wish was in #Kotlin stdlib (originally by Duncan McGregor)

fun <T> T.printed(): T = apply { println(this) }

So you can do foo.update().printed() without extracting a variable and using a separate line for println().

2023/09/17

Rick Beato has a great YouTube channel. In particular, ā€œWhat Makes This Song Great?ā€ videos, e.g. Metallica - ā€œMaster of Puppetsā€ Breakdown. I’m wondering if there is something similar for #software analysing/appreciating/criticising well-known projects. Should John Carmack or Dave Farley do it? šŸ˜…

2023/09/16

Does the ā€œSmall adviceā€ in this talk mean that explicitly specifying return type for public functions will noticeably improve compiler/IDE speed? If yes, it sounds like an inspection šŸ¤” #Kotlin #IntelliJ

There is ā€œPublic API declaration with implicit return typeā€ inspection in ā€œKotlin->Other problemsā€ disabled in the default profile. If it’s really going to make difference and is recommended in general, should it be enabled then?

2023/09/15

I’m pretty sure I read a few years ago that #Mastodon (social network) was named after Mastodon (a metal band). However, most articles I can find now are saying Mastodon (social network) was named after the animal. Does anyone know more of the backstory? https://www.youtube.com/watch?v=s6WGNd8QR-

2023/09/14

Videos from JVM Language Summit 2023 https://www.youtube.com/playlist?list=PLX8CzqL3ArzW90jKUCf4H6xCKpStxsOzp I enjoyed ā€œThe Challenges of Introducing Virtual Threads to the Java Platformā€ šŸ™‚

2023/09/13

It might be the ā€œold man yells at cloudā€ problem but many tools which are supposed to empower developers are achieving the opposite. More levels of indirection, more configs, slow pipelines, etc. instead of faster feedback loops (on faster modern hardware). There is a joke that k8s is a conspiracy by big tech to slow down the rest of the industry 😳

2023/09/12

Here is the simplest way to implement any interface in #Kotlin šŸ™ˆ Aka mocking library in four lines of code. (I didn’t come up with it though so can’t take the credit.)

class MyList<T> : List<T> by strictMock() inline fun <reified T> strictMock(): T = java.lang.reflect.Proxy.newProxyInstance( T::class.java.classLoader, arrayOf(T::class.java) ) { _, _, _ -> throw NotImplementedError() } as T

2023/09/11

If you’re interested in #Kotlin, KotlinConf on May 23-24 next year will be a good excuse to visit Copenhagen. It’s the same venue as in 2019 which was quite nice. And don’t forget the best way to get the ticket is by submitting a talk https://sessionize.com/kotlinconf-2024 šŸ™ˆ (As always, you don’t really need to be an expert in the field to do a good talk!)

2023/09/10

Super slow search for #Kotlin data class components in IntelliJ is a massive contributor for me not enjoying Kotlin as much as I could. It feels that problems like this one are too fundamental to not be fixed on day one 😐 Unreliable/slow search defeats the whole point of IDEs.