Earlier this year, as I approached the end of my degree, I started to prepare for life as a software engineer. I thought it would be easy: just write a CV highlighting all my Java and Android projects and let the Unicorns come knocking. It didn’t quite work like that.
My first interview went terribly. I thought the quality of my code would speak for itself, so I was poorly prepared for theoretical questions. The interviewers probably thought I was a Lego engineer — sticking building blocks together from an instruction book, with no idea how it all really works.
After my rejection, I licked my wounds and changed my approach. First, I went back to basics and re-read all the documentation and literature that had helped me on practical projects. Next, I refactored my old code, increasing its quality and applying all the missing things that I thought I knew as a cocky student.
Finally, I learned how to use frameworks like Butterknife, Retrofit and basic Dagger 2. I also applied to four Java jobs that I suspected I might not get, in order to learn from the recruitment processes and get some feedback. My first experience had taught me a valuable lesson: rejection is an education.
With this newfound knowledge, and a little more humility, I applied for an Android internship with Azimo.
The selection process had 3 steps:
- Remote meeting with the engineering team
- Coding task
- Face-to-face interviews
The coding task was to build a GitHub client application that displays a list of public repositories belonging to a selected user.
I aimed to build an app that was not only functional but also easy to maintain and develop. I implemented MVVM architecture patterns using Android Architecture Components’ ViewModel class. I also used Butterknife to bind views easily, Retrofit to fetch data from GitHub and a basic Dagger 2 to inject a GitHub client. Because the task emphasised a simple UI, I used basic components and icons available in Android Studio with GitHub colours (source code: https://github.com/flowerasny/MobileInternshipTask).
Programming task for mobile internship candidates. Contribute to flowerasny/MobileInternshipTask development by…
Thanks to the combined skills I’d learned since my first rejection, I was invited to a final interview with senior engineers at the Azimo offices in Kraków, Poland. We discussed my app and they gave me constructive feedback about what they liked and what I could have done better or differently. I was delighted to be offered a summer internship, and accepted immediately.
The internship was a baptism of fire. Every day I had to learn new skills, and I was treated as if I were a full-time member of the team rather than an intern. Being thrown in at the deep end was hard to begin with, but I had a lot of support from the team. They were patient, kind and helped me improve my skills to the expected standard.
My first task was to write some unit tests for existing code. If I can offer one tip to aspiring software engineers it is this: learn to write unit tests. I hadn’t written a single line of unit testing code until my internship. I now recognise how important they are to creating production-ready code.
For more on why testing is so important, read this fantastic piece by Mirek Stanek: Automated testing will set your engineering team free.
Automated testing will set your engineering team free
“Automation frees engineers to focus on the things that matter and unleash their creativity”
My second task, along with some bug fixing, was related to deeplink handling. Azimo’s customer service agents send deeplinks via email or chat that will open a specific screen in a customer’s app. With a bit of help from a senior Android developer, I had code in production by the second week of my internship 😎.
After that, I made a few debug features to make life easier for Azimo’s QA and designers:
- Language Switcher Tile — allows QA to quickly change the device language, rather than tapping through a bunch of screens. Open source: https://github.com/AzimoLabs/Language-Switcher-Tile/
- Test card picker — we have a few credit/debit cards that can be used for testing purposes like paying for a fake transaction. Test card picker lets QA choose a test card rather than enter the card details manually
- Popup list — there are more than twenty popups in the Azimo app. Popup list allows a designer to see possible popup layouts and to test them in the app
- Debug logging enabler — a switch that allows us to change HTTP logging level. If you build something that fetches data from the internet, for example, you can see a full body of your request
An android plugin that allows you to easily change your device language. - AzimoLabs/Language-Switcher-Tile
Next came my final and biggest task: to build a customer document uploader. In certain situations, an Azimo customer is legally obliged to confirm their identity with documents such as a passport or bank statement. In the past a customer had to leave the app and contact our support team to do this.
The document uploader was designed to solve this problem by letting users select documents from their device gallery and upload them to the Azimo API. The uploader also had to be compatible with deeplinks, so that customer support could guide a user through every stage of the process.
This task was my first introduction to working with other teams in a software company, including designers, product managers and the translation team (Azimo supports nine languages). It made me feel like a working software engineer, and taught me what to expect from my first job.
The document uploader can be seen below and in the Azimo app 📱:
How the internship changed my approach
To really understand what I’d learned during my three-month internship, I decided to go back and rewrite the app I’d submitted during my application and compare the new version to my original solution. Here are the changes I’d like to point out:
● MVP architecture: Initially I used MVVM but since azimo app uses MVP extensively, I decided to give newly learnt pattern a go and rewritten it to MVP
● Packaging: In my previous app I separated classes like one package for one architecture layer. Working on a consumer app with hundreds of thousands of users taught me that this approach doesn’t scale. In the new version I used a package-per-feature approach and found it a lot more intuitive and readable
● Bases : It’s good to have base classes for Activities and Presenters because you don’t have to deal with the same problems repeatedly, such as Butterknife binding or RxJava unsubscribing
● Dependency Injection: Before my internship I was only able to provide the basic Dagger 2 configuration for retrofit with Gson and OkHttp client. In the new version I built a dependency graph for the whole application using provide methods, fields and constructor injection, but the major change is that I’ve finally seen the real benefits of dependency injection
● RxJava: RxJava is used in most Azimo projects. I’m still new to it, but i managed to implement basic fetching data observable instead of LiveData from Android Architecture Components I used previously
● Testing: as I mentioned before, I didn’t write any unit test before my internship. This time I used Mockito to fully unit test the Presenter layer to show you how it is separated from View layer and Android framework because of the Dependency Injection
There are also a lot of tips that I’ve learned, like using Navigator class to navigate among the screens, RxTransformerManager to easily compose Observable etc. They’re all very useful and make a software engineer’s life easier.
My internship taught me:
- Go back to old work and apply new skills to it. Real products have to be updated all the time, and the process will show you what you’ve learned
- Imagination and creativity are essential to being a successful engineer: good teams expect you to come up with your own solutions to problems rather than waiting to be told what to do
- Good software starts with understanding real user problems. If you can’t get inside your user’s head then you’re not going to write code that makes their life easier
- Open source your work. Even if you’ve made mistakes, it shows employers that you’re willing to share your knowledge with the world and learn from others
- Being a full-time software engineer requires discipline and lifelong learning: practice every day