author photo
Nicholaus Adisetyo Purnomo
November 11, 2020

The Journey of Pegipegi’s iOS App Revamp


After almost 9 months since the release of Pegipegi iOS v2.0.0 to AppStore, I’ve taken a look back at everything iOS team have been through in this project and want to share with you the lessons that I have learned along the way.

Our iOS App on the AppStore has received good feedback from our customers. Currently, by the time this article is written, Pegipegi got the highest rating (rated 4.9/5.0) and the most review count (22K+ reviews) on the AppStore compared to our competitors.


Where It All Started

Since 2015 Pegipegi launched its mobile apps for both Android and iOS Platform, the UI was always kinda the same. Finally, in May 2018, Pegipegi mobile apps started the full revamp project. Not only the UI but also its codebase from scratch. Notes here, I only share the experiences from iOS team whom I love so much because they would go further and beyond my expectation to finish this project and achieve this beautiful result. From the engineering side, there are many enhancements like using new architecture, new design patterns, new pods, new tools, and many more.

Before vs After


Now let’s start. Like I said before, for around 3 years, Pegipegi mobile app UI is like “that”. Yeah, I know it’s crappy and buggy. Also, from the engineering side, it’s tough to maintain this codebase. Believe me, maintaining two languages; Obj-C and Swift 2.3 is not that easy. Also, we still use one storyboard for many screens. Can you imagine? 😨

Now, Pegipegi iOS app is like this 😎. Beautiful, smooth experience 60 fps and now easier to maintain from the engineering side. We use VIPER architecture, full Swift 4.2, reactive programming, implement many design patterns, and many more…


The Journey

Here is the timeline of iOS revamp project. In the beginning, the timeline should be around 3–4 months. It supposed to release before the big holiday, Idul Fitri 2018. However, this project took around 6 months to finally finish; starting from April until September 24, 2018 (the day Pegipegi iOS v2 released). After that, we released two hotfixes after the first release. Let me walk you through what we have done in this iOS revamp.

The Preparation Stage

Around April 2018, Company gave me trust to lead this revamp project and prepared for it because the development stage started in May 2018. When I got the chance to saw the first draft UI revamp, it looked really good. It got me excited, hence made me don’t want to lose from the UI/UX team (I know, quite competitive, right? 😤).

So, I gathered the iOS team and we had a meeting about how we should approach this revamp project. I told them to have clean, beautiful, and great codebase. I explained that we have around 1 month to prepare and research about this. We were so excited! We researched many things about best practices in iOS development; from what is the best Architecture, Swift 4 programming language, Design Patterns, Multiple Build Environment, Networking, Reactive Programming, and more.

In conclusion, we did a full rewrite from scratch; created a new iOS project and repository, created basic components, then implemented everything that we have researched before. Haha, easier said than done. 😶

The Development Stage

After creating a new repository and project, we broke down every feature, page, and logic to list of small tasks, then prioritized the basic component first.

For the starting point, we set up the Multiple Build Environment. This feature can help us differentiate among backend environments. We have four build types; Dev, Pre, ProdQA, and Release. Each build type has its different Bundle Identifier, App Icon, and Backend Endpoints.

After that, we tried to use the new architecture, VIPER (View-Interactor-Presenter-Entity-Router). VIPER is one of the architectures on the iOS development. TL;DR; We love VIPER because of its Separation of Concerns. Later, I will explain more detail about VIPER architecture and why it is the best!

It isn’t an easy task to change our mindset from MVC to VIPER. We learned together about VIPER. Almost every day, we discussed what this function should be written in ViewController, Interactor or Router. It was fun 😆. However, that wasn’t the hardest part. Even after we understood VIPER well enough, it was still hard to implement it on our codebase. Because the way each engineer constructed project files, named the VIPER files, and how to code was different. We realized that we didn’t have a standard.

So, we discussed again what we should do to fix this. We had this question, “How we make our code easy to maintain and yet we can speed up our progress?” Why? Because to create a single VIPER module, we have to create four classes + a storyboard. We researched again until we found that Xcode has something called XCode Templates 😮. We can create a template, and then others can use it. Xcode created file according to the template. So we created our VIPER template. This method makes our productivity improved. Therefore, our code is easy to read and maintain. We only have to click File>New>Choose template>Name our VIPER module and voila! All files are created with the same standard naming convention. Yep, that’s our workflow to create new VIPER module. Simple, huh? 😏. We also agreed to standardize our file naming convention like this “{General Module}{Specific Module}{VIPER Classname}”. Right now, all of our modules use the same naming standard. This standard can also help us debug, because we know what class we should have to search for, even if the other person is not the one that created the module.

Along the way, we found something concerning that will become fat. I mean very fat 😵. We gathered together then tried to resolve the problem. We already used the VIPER and it had a great Separation of Concerns. So.. what’s the problem? The answer is the Interactor class. Interactor is a class containing business logic, or any logic that doesn’t comprise UI interaction. For some modules, this could become a massive class.

What makes the Interactor big? We brainstormed and analyzed it again and… yep, it’s the API and local DB. Shortly after that, we found out that we could separate the code that calls API and retrieve local DB to be another layer. We named it RemoteDataManager for all API-related stuff. For local DB, we created singleton call RealmHelper because we use Realm as local DB. RealmHelper handled all stuff about Realm DB, like create, read, update, and delete Realm data. The reason why we use Realm and not the core data could be a topic for another time (don’t miss it lol). For networking stuff, we use Alamofire + ObjectMapper. Alamofire made the networking easy from calling API to getting an API response. Combination with Alamofire + ObjectMapper is great, parsing API response became very easy.

As we all know, storyboard has a bad stigma. However, we don’t want to move to fully create the UI programmatically because we had deadline that we need to maintain. Remember, it should be finished before the big holiday 😧. We were looking for a solution that can help us make things fast but doesn’t have to invest too much. We found IGListKit from Instagram Engineer. After some researches, we found that this could help us make a reusable cell and better handling diff algorithm to reload collectionView.

We created a cell with params then reused in IGList collectionView. We had the List Adapter that contains what cell class needs to create then IGListKit handles it. The biggest reason why we use it because it has an excellent diff algorithm. IGListKit won’t refresh the whole cells; it only refreshes cells that changes. Moreover, they have a good animation in it 😆. When the other engineers have the same UI on their page, we only need to reuse cell from before. This method improved our speed when creating a View layer faster. We add this layer to ViewController we called Adapter. With this method, we were able to complete our Custom VIPER Architecture 😎 from Adapter-ViewController-Presenter-Interactor-RemoteDataManager and Presenter-Router.

With this Custom VIPER Architecture, we could work in parallel. For example, in one module/screen, Person A could focus on View and its interaction. Person B could focus on business logic like sorting, filter, calculate, and more. Person C could focus on how to call API and parse the response. If there’s any local storage logic, Person D could focus on it. We were happy that we’d done this. I bet our old architecture (MVC) wouldn’t be able to do this collaboration. This new method showed us that we were in the right direction.

We really love our new codebase. In terms of keeping the codebase in a great standard, we kept researching then we found pod called SwiftLint. SwiftLint is a library to enforce us to use the same standard in our code and give warning or error if one of us break our guidelines. For example, using force unwrapping or long naming, also maybe too many parameters in a function. SwiftLint can speed up our code-review process. SwiftLint eliminates basic stuff that we have to review, so that it will let us focus on what matters. Now our code has only one standard, and all engineers use the same guidelines.

The Testing Stage

We also used a library called FLEX. This pod speed up our testing process. Normally, if QA team found bugs, then they asked us to debug and find the root cause and we fixed it. Sometimes bugs were caused from a wrong backend response. We taught our QAs to use FLEX for faster debugging workflow and to read params & response. If QAs found something unusual, they used FLEX to see network log written directly on the devices being used for testing. On this day, they can investigate what causes the bugs; the backend response or the app itself. So, QA team only asks for help if the bugs were caused by from the iOS app itself.

Final Touch

In July 2018, we almost finished our iOS revamp. Normally, we used the dev environment to test our ios app. When we tried to use our production environment, the animations were lagging. This problem happened because we only had smaller data in our dev environment. We didn’t optimize it to handle too much data. We wanted a smooth experience in iOS App. To achieve this, we had to get 60 FPS on most of the screens. We added a new pod to show our FPS on every page and tried to optimize it. Usually, FPS dropped because of large data and too many processes at the start when a page is being loaded (viewDidLoad). We improved our FPS by moving heavy processes such as sorting and filtering to a background thread. This solution helped us achieve a smooth experience (60 FPS) in our app.

Release The Kraken

Finally, we released Pegipegi iOS v2.0 on September 24, 2018. After a lot of hard work and many hours of development and testing, we finally did it! 😂. We also implemented Firebase Performance and Crashlytics to track our performance and crash-free rate. After 3 days of rollout, we achieved a 99.2% crash-free rate. It was a good number for the first release. This result made Pegipegi v2.0 only less 0.7% than Pegipegi v1.x (FYI, even though Pegipegi v1.x was crappy and bad, its crash-free rate was 99.9%).

Honestly, I didn’t expect the result would become this great. I feared that the result would be worse, like around 80% or even below that.

We were thrilled with this result, but we didn’t stop there. From Firebase Performance and Crashlytics, we knew what went wrong. We started with Firebase Crashlytics, and we spent around two days to fix most crashes. Also, Firebase Performance told us that our app_start was bad around 6s, which meant that our users had to wait for 6s on the splash screen to use our iOS app. We were looking for what caused this before we found out that many API calls made during app_start in the main thread. So, we moved all API calls to a background thread.

Other than that, we noticed that most data downloaded (around 98%) were images. In our exploration to resolve this problem, we stumbled upon pod called Kingfisher. Kingfisher is a library to cache images. We also implemented Kingfisher in this hotfix to reduce cost in downloading image data. We fixed this in just one week before we released hotfix 2.0.1 and prayed that everything would be improved.

Back to original greatness

After two days of rollout the second release (v2.0.1), we saw that our crash-free rate improved to 99.5%. Our app_start improved to 2–3s. We noticed that network usage was also improved. The network usage of the image had reduced to 70–75%. What a great success! The pursuit of perfection didn’t stop here. We still wanted to achieve more; to have a crash-free rate as great as Pegipegi v1.x. Hence, we fixed most crashes that user found, and we moved Realm logic to a background thread. After all, we did hotfix again (v2.0.2). It ends up with crash-free rate of 99.9% and app_start around 2–3s. In this v2.0.2, we achieved the same stability as before, and also we had a robust codebase. Yeah!


My Two CentsAlways be realistic

  •   Be realistic about your timeline and your team capabilities. Don’t overdo it.Hours of planning can save you weeks of coding
  •   Plan how you want to code at the start. Don’t just jump straight to write the code.Knowing that there are problems to solve is tough
  •   We always have to ask ourselves. “Is there a better way to do this?” or “Is this the right way?”

Conclusion

In conclusion, I think the iOS team nailed it! 😎. The iOS revamp project was a great success. We wrote our new codebase from scratch, new architecture, new design patterns, use many new modern libraries, and achieve great stability of 99.9% crash-free rate.

I know it was just a start and there are so many things that could improve our codebase. Such as auto deployment using Jenkins and Fastlane, Modularization, etc. We won’t stop here. It’s a good start. Let’s continue to the next journey with this great codebase that we have now. And if you are engineers who want to build it together with us, let us know by applying yourself to Pegipegi’s career page, and we’re waiting for you here at Pegipegi :)

Wrap up

Thanks for reading this long articles. If you found this article helpful, feel free to hold down that clap button 👏. It means a lot to me 😁. And don’t forget to share. Sharing is Caring. Also, let’s be friends on Twitter, Linkedin, Github, and Facebook.

This article is about what I’ve learned from this revamp project. In my next article, I will write more about the detail of implementation for every enhancement. See you on my next article! 👋

Are you passionately seeking new knowledge to tackle big challenge? In Pegipegi, we believe in simplicity, problem solving, continuous learning and mission-driven life. We’re looking for talent who focus on create meaningful impact and never settles to keep learning.

Are you up for the challenge? Join us and let’s #GrowTogether!

discuss-like Suka
icon bagikanBagikan
0 Komentar

Diskusi Populer

Top Member