I think it boils down to where you define the extension functions and how that impacts coupling.
At some level you want to divorce the repository storage of the data from your domain object. Let’s say that the repository changes, and “name” is no longer just “name”, but now “firstName” and “lastName”. The body of your application doesn’t care, or need to know that the repository has changed, as it will still just deal with a name, whatever that is.
So something has to put “firstName” and “lastName” together into a “name”, and it needs to be consistent with how the application has always received it. Is it “Fred Smith”, “Fred, Smith” or “F. Smith”? And who “owns” that logic?
From a coupling perspective, you don’t want the application logic to know anything about the repository or the internal structure of the DTO. On the other hand, you don’t want the repository service layer to know about how the data is going to be used.
Let’s say that you have two different applications that used the “name” field, but in different ways somehow. So the conversion from the two “name” fields into one might be different for each application. Yes, you could argue that recombining them back exactly the way the repository service originally delivered “name” would be transparent to the client applications, but what if the change to the repository was driven by one of those applications needing split data?
That’s usually why you put your adapters in some neutral place, associated with the client application but yet somewhat outside of it.
You could use extension functions to provide the adapter, but you need to make sure that they’re not co-mingled with you application code. Otherwise you’ve just reestablished the coupling between the repository and the application that you where trying to avoid.
Are they though? Aren’t DTO’s supposed to be pure data objects? […] So what about extensions?
I’m not 100% familiar with Kotlin, but I think extension methods in Kotlin are the same as C#, basically syntactic sugar.
So you’d write an extension method like:
<span style="color:#323232;">public static class ObjectExtension
</span><span style="color:#323232;">{
</span><span style="color:#323232;"> public static void DoSomething(this object input) { }
</span><span style="color:#323232;">}
</span>
this being the keyword making it an extension method - and you can call that function on an object by doing object.DoSomething() - Yes. But underneath it’s the same as doing ObjectExtension.DoSomething(object) (A static invocation to your ObjectExtension class and DoSomething method.
So on the surface it looks like you’re injecting a new method into your DTO, and your DTO is not a pure data object anymore, but actually you’re just creating an helper function that’s statically invoked - that looks like you can call it “on the object” but actually you’re not.
As for whether it’s a good / common practice to create mappers like that in Kotlin, I don’t really know. I do it often in C# though.
I was suspecting something like that. I’ll be looking into it a bit more.
I also notice some difference in what’s considered “best practice” between Java and C#, so I’m not sure what’s actually best practice haha. Probably somewhere in the middle, I suppose.
<span style="color:#323232;">
</span><span style="color:#323232;">// Add some logic to detect when we're stuck in a loop
</span><span style="color:#323232;">boards.add(conway.map { true in it }.toList().hashCode())
</span><span style="color:#323232;">
</span><span style="color:#323232;">…
</span><span style="color:#323232;">
</span><span style="color:#323232;"> if (boards.size < 5) {
</span><span style="color:#323232;"> // Stuck in loop, add some randomness
</span><span style="color:#323232;">
</span>
What do you mean with stuck in a loop? Is it where the game reaches a state where its cycling continuously through the same variations repeatedly?
I’m not sure what you mean with “needs a buildscript classpath”. Are you trying to use a dependency in your convention plugin? If so you should add it to build.gradle in the buildSrc directory.
An example of what you are trying to do would help a lot.
Instead of applying it directly to the project, I want to add all this config to a convention plugin and add that to the project. Hoping to reuse the config across many projects.
I threw this together really quick: github.com/foip/jib-convention-test . The crux is adding the jib plugin and the extension to buildSrc/build.gradle.kts. I don’t know if this matches your project setup, so let me know if this does or doesn’t work for you (:
Edit:
To put the answer to the original question in more general terms for anyone who stumbles upon this thread: In this case the jib-gradle-plugin is applied as a plugin in the root build.gradle.kts, but it needs extra runtime dependencies for its extensions. You normally would declare those dependencies like so:
When you want to write a convention plugin to wrap that configuration, basically everything that went inside that buildscript block now goes into buildSrc/build.gradle.kts:
That goes for other dependencies as well, for example if you want to use a library to write a custom task, and then you refactor that task into a plugin inbuildSrc.
It is a very popular library that abstracts away the issue of fetching data from multiple local/remote sources and displaying them, managing in-memory and on-disk caches as well as synchronization issues and authentication (if images are not public). Its popularity stems from both ease of use and being well designed to integrate with the language features (such as coroutines) as well as UI toolkits (such as Jetpack Compose). On KMP projects it could not be used in commonMain due to its being available only for Android. In the future this will likely change, as the talk explains. There are already open source image loading libraries which support multiplatform, such as Kamel but - personally - I found bugs and (forgive me) a little unfriendly maintainers.
The company I work at uses KMP in order to develop web applications and backend services with a shared code base. We use the technology in production and have had great success doing so. In my opinion the biggest benefit apart from Kotlin’s type safety is the ability to write shared data models and validation logic in a single code base shared between our different targets.
I do, to some degree, agree with the point that people tend to refuse adoption of new technologies and can observe this behavior at work as well. However: In my company, those people mostly turned out to be shitty developers anyway, generally unwilling to learn new technologies and tech stacks and without any actual arguments against the migration. They are a minority though and didn’t manage to convince people otherwise.
Well thank you, that was more or less what I wanted to hear. I am a big fan of Kotlin, wouldn’t be here otherwise, and I’m experimenting with KMP (and Compose multiplatform on desktop) in some side projects but never at work: all of my colleagues are quite skeptical, paradoxically the Android guys more than the iOS devs, some were real “haters” and I struggle to understand why, maybe having dealt with the technology when it was at an early stage a couple of years ago and having formed a bias then.
kotlin
Hot
This magazine is from a federated server and may be incomplete. Browse more on the original instance.