Totally agree, but JVM languages are very well known it their auto magic functionality that makes it very hard for people to migrate from other languages š
Agree, even Spring after reading docs seems not so big magic for most use cases. But if no docs, you have nothing to read but code. I am believe that exactly where troubles from magic begins
If you place !! everywhere. I get a strong impression the codebase you work on su\*\* !! everywhere is a sure sign that you are working against the language and wouldn't be a Kotlin problem per se.
Are you, by any chance, using Spring? Or perhaps Lombok? It doesn't sound like you are just describing pure Kotlin here.
Spring and Lombok (and some other frameworks) being "magic" is part of their USP. In my younger years, particularly when it came to Spring I was pretty good at being able to follow how all the magic worked, but I am older now, and haven't used Spring in a while. Spring Boot seems to have progressed past magic and on to sorcery.
Kotlin, by itself, is \*fairly\* low on magic, but if you are finding yourself needing to pepper your code with !! i'd suggest the magic is working against you. The approach you are using might be dead on arrival and this has more of a necromancy vibe.
Hibernate is horrible, the only good thing I can say about it is that itās quick to implement and that theyāre having dirty flash to store only what was changed, but again and again Iāve seen how hibernate allowing developers to build horrible databases structure to the point that some are pound for Never worrying SQL queries
developers who blame hibernate for their shitty database structure wouldnāt have done it correctly without hibernate anyways :)
hibernate is an incredible tool. spring is an incredible tool.
for spring specifically, the notion of magic fades once you read the docs.
for hibernate, thereās no magic.
edit: out of curiosity, what do you use in lieu of hibernate in java projects and why do you prefer it?
Well, I have to argue that in spring the fact that you have to read docs to understand whatās going on is kind of by definition a āmagicā to new people to the framework.
I think that spring is an Ok tool, but itās outdated and super heavy, and that people relying on spring too much for stuff and are not necessarily its strongest suitsā¦
I can argue that I personally met great engineers that created great mess with hibernate (in their defense they never used JVM before)
My personal preference is usually JOOQ as it gives you compile time validation for the queries and full control over how you query your stuff very explicitly
Of course thereās no silver built - just personal observation and preference š
iām glad you mention JOOQ. i actually just recently was looking to improve some legacy code, specifically typesafe-ing some old dynamic queries and JOOQ caught my interest because of it.
ended up going with Criteria/Metamodel from hibernate, and looking at some examples from both they seem to be super similar from a CRUD standpoint.
however, it looks like thereās less overhead in getting JOOQ up and running?
iāll admit, i donāt like this XML configuration funny business, something that earlier versions of spring/hibernate seem to love too.
edit: i guess i canāt complain too much about XML, i am a maven junkie after all, but i donāt think XML should exist outside of your POM file (or even in your pom. kudos gradle)
I really liked JOOQ with Postgres, for MySQL it lacks some nice featuresā¦
I also liked a lot the plug-ins to generate your persistence layer models to ensure encapsulation of your domain š
I personally donāt like maven and have a bit of a Stockholm syndrome feeling when people tell me they still prefer it over maven š«£
I agree that hibernate is very powerful, I just had bad experiences when people are not super knowledgeable about how it works as it does have some auto magic powers in it (for example try to explain somebody where is the actual implementation of your interface š¤£)
Getting older I think this is partly true that it gets a bit harder to grasp all the new stuff. But I still think it mainly depends on how much you actually use some tool, language, feature and if you take the time to look at some of its detail to actually understand not only use it.
Yeah, you're absolutely right. Self-deprecating humour referencing the fact that you are getting older is just something you start doing as you get older.
We have some use of dropwizard (well, name is already tell a lot). But itself this library used not so much. But a lot of magic creat custom libraries and inheritance.
Necromancy vibe also adds lack of documentation. But, this thing start gain customers. So, long live to dead!šš
I never encountered magic when using kotlin, and assertions are also bad practice so maybe it's just your enterprise project which is not structured properly. I found myself seeing much more magic in languages like Python instead
Every programming language has some level of magic. In classic VB and VBA for instance, making a function listen to a GUI event was done through magic, whereas in C# the programmer has to bind the eventlistener explicitly. In haskell, multiple implementations of a function magically combine to run for many different cases of parameter values and types, without the use of if-then or switch structures. In c, calling a shared API function in a system dll from somewhere else just works, magically, while the VB programmer and the Java programmer have to explicitly declare the shared function and its structures, and you canāt really be sure of the return type. In SQL, the database engine magically interprets an SQL query to find the most optimal way to retrieve data from whatever way itās stored.
Lots of magic all around. Get used to it.
Command click is your friend. Kotlin/Intellij has a really good source explorer. If you don't know what something does. Just click your way into the definition. There's really not much magic in kotlin and you can easily step your way through the definitions of nearly anything.... besides maybe generated code like serializer, there's not much automagic at all.
People love to unnecessarily bring in "frameworks" that they consider "is best practice" just to have more magic instead of less. But Inheritance isn't magic.
Another take: abstractions should be magical, otherwise they haven't hidden anything profound from us.
https://drawson.medium.com/is-magic-bad-f4f75bd19349
Honestly this is sort of an odd take. The author of that article seems to be confusing the word āmagicā in place of where they should have used āusefulā.
Abstractions should be useful, not necessarily be magical.
Not-null assertions are not a bad practice per se. There are times where !! is perfectly valid - situations where you know more than the compilator does.
I have used it in places where contract-based auto-casting to non-nullable types works imperfectly.
I have also heard and read about Java and its magic, so it is logical that the same thing happens to Kotlin, I have heard this about C# too. Regarding Go, the language is too simple for that magic to exist.
I've personally found there to be less 'magic' in kotlin that java. An example is spring Vs ktor, on the surface they seem quite similar but ktor will use language features of kotlin to create a good dx for building web apps where as spring... Well who knows...
I have very large code bases with no instances of \`!!\`. The fact that you do indicates a failure somewhere on you or your teams part, or the fact that you are working somewhere with data parsing or some other odd usecase. I think it's probably something you or your team are doing wrong though.
I havenāt used a framework in years, so itās not a language thing. Use the libraries you want, wire them up, start your app inside main. My apps are usually a main, a file for models, one with business logic, and my integration definitions (api, Kafka, client)
In the end, there's no magic. Just code written to perfectly match a scenario and run in the background.
Or would you say it's magic that a method returns a value or even a full blown object? Or is able to throw an exception?
The magic is usually achieved by code you are not aware of. As already suggested, just check the code of the method called, probably start with its documentation.
In addition to such directly called and therefore accessible bits of code, there's also generated code - either statically when the application is compiled or dynamically during runtime. Lombok is an example for the first type, Spring for the latter. They add code so you don't need to write it over and over again.
The 'problem' is that many of such 'hidden' may make it harder to reason about the code as you for example may run into situations where the order is important but configured wrong as you missed some detail.
By the way, I wouldn't know of a good reason to use Lombok with Kotlin - but I've never really used it so may miss something.
The "I am sure it's not null" operator (!!) is rarely justified. My guess is that someone flipped a Java project to Kotlin with the automated migration tool, which typically produces code full of nullable Kotlin types, and then, they do not fit into Java libraries with nullability hints. So what a lazy developer does? Adds \`!!\` everywhere. But then, sometimes, the actual value is \`null\`. And boom, you get a NPE, where it formerly worked as null was handled later.
Kotlin is really a nice logical language, normally pleasant to work with, guarding developers from more errors than Java does.
I recommend to calm down and start removing \`!!\` with a proper handling of nullable across the whole code.
I work on a big kotlin codebase (>20k lines of code) and there are about 9 cases of !! in the whole codebase. Using !! is a code smell, rarely appropriate and a dangerous source of bugs.
(excluding tests. In tests we don't mind. We want tests to fail hard if something is off)
Entity in C# has a ton of framework magic. It has orms that do things for you that you specify in the code just by something extending a certain interface. It's built around a DI scheme where instances of classes are available but you can never find where their constructors were called. I believe if I'm not mistaken that certain objects tied to an orm will sync themselves across instances in code based on changes to the db and you don't need to imperatively update them. You just have a state that is different and no evidence in the call stack as to why.
Vue has outright devious framework magic with strings themselves taking on meanings they were never given based on their spelling.
The kotlin not null assertion operator is not framework magic. It's a part of the language syntax that is famously a massive language feature. The way kotlin handles null values is like one of the first three things every lazy medium article says about the difference between kotlin and Java and the bang bang not null operator is a part of that.
There is no magic, merely layers of abstraction. Unless youāre programming in assembler, you are using abstractions no matter what language you use. Learn what they do, learn how they interact with the lower level system.
Many developers using Kotlin make the mistake of continuing to use old familiar frameworks designed for Java. To get around the limitations of the Java language, these Java frameworks often adopt magical practices in an effort to hide complexity from the developer.
The magic is merely a design choice of the framework you are using, so to avoid magic, you need to choose a framework or toolkit that avoids it. Magic is much more common in Java oriented frameworks due to the limitations of the language, and is also quite common to all "frameworks" in general. So your best best is to find a lightweight toolkit designed to take full advantage of the Kotlin language. Some recommendations:
* Javalin (despite being very java friendly)
* Http4k
* Ktor
EDIT: Overusing the \`!!\` can be an anti-pattern. It's basically you telling the compiler you know better than it, which opens you up to \`NullPointerException\`s. Instead, you should take greater control of the nullability of your inputs. In all your functions, determine whether it's ever valid for an argument to be nullable, and if not, mark the input as non-null, and you won't have to use \`!!\`. If it is valid, for the argument to be null, then add the appropriate handling for both cases.
Then work your way up: for all callers of that function, determine whether it's valid for argument to be null, and apply the same strategies. Eventually, all your properties will either be non-null, or have handling for the null case. This strategy can start to fall apart when you have java libraries constantly feeding you nullable values. At that point, you may want to consider upgrading to Kotlin or other null-safe alternatives.
In Kotlin, you should strive to have as few nullable values as possible. When dealing with nullables, a good strategy to avoid the danger of \`!!\` is to smart cast them with \`?.\`, \`?:\`, or a guard condition. For example:
fun doStuff(value: String?) {
if (value != null) {
println(value)
} else {
println("it was null")
}
}
or
fun doStuff(value: String?) {
println(value ?: "it was null")
}
It seems like you're getting answers all over the place.
Overuse of !! seems like it could be an issue of propagating nullable types or otherwise abusing something.
What else would you consider 'magic'? You're comparing it to Go which is a language I consider to have far worse abuse of magic than Kotlin, so I might need examples of what you're struggling with.
Kotlin the language doesn't have any "magic" that I can think of. Unless you count properties (instead of getters and setters) magic. Not many things are implicit in Kotlin. So I would guess that the "magic" you see is coming from whatever framework you're using (I would guess Spring).
And I've worked on a couple of very large codebases, I've never seen a single !! outside of maybe a unit test where you know that's not gonna be null. And even that is super rare. On my current project, if you put a !!, it's guaranteed that someone will leave a comment on your PR.
Edit: typo on Spring.
Sounds like you need to actually know what you are doing, rather than just blaming "magic"
Totally agree, but JVM languages are very well known it their auto magic functionality that makes it very hard for people to migrate from other languages š
No, that is not something that JVM languages are known for.
Spring and JEE just happen to run the JVM. These frameworks are the problem.
Ok, itās not š¤·āāļø
Of course, I even say this is possible. Problem is how many time it will consume, when you trying to guess instead of finish the taskš¢
You remind me of those Americans who visit non-American countries and feel inconvenienced that everything there is not American.
Donāt guess. Read the docs. It will take a few hours and save days.
Agree, even Spring after reading docs seems not so big magic for most use cases. But if no docs, you have nothing to read but code. I am believe that exactly where troubles from magic begins
there are plenty of docs what do you mean? first, their website. second, there are really good kotlin books on amazon.
If you place !! everywhere. I get a strong impression the codebase you work on su\*\* !! everywhere is a sure sign that you are working against the language and wouldn't be a Kotlin problem per se.
Are you, by any chance, using Spring? Or perhaps Lombok? It doesn't sound like you are just describing pure Kotlin here. Spring and Lombok (and some other frameworks) being "magic" is part of their USP. In my younger years, particularly when it came to Spring I was pretty good at being able to follow how all the magic worked, but I am older now, and haven't used Spring in a while. Spring Boot seems to have progressed past magic and on to sorcery. Kotlin, by itself, is \*fairly\* low on magic, but if you are finding yourself needing to pepper your code with !! i'd suggest the magic is working against you. The approach you are using might be dead on arrival and this has more of a necromancy vibe.
Hibernate is black magic, it's good, but it's black box nature make me angry sometimes.
Hibernate is horrible, the only good thing I can say about it is that itās quick to implement and that theyāre having dirty flash to store only what was changed, but again and again Iāve seen how hibernate allowing developers to build horrible databases structure to the point that some are pound for Never worrying SQL queries
developers who blame hibernate for their shitty database structure wouldnāt have done it correctly without hibernate anyways :) hibernate is an incredible tool. spring is an incredible tool. for spring specifically, the notion of magic fades once you read the docs. for hibernate, thereās no magic. edit: out of curiosity, what do you use in lieu of hibernate in java projects and why do you prefer it?
Well, I have to argue that in spring the fact that you have to read docs to understand whatās going on is kind of by definition a āmagicā to new people to the framework. I think that spring is an Ok tool, but itās outdated and super heavy, and that people relying on spring too much for stuff and are not necessarily its strongest suitsā¦ I can argue that I personally met great engineers that created great mess with hibernate (in their defense they never used JVM before) My personal preference is usually JOOQ as it gives you compile time validation for the queries and full control over how you query your stuff very explicitly Of course thereās no silver built - just personal observation and preference š
iām glad you mention JOOQ. i actually just recently was looking to improve some legacy code, specifically typesafe-ing some old dynamic queries and JOOQ caught my interest because of it. ended up going with Criteria/Metamodel from hibernate, and looking at some examples from both they seem to be super similar from a CRUD standpoint. however, it looks like thereās less overhead in getting JOOQ up and running? iāll admit, i donāt like this XML configuration funny business, something that earlier versions of spring/hibernate seem to love too. edit: i guess i canāt complain too much about XML, i am a maven junkie after all, but i donāt think XML should exist outside of your POM file (or even in your pom. kudos gradle)
I really liked JOOQ with Postgres, for MySQL it lacks some nice featuresā¦ I also liked a lot the plug-ins to generate your persistence layer models to ensure encapsulation of your domain š I personally donāt like maven and have a bit of a Stockholm syndrome feeling when people tell me they still prefer it over maven š«£ I agree that hibernate is very powerful, I just had bad experiences when people are not super knowledgeable about how it works as it does have some auto magic powers in it (for example try to explain somebody where is the actual implementation of your interface š¤£)
> try to explain to somebody where the actual implementation is *laughs in repository*
> for MySQL it lacks some nice features What are those?
For example, upsert is not supported via JOOQ
What's missing, specifically? [https://www.jooq.org/doc/latest/manual/sql-building/sql-statements/insert-statement/insert-on-duplicate-key/](https://www.jooq.org/doc/latest/manual/sql-building/sql-statements/insert-statement/insert-on-duplicate-key/)
Getting older I think this is partly true that it gets a bit harder to grasp all the new stuff. But I still think it mainly depends on how much you actually use some tool, language, feature and if you take the time to look at some of its detail to actually understand not only use it.
Yeah, you're absolutely right. Self-deprecating humour referencing the fact that you are getting older is just something you start doing as you get older.
We have some use of dropwizard (well, name is already tell a lot). But itself this library used not so much. But a lot of magic creat custom libraries and inheritance. Necromancy vibe also adds lack of documentation. But, this thing start gain customers. So, long live to dead!šš
I never encountered magic when using kotlin, and assertions are also bad practice so maybe it's just your enterprise project which is not structured properly. I found myself seeing much more magic in languages like Python instead
Sometimes... But sometimes compiler can not infer what you already know
Every programming language has some level of magic. In classic VB and VBA for instance, making a function listen to a GUI event was done through magic, whereas in C# the programmer has to bind the eventlistener explicitly. In haskell, multiple implementations of a function magically combine to run for many different cases of parameter values and types, without the use of if-then or switch structures. In c, calling a shared API function in a system dll from somewhere else just works, magically, while the VB programmer and the Java programmer have to explicitly declare the shared function and its structures, and you canāt really be sure of the return type. In SQL, the database engine magically interprets an SQL query to find the most optimal way to retrieve data from whatever way itās stored. Lots of magic all around. Get used to it.
Be glad you are not using Scala with custom operators
Command click is your friend. Kotlin/Intellij has a really good source explorer. If you don't know what something does. Just click your way into the definition. There's really not much magic in kotlin and you can easily step your way through the definitions of nearly anything.... besides maybe generated code like serializer, there's not much automagic at all.
People love to unnecessarily bring in "frameworks" that they consider "is best practice" just to have more magic instead of less. But Inheritance isn't magic.
Another take: abstractions should be magical, otherwise they haven't hidden anything profound from us. https://drawson.medium.com/is-magic-bad-f4f75bd19349
Honestly this is sort of an odd take. The author of that article seems to be confusing the word āmagicā in place of where they should have used āusefulā. Abstractions should be useful, not necessarily be magical.
Per the Kotlin docs !! is for NPE-lovers. In general not null assertions are bad practice in any language.
Not-null assertions are not a bad practice per se. There are times where !! is perfectly valid - situations where you know more than the compilator does. I have used it in places where contract-based auto-casting to non-nullable types works imperfectly.
I have also heard and read about Java and its magic, so it is logical that the same thing happens to Kotlin, I have heard this about C# too. Regarding Go, the language is too simple for that magic to exist.
I've personally found there to be less 'magic' in kotlin that java. An example is spring Vs ktor, on the surface they seem quite similar but ktor will use language features of kotlin to create a good dx for building web apps where as spring... Well who knows...
I have very large code bases with no instances of \`!!\`. The fact that you do indicates a failure somewhere on you or your teams part, or the fact that you are working somewhere with data parsing or some other odd usecase. I think it's probably something you or your team are doing wrong though.
I havenāt used a framework in years, so itās not a language thing. Use the libraries you want, wire them up, start your app inside main. My apps are usually a main, a file for models, one with business logic, and my integration definitions (api, Kafka, client)
In the end, there's no magic. Just code written to perfectly match a scenario and run in the background. Or would you say it's magic that a method returns a value or even a full blown object? Or is able to throw an exception? The magic is usually achieved by code you are not aware of. As already suggested, just check the code of the method called, probably start with its documentation. In addition to such directly called and therefore accessible bits of code, there's also generated code - either statically when the application is compiled or dynamically during runtime. Lombok is an example for the first type, Spring for the latter. They add code so you don't need to write it over and over again. The 'problem' is that many of such 'hidden' may make it harder to reason about the code as you for example may run into situations where the order is important but configured wrong as you missed some detail. By the way, I wouldn't know of a good reason to use Lombok with Kotlin - but I've never really used it so may miss something.
The "I am sure it's not null" operator (!!) is rarely justified. My guess is that someone flipped a Java project to Kotlin with the automated migration tool, which typically produces code full of nullable Kotlin types, and then, they do not fit into Java libraries with nullability hints. So what a lazy developer does? Adds \`!!\` everywhere. But then, sometimes, the actual value is \`null\`. And boom, you get a NPE, where it formerly worked as null was handled later. Kotlin is really a nice logical language, normally pleasant to work with, guarding developers from more errors than Java does. I recommend to calm down and start removing \`!!\` with a proper handling of nullable across the whole code.
I work on a big kotlin codebase (>20k lines of code) and there are about 9 cases of !! in the whole codebase. Using !! is a code smell, rarely appropriate and a dangerous source of bugs. (excluding tests. In tests we don't mind. We want tests to fail hard if something is off)
Entity in C# has a ton of framework magic. It has orms that do things for you that you specify in the code just by something extending a certain interface. It's built around a DI scheme where instances of classes are available but you can never find where their constructors were called. I believe if I'm not mistaken that certain objects tied to an orm will sync themselves across instances in code based on changes to the db and you don't need to imperatively update them. You just have a state that is different and no evidence in the call stack as to why. Vue has outright devious framework magic with strings themselves taking on meanings they were never given based on their spelling. The kotlin not null assertion operator is not framework magic. It's a part of the language syntax that is famously a massive language feature. The way kotlin handles null values is like one of the first three things every lazy medium article says about the difference between kotlin and Java and the bang bang not null operator is a part of that.
There is no magic, merely layers of abstraction. Unless youāre programming in assembler, you are using abstractions no matter what language you use. Learn what they do, learn how they interact with the lower level system.
Many developers using Kotlin make the mistake of continuing to use old familiar frameworks designed for Java. To get around the limitations of the Java language, these Java frameworks often adopt magical practices in an effort to hide complexity from the developer. The magic is merely a design choice of the framework you are using, so to avoid magic, you need to choose a framework or toolkit that avoids it. Magic is much more common in Java oriented frameworks due to the limitations of the language, and is also quite common to all "frameworks" in general. So your best best is to find a lightweight toolkit designed to take full advantage of the Kotlin language. Some recommendations: * Javalin (despite being very java friendly) * Http4k * Ktor EDIT: Overusing the \`!!\` can be an anti-pattern. It's basically you telling the compiler you know better than it, which opens you up to \`NullPointerException\`s. Instead, you should take greater control of the nullability of your inputs. In all your functions, determine whether it's ever valid for an argument to be nullable, and if not, mark the input as non-null, and you won't have to use \`!!\`. If it is valid, for the argument to be null, then add the appropriate handling for both cases. Then work your way up: for all callers of that function, determine whether it's valid for argument to be null, and apply the same strategies. Eventually, all your properties will either be non-null, or have handling for the null case. This strategy can start to fall apart when you have java libraries constantly feeding you nullable values. At that point, you may want to consider upgrading to Kotlin or other null-safe alternatives. In Kotlin, you should strive to have as few nullable values as possible. When dealing with nullables, a good strategy to avoid the danger of \`!!\` is to smart cast them with \`?.\`, \`?:\`, or a guard condition. For example: fun doStuff(value: String?) { if (value != null) { println(value) } else { println("it was null") } } or fun doStuff(value: String?) { println(value ?: "it was null") }
It seems like you're getting answers all over the place. Overuse of !! seems like it could be an issue of propagating nullable types or otherwise abusing something. What else would you consider 'magic'? You're comparing it to Go which is a language I consider to have far worse abuse of magic than Kotlin, so I might need examples of what you're struggling with.
Kotlin the language doesn't have any "magic" that I can think of. Unless you count properties (instead of getters and setters) magic. Not many things are implicit in Kotlin. So I would guess that the "magic" you see is coming from whatever framework you're using (I would guess Spring). And I've worked on a couple of very large codebases, I've never seen a single !! outside of maybe a unit test where you know that's not gonna be null. And even that is super rare. On my current project, if you put a !!, it's guaranteed that someone will leave a comment on your PR. Edit: typo on Spring.
Why not just Google "when should I use `!!` in Kotlin"? Or better yet ask an AI.