Out of curiosity, what naming conventions do you u...
# random
p
Out of curiosity, what naming conventions do you use for files containing only a function? Eg. I have a file that is basically a factory function declared as extension function of some domain object:
Copy code
data class MyDomainObject(val message: String)

//some adapter package
data class MyResponse(val localizedMessage: String)

fun MyDomainObject.toMyResponse(locale: Locale) : MyResponse {
    /*    imagine a lot of mapping here, calling other pure functions in the same file     */
    
    return MyResponse(this.message + locale.toString())
}
It’s a complex object, so placing the extension function inside the
MyResponse
file would hinder readability. I couldn’t really find anything regarding that in the kotlin docs. What’s your take on it? I would love to hear different opinions!
s
For a file containing a single function, I often use the function name as the file name. For files with several extension functions, I would name the file after the plural form of the receiver type, e.g.
Strings.kt
for
String
extension functions.
1
r
I sometimes have a package
extensions
and using the extended type name as file name for simple QoL extensions (with not much logic, just shortcuts or little cool wrappings) In your example, I understand what you want to do, but I would still define a proper MyDomainObjectMapper (or something like that) class containing the mapping function, or probably multiple functions. I would then have your extension above the class, calling it’s “entry point”. You could even hide the class as internal/private depending on what you do I don’t really like “floating” extensions with complex behaviors, but maybe that’s from my Java background. I’d rather have a class, maybe even with an interface to eventually make it mockable for testing
a
MyDomainObjectExtension.kt
t
This convention may be unpopular amongst the programming community, yet I thought you might benefit from hearing it. I would name it
MyDomainObject+toMyResponse
. That's what I use all the time for my Android apps/other projects (learned it originally from Udemy):
🤨 8
m
Here are some suggestions on how to organize Kotlin code, in particular for extensions which I think is a well-thought advice. https://arturdryomov.dev/posts/kotlin-code-organization/
t
That seems to be overkill for such a simple topic of naming conventions. Programmers oftentimes love to make their life harder for reasons unbeknownst to me. I would recommend you follow my advice or ade's if you want a safer option. Adding extra layers of abstraction will overcomplicate your codebase.
m
It’s a matter of perspective and context. If you’re running your personal project, cool you can arrange and name files as you like. But if you work in big shared projects, at a big company (my case), you’ll find that conventions are important and many of them can have a rationale behind you may not see at first. You say “follow my convention”, but in all honesty yours looks unintelligible to me while it makes perfect sense to you 😉 It always depends you see, the main point here is just to find a convention that works for you, but most important for your team or collaborators, if it’s an OSS project.
e
the + naming convention is common in Objective-C and Swift extensions, but IMO it does not make sense for Kotlin as it gets compiled totally differently
today i learned 1
r
Here are some suggestions on how to organize Kotlin code, in particular for extensions which I think is a well-thought advice.
https://arturdryomov.dev/posts/kotlin-code-organization/
@Matteo Mirk: IIRC a major downside to placing your extensions in ``src/main/kotlinX/third/party/` is that it will break IntelliJ's Command + Click (Go to Implementation?) for anything under that package and take you to your source set instead.
m
Honestly I don’t know, but in theory it should work since Intellij indexes all the source paths (from build or manual config) so it should be able, but I didn’t try this case. Apart from the separate “src/main/kotlinX” advice, that seems to destabilize many 😁 , I really like the convention of using the original target class package and file name for its extentions.
t
Fair enough, though I'll still be using the '+' naming convention. I actually learned it on a fairly well-known, new, paid Android course. I don't see anything wrong with it. But thanks for your perspectives!
👍 1
p
Sooo first of all: Thank you for all the answers! Super interesting read. Let me go through them, maybe that starts another discussion: @Sam Makes sense, but how do you go about having a single extension function? Like
fun DomainObject.toDto()
? @ribesg I think you already brought up the point yourself and the Java/OO roots can be seen there. Honestly I see that this makes sense but I’d ask why you would not just use a function when that’s all that is necessary. 🙂 That reminded me actually of this article. Great read! @Matteo Mirk overall a great read! That gives me a lot of ideas that I have to think about, not just only about extension functions. Overall I see that I should’ve been more precise. FWIW, here’s my view on it: Our scenario are backend services, DDD and hexagonal oriented, meaning that the code (files,classes,functions) should all be readable without much technical knowledge, which also results in slicing the application in the business contexts. This basically denies the use of something like
Strings.kt
or
Extensions.kt
or an extra
/extensions
package/dir/whatever. Right now we still use nouns as file names, e.g.
MyRepresentationCreator.kt
that actually holds
fun MyRepresentation.Companion.from(someDomainObject)
.
👍 1
a
A bit late to the party but I do have this convention • for builder functions (that are not extentions), I normally go
DomaimObjectBuilders.kt
• for extension functions I used to have files called
DomainObject.ktx.kt
but I grew out of that into
DomainObjectUtils.kt
• If I have many extension functions, I would group them with the DTOs they are trying to interact with, something in the lines of
DomainObjectDTOUtils.kt
🤘 1
e
in the Kotlin codebase, it typically uses
Foos.kt
for extensions on or relating to
Foo
, although sometimes it's
foos.kt
(lowercase) or
FooExtensions.kt
. but commonly extensions are mixed with other declarations in the same file - e.g.
MyDomainObject
,
MyResponse
, and
MyDomainObject.toMyResponse
all in the same file, instead of being split up
p
I like the idea of calling it ...Builders.kt., that could be some kind of convention for the company and doesn't say if it's an extension method or not.
t
Is
MyResponse
used in so many different other classes then? In my projects it's typically not used over many other classes, but can be contained within one class, so then the extension function also lives there, inside that one class, at the very bottom. Then again, those transformations are simple enough. Maybe if there's a lot of "mapping" logic going on, I'd put it in a class called
SomethingSomethingMapper
and probably unit test it if there's enough logic in there. You can still have the extension function in that mapper (and probably unit test through there instead of via the mapper itself). I guess doing "mapping" is more specific than doing "building". Building is just creational, whereas mapping indicates more clearly that there's some translation going on (between boundaries, not language).
p
Okay, here's an example: We have a complex domain object that actually has to be mapped to a complex dto. 'complex dto' in the way of actually mapping from the domain to the adapter, but also having conditions on what strange third party key to use for a given property. It's mapping from the domain object, but the creation of the dto itself is kinda complex. (We are talking about applying for some kind of financing, so lots of data which is thoroughly tested)
t
In that case, I would try to make that concept more explicit and choose for a class rather than an extension function. Maybe the extension function could call that class for improved readability.
p
But why though? 🙂 That would either mean that the class is always instantiated when the function is called or is instantiated in a private val inside the same file as the extension function.
I like the purity of the function. But interesting view!
e
if it is pure and doesn't need to be mocked for testing or anything like that, I would put that as a top-level function into a
MyDomainMappers.kt
or similar file. if it doesn't cleanly belong to either type then at least it should be descriptive. but injecting a class to handle mapping is something that may make sense in some cases
t
Sorry to reply so late 😅 I guess I still cling to OO concepts when I want to express "togetherness of code". My experience with FP is quite limited. So that pure function is probably considered to be more idiomatic kotlin.