COMMENTS
COMMENT THE WHY NOT THE WHAT
"foo() looks like this because it turned
out all the other 15 solutions we tried
sucked”
Slide 9
Slide 9 text
COMMENTS
COMMENT MAGIC CONSTANTS
val NUM_THREAD = 8
val MAGIC_CONSTANT = 42
Slide 10
Slide 10 text
COMMENTS
COMMENT MAGIC CONSTANTS
val NUM_THREAD = 8 // My desk legs * 2
val MAGIC_CONSTANT = 42 // The Answer
Slide 11
Slide 11 text
COMMENTS
USE COMMON MARKERS
// TODO “We should [add random task] in the future”
// HACK “This works but is kinda hacky”
// HERE BE DRAGONS
Slide 12
Slide 12 text
COMMENTS
USE YOUR OWN ANNOTATIONS
@TechDebt(jira = "https://biowink.atlassian.net/browse/ATD-28")
class BackupActivity : BaseActivity() {
…
}
/**
* The [TechDebt] annotation can be used…
*/
annotation class TechDebt(val jira: String)
Slide 13
Slide 13 text
COMMENTS
DO NOT COMMENT
▸ Constructors, getters, setters… Seriously!
▸ Bad functions names. Fix them!
▸ Everything that can be inferred from the context and the code.
Slide 14
Slide 14 text
COMMENTS
FROM YOUR HEART TO YOUR CODE
What you actually mean and should write:
“Careful! This routine is not thread-safe!”
What you might write while panicking or thinking you are funny or helpful:
“Sh*t! This thing will blow up the moment
we start using threads! Fingers crossed!”
Slide 15
Slide 15 text
COMMENTS
FROM YOUR HEAD TO YOUR CODE
scrollsSubscription =
calendar
.scrollEvents()
.map { it.scrollState() }
.filter { it == OnScrollListener.SCROLL_STATE_IDLE }
.skip(5)
.subscribe(
{ scrollsCount++ },
{ Timber.e(it, "Scroll events observable died ") }
)
Slide 16
Slide 16 text
COMMENTS
FROM YOUR HEAD TO YOUR CODE
/*
To be able to effectively track scroll events
we start observing every scroll event
we focus on the scroll state
we ignore everything that's not [OnScrollListener.SCROLL_STATE_IDLE]
we skip the first 5 events because Android fires 5 bogus events on screen loading
we increment the counter that we will later use when the user navigates away from the screen. */
scrollsSubscription =
calendar
.scrollEvents()
.map { it.scrollState() }
.filter { it == OnScrollListener.SCROLL_STATE_IDLE }
.skip(5)
.subscribe(
{ scrollsCount++ },
{ Timber.e(it, "Scroll events observable died ") }
)
Slide 17
Slide 17 text
COMMENTS
FROM YOUR HEAD TO YOUR CODE
interface AdsManager {
fun hasPrefetchedAd(placement: Placement): Boolean
}
Slide 18
Slide 18 text
COMMENTS
FROM YOUR HEAD TO YOUR CODE
interface AdsManager {
/**
* This method checks if there is a prefetched ad for the given [placement].
*
* @param placement the placement for which to check if a prefetched ad is
* available
* @return true if a prefetched ad for the given placement is available,
* false otherwise
*/
fun hasPrefetchedAd(placement: Placement): Boolean
}
Slide 19
Slide 19 text
VARIABLES
Slide 20
Slide 20 text
VARIABLES
THEY DON’T DESERVE A NAME
tmp
retval
i, k, j
foo
Slide 21
Slide 21 text
VARIABLES
PACK INFORMATION IN THE NAME
▸Is being temporary the only actual quality of tmp?
▸If retval is a list of employees that we are returning, why
don’t we call it employees?
▸Can those loop indexes improve the general readability
somehow?
Slide 22
Slide 22 text
VARIABLES
LOOP INDEXES
for members[j]
for clubs[i]
for towns[k]
doSomething()
Slide 23
Slide 23 text
VARIABLES
LOOP INDEXES
for members[members_i]
for clubs[clubs_i]
for towns[towns_i]
doSomething()
Slide 24
Slide 24 text
VARIABLES
LOOP INDEXES
for members[i]
for clubs[j]
for towns[k]
doSomething()
BOOLEANS
PACK INFORMATION IN NAMES
val readPassword = true
Slide 38
Slide 38 text
BOOLEANS
PACK INFORMATION IN NAMES
val needsPassword = true
val userIsAuthenticated = true
Slide 39
Slide 39 text
BOOLEANS
PACK INFORMATION IN NAMES
val disableSSL = false //
val useSSL = true // ❤
Slide 40
Slide 40 text
FUNCTIONS
Slide 41
Slide 41 text
FUNCTIONS
PACK INFORMATION IN THE SIGNATURE
fun delay(amount: Int) //
Slide 42
Slide 42 text
FUNCTIONS
PACK INFORMATION IN THE SIGNATURE
fun delay(amount_seconds: Int) //
Slide 43
Slide 43 text
FUNCTIONS
PACK INFORMATION IN THE SIGNATURE
typealias Seconds = Int
fun delay(amount: Seconds) // ❤
Slide 44
Slide 44 text
FUNCTIONS
PACK INFORMATION IN THE SIGNATURE
fun createCache(size: Int) //
Slide 45
Slide 45 text
FUNCTIONS
PACK INFORMATION IN THE SIGNATURE
typealias Megabytes = Int
fun createCache(size: Megabytes) // ❤
Slide 46
Slide 46 text
FUNCTIONS
SIDE NOTES
‣ Aim for small reusable functions
‣ Aim for pure functions
1. Dependencies IN
2. Result OUT
3. No side effects
Slide 47
Slide 47 text
IF THEN WHAT?
THE ORDER
if (length >= 10) {…}
if (10 <= length) {…}
Slide 48
Slide 48 text
IF THEN WHAT?
THE ORDER
‣ Left: the expression being interrogated,
the one more likely to change
‣ Right: the expression being compared
against, the one that stays the same over
time
Slide 49
Slide 49 text
IF THEN WHAT?
THE ORDER
‣ Positive case first
‣ Simpler case first
‣ More interesting case first
‣ The case that returns earlier first
Slide 50
Slide 50 text
IF THEN WHAT?
TERNARY OPERATOR
Given that lines are free
When one single line can be replaced with four lines
of more easy-to-understand code
Then don't be a j*rk!
⚠
Slide 51
Slide 51 text
IF THEN WHAT?
TERNARY OPERATOR
fun isUserOfAge(user: User?) =
user?.age.takeIf { it >= 18 } ?: false
Slide 52
Slide 52 text
IF THEN WHAT?
TERNARY OPERATOR
fun isUserOfAge(user: User?) =
if (user == null) false
else user.age >= 18
Slide 53
Slide 53 text
THE USER PROFILE
REAL WORLD EXAMPLE
Slide 54
Slide 54 text
THE USER PROFILE
USER OBJECT
data class User(
name: String,
lastName: String,
email: String)
Slide 55
Slide 55 text
OBTAINING THE USER PROFILE
fun getUser() : User
THE USER PROFILE
Slide 56
Slide 56 text
fun fetchUser() : User
THE USER PROFILE
OBTAINING THE USER PROFILE
Slide 57
Slide 57 text
fun downloadUser() : User
THE USER PROFILE
OBTAINING THE USER PROFILE
Slide 58
Slide 58 text
fun loadUser() : User
THE USER PROFILE
OBTAINING THE USER PROFILE
Slide 59
Slide 59 text
THE USER PROFILE
OBTAINING THE USER PROFILE
fun loadUser(callback: Callback)
fun loadUser(): Observable
Slide 60
Slide 60 text
THE USER PROFILE
OBTAINING THE USER PROFILE
fun loadUser(): Observable
loadUser()
.subscribeOn(Schedulers.io())
[…]
Slide 61
Slide 61 text
THE USER PROFILE
OBTAINING THE USER PROFILE
fun loadUser(): Single
loadUser()
.subscribeOn(Schedulers.io())
[…]
Slide 62
Slide 62 text
NAMING IS HARD
YES
Slide 63
Slide 63 text
WRAPPING UP
HEALTHY DEV TEAM TIPS
‣ YAGNI and KISS
‣ Keep your codebase small
‣ Create a routine of removing bad code
‣ Keep writing and maintaining your tests
Slide 64
Slide 64 text
WRAPPING UP
FURTHER READINGS
‣ The Art of Readable Code
‣ Working effectively with legacy code
‣ The pragmatic programmer
‣ Mini Habits: Smaller Habits, Bigger Results
Slide 65
Slide 65 text
BE BRAVE
Ivan Morgillo
@hamen
Sebastiano Gottardo
@rotxed