google / ground-android

Ground mobile data collection app for Android

Home Page:http://groundplatform.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Code health] Rename `on*` functions

scolsen opened this issue · comments

We have some functions throughout the app that are called on...Result... on...Click... and similar. These names are really opaque and do not convey anything about the actual behavior that's happening when the function is called. It'd be better to convey semantics in these names instead of intended/current call site use, e.g. onTakePhoto --> startPhotoCapture, onSignInButtonClick --> attemptUserSignIn etc.

We have some functions throughout the app that are called on...Result... on...Click... and similar. These names are really opaque and do not convey anything about the actual behavior that's happening when the function is called. It'd be better to convey semantics in these names instead of intended/current call site use, e.g. onTakePhoto --> startPhotoCapture, onSignInButtonClick --> attemptUserSignIn etc.

I saw a related ToTT about naming recently, and I partly disagree with the idea that naming handler methods as such is necessarily a bad thing. Like setters and getters, they're such a common pattern that a consistent naming convention can add clarity. For additional clarity, those methods could call "action" methods that actually do things (eg startPhotoCapture()) rather than implementing that logic themselves. Also, on* is such a pervasive naming pattern in Android SDK and related APIs that even if we try to eliminate it from our own classes, we'll still end up having references to onClickListener and the likes in our code. Change my mind! :)

It is a definite tradeoff. The on* style conveys, in the context of the enclosing class, that we basically intend that functionality to be used in a handler. OTOH, it conveys nothing at point of use in e.g. the fragment layout:

class ... {
  // oh cool, this is a handler
  fun onSignInButtonClicked() ...
}

// elsewhere..........

// Huh? What does this do?
onClick = frag.onSignInButtonClicked()

Contrarily, giving more semantic names doesn't convey the handler intention within the enclosing class, but it gives readers in the layout fragment way more context:

class ... {
  // ok this attempts a sign in, where's it used exactly?
  fun attemptSignIn() ...
}

// elsewhere..........

// oh cool, we'll attempt to sign in when this button is pressed
onClick = frag.attemptSignIn()

So I think it depends on what we think is more valuable. I'd also argue that the naming scheme overemphasizes a shared property that isn't important. Knowing that all the various action handlers we have are ui handlers doesn't really benefit us since it's rare that we'd ever modify all of these functions based on this shared characteristic, in spite of this, the naming scheme really puts this shared characteristic front and center.

I think names with terms like button in them are also problematic because it means we'll need a rename if we ever happen to change the control component we bind the behavior to.

Maybe we can get the best of both worlds by adopting a nice suffix instead of a prefix, and by dropping references to buttons etc. What about, e.g. attemptSignInAction, takePhotoAction -- this would convey more meaning at call sites while still making this class of methods nice and control f-able.

As for the android terminology, I think that's necessary and makes sense given android's role as the platform. I think it makes less sense for application logic to mirror this approach. In fact, listeners are another example where using the on... pattern just states the obvious and is redundant most of the time .setOnClickListener(onButtonClick()) v. setOnClickListener(uploadMedia())

Just my 2c, the tott is what inspired this. I'd be happy to drop it if we don't feel strongly, but I did touch the photo fragment recently and felt that it'd have been easier to reason through what was happening if the On.... had more meaningful names. Instead, there were a bunch of onSelectPhoto that then calls onPhoto that in turn calls onBlah so it became quite confusing.

Ok, I'm convinced: As I read your response I realized I was thinking of event handlers as the primary means of documenting the result of a particular UI interaction. However, with both Compose and XML Data Bindings handlers are already described in a discoverable, non-ambiguous way. In that case adding another level of indirection is unnecessary.

The one potential exception I can think of is when an event triggers multiple semi-related actions. In that case we have to option of putting all the effects in the method name (showConfirmationDeleteTheThingAndAddTheOtherThing()), or regressing to the handler method naming style. That said, I assume actions can usually be generalized in a way which doesn't expose all the sub-routines involved, so this edge case may just be a hallucination rather than an actual issue.