Simple is better. And faster! Boost your productivity now, with Android Development Best Practices: Productivity Guide.
Every programmer is familiar with this XKCD comic. Compiling time often takes us out of ‘the zone’, dragging us into a sea of compulsive Internet and Social Media browsing, or forcing yet another coffee break.
Android Developers may especially suffer from it – as big projects, such as poorly configured Gradle build systems make current screen refreshing an endless task. As a result, our focus disappears and the time to complete a user story increases.
But even with blazing fast rebuild time I noticed programmers working inefficiently by organising using unproductive workflows.
Productivity tips for Android developers
Don’t get me wrong.
I’m not comparing programming to an assembly line. But I can find ways to improve our workflow to get more productive and satisfied by the end of the day.
For instance, let’s imagine John Doe – a junior Android Developer. He needs to apply a few changes to the user onboarding process.
How would his workday look?
- Checkout project
- Gradle sync
- Run application
- Sign in – type full email and long, safe password
- Wait for ‘server response’
- Click next 5 times – we have to edit on the 5th screen from the actual process
- Confirmed, ‘icon is too small!’
- Increase image size in editor
- “I have to uninstall the app, I’m no longer a fresh installed user”
- Sign in again – click to see result
- “Oh snap, now the image is too big”
- Repeat steps over and over – and since the project is building and installing to the device, ‘let’s browse funny cat gifs’
- “It’s already lunch break, and I’ve done nothing!”
Poor Joe, he then has to explain to his manager that nothing is done, and after coming back from work he’s physically exhausted despite no achieved measurable result.
But how can we get better?
Use Preview tab for checking UI
First of all, many developers underestimate the power of Android Studio Preview.
It’s no matter if you use the Design or Text tabs, as Preview Tab is your best friend when working with Android UI.
There’s no need to rebuild and relaunch apps to see if adjusted margins already look up to scratch. Here, you can choose device size, orientation, theme and language from the top menu!
That’s cool for static screens you might say, but what if I rely on data downloaded from API?
Tools prefix
No problem, just get familiar with the tools prefix – a real time saver.
- Want to preview text –
short, multiline, with RTL orientation?
- Just use tools:text=”your test text” within the TextView tag.
- Want to preview how an
image view will look after Glide finishes its job?
- Use tools:src within ImageView and provide a drawable sample test .
- Working with
RecyclerView?
- No problem, you can see use tools:listitem=”@layout/item_friend_row” to check how your rendered RV will look.
- Showing/Hiding content
dynamically?
- Use tools:visibility=”gone|visible|invisible” to preview progress, first-time-user-messages on-screen without the need to launch the app over, and over
Feel free to read this overview for other useful tags making your life easier.
Use unit test for testing pure, android free code
Let’s come back to John. He finished UI adjustments, and now he wants to get data from the API, preprocess it, and display.
He’s back to old his habits: writing the preprocessing method, and testing on the device. After a great many clicks, he noticed a bug – array bounds were insufficient. Let’s use <= instead of < and test again.
Edge cases
But what about edge cases? What if the returned array is empty? What if he has 2 happy paths to check?
Testing it on device/emulators every time is not time-efficient. His preprocessing method has no android dependencies, won’t modify the global state, uses java/kotlin pojos as input and output – i.e. it’s a pure function in the flesh. That’s when jUnit becomes super useful.
Let’s imagine processing meeting details:
data class User(
data class MeetingDetails(
|
And sample functions responsible for preparing data for UI, so we can easily bind for data:
fun processMeetingInfo(attendees: List, currentUser: User, ownerId: Long): MeetingDetails |
Actually, there are two things to achieve. Firstly, if a current user is meeting its owner – you can cancel the meeting. Secondly, we need to find meeting owner name.
Unit testing
Instead of jumping into implementations and continuing testing on a device until it’s done, we can use unit testing to simplify the process. Let’s analyse this sample unit test:
@Test
//evaluation phase
//assertion phase
|
Test phases
Consequently, this test has 3 phases:
- First, we set up the input parameters. Thanks to no dependencies, we don’t have to mock and inject any constructor fields – just prepare inputs for our test.
- The second part is evaluation, whereby we pass our input into the function to receive a result.
- The third part is the assertion phase, where using assert methods, we compare received data with an expected result. Note that in this test, we ignored the owner name, which is fine. Different tests should take care of it, as our goal is to create a battery of small tests, independent of each other, and each testing one single aspect. To validate if the owner name is correct we’d need to create a new test.
Wait a second – what if the owner is not on the list of attendees?
We accidentally discovered an edge case without running the app on the device and can now clarify with the product owner how to respond, a unit test will cover this case!
Certainly, I’m not a TDD advocate, influencing you to cover 80% of the application, services and view models with unit tests. I know it’s hard, time-consuming, and sometimes not worth the effort – but a modern software engineer should use unit tests, and simple android-free classes are perfect candidates to start learning.
Fake it ‘till you make it
What can we do to reduce interruptions and spend more time “in the zone”?
I really like the “Fake it till you make it” phrase, as it also refers to software.
Poor John Doe is working on app onboarding and has to uninstall the app after each use. But can he save more time? Who decides if onboarding should show?
fun shouldShowOnboarding(prefs: SharedPreferences): Boolean{
//return prefs.contains(ONBOARDING_SHOWN) // TODO – just for testing, remove before going to production! return false } |
We can hack into these methods for development purposes.
Temporarily hardcode long tester account credentials
It’s not over – you can temporarily hardcode long tester account credentials into a form, return fake responses from the server, start our activity on app launch with a prefilled necessary input.
That’s one of the reasons lazy folk are often good engineers – if a task requires too much manual work (clicking a phone is obviously manual labour) – automate it or look for shortcuts.
Self-code-review
Remember – if you make similar shortcuts or hacks during development, always mark it with TODO and review carefully before committing it to the source repository. Always make self-code-review ahead of clicking the ‘big red’ push button. It’s also very good practice to request code reviews from your peers. In fact, you can implement it as a healthy habit.
And of course, once you’re satisfied with your result, spend some time testing outside your ‘safe experiment’ environment!
Because you wouldn’t want to deliver an application with isUserPremium = true hardcoded to-store, right?
Quick Summary
Long build time and inefficient workflow certainly make developers busy and exhausted.
Know your tools, test in isolation in the early phase of development and introduce unit testing for android-free code. And finally – don’t forget to test on live data.
Read more articles like this on SofwareHut blog