← Back to list

Road to PDP : Modularization 2.0 Approach

We describe the transformation process we achieved by applying Clean Architecture and modularization principles when redesigning the PDP

Ozan TURCAN in Trendyol Tech · 2025-10-30 11:31 · 154 claps · 9.9 min read paywalled
#modularization #android-cleanarchitecture #android-development #trendyoltech #clean-architecture
Open on Medium ↗
Wiki topics: 📱 · Mobile Development 🏛️ · Architecture

Road to PDP 2.0: Modularization Approach

Introduction

In large-scale mobile applications, complexity can grow at an alarming rate. As feature sets expand, and multiple teams contribute to overlapping domains, codebases can devolve into tangled structures that are difficult to maintain, extend, and test. The Product Detail Page (PDP) within our application is a prime example of this phenomenon. What began as a fairly straightforward screen embedded within the Discovery module gradually evolved into a robust set of functionalities and interdependent features — spanning product details, ratings, questions and answers, and more. Over time, the PDP codebase sprawled across multiple modules, resulting in challenges such as circular dependencies, long build times, and difficulty isolating and testing individual components.

This article chronicles the journey of how our PDP team tackled these issues head-on by adopting a modularization strategy deeply influenced by clean architecture principles. By detailing the steps we took — from the initial formation of a dedicated PDP team to our ongoing efforts to streamline code, reduce dependencies, and ensure scalability — we hope to provide valuable insights for other teams facing similar challenges.

So, grab a cup of coffee, sit back, and join us as we take a deep dive into the evolution of the PDP module and the strategies we employed to navigate the complexities of large-scale mobile development. ☕💻

Before establishing the PDP team, the PDP was a component of the Discovery team. As the size of the PDP screen and other related screens grew, it became necessary to divide the team into two separate entities. This led to the formation of the PDP team, which now manages these screens. 🤝💻📈

Before the PDP Module: A Tale of Two Trendyol Modules

At the time the PDP team emerged, the codebase included two major modules: Trendyol and Trendyol_v2. Over time, old classes from Trendyol_v2 were slowly being refactored and migrated into the main Trendyol module. During this process, significant domains like Product Detail, ReviewRating, and QuestionAndAnswer (Q&A) remained interwoven across these two modules. This cross-pollination of functionalities eventually introduced several obstacles:

  • Circular Dependencies: When multiple modules depend on one another, directly or indirectly, changes in one module can trigger unexpected side effects in another. This bidirectional reliance made maintenance more complex and time-consuming. In line with Uncle Bob’s Clean Architecture principles, dependencies should ideally point inward towards more abstract, stable modules, reducing the risk of ripple effects. However, our interlaced structure violated this principle regularly.
  • Intertwined Project Structure: With domains scattered, our project lacked clear boundaries. This was like having different parts of a puzzle mixed into the wrong boxes. Engineers often struggled to locate relevant classes or isolate logic for testing. Without a clear delineation between domains, making small changes could feel like navigating a maze of dependencies.
  • Long Build Times: Due to the intertwined modules, changing a single line of code in one domain could trigger recompilations in entirely unrelated parts of the codebase. The more the project grew, the slower the build times became. In a fast-moving environment where rapid iteration is key, slow builds impede productivity and frustrate developers.
  • Inconsistent Modifications and Ownership Conflicts: Since multiple teams sometimes touched the same shared classes (e.g., ProductCard, ReviewRatingView, ReviewRatingUseCase, ProductModel), it was easy for one team’s changes to unintentionally break functionality for another team. Without clear ownership or domain boundaries, coordination became an overhead.

The result was a vicious cycle of inefficiency: circular dependencies, tangled structures, long build times, and teams stepping on each other’s toes. The need for a dedicated PDP module and a more principled architecture became undeniable.

After all folder changes we had some problems like below in a short

  • Circler dependencies
  • Intertwined project structure
  • Long Build Times
  • Failure to create a Sample App
  • Different teams were making changes to shared classes who developed by the PDP team

The First Attempt: Introducing the PDP Module

Our initial approach involved creating a dedicated PDP module to host the classes specifically related to the Product Detail Page. This first version was rudimentary. We started by moving new and cleanly separable classes — mostly custom views and UI components — into the PDP module. The hope was that, over time, we could shift all PDP-related logic out of Trendyol and Trendyol_v2, thereby reducing the complexity and confusion caused by the pre-existing scattered structure.

However, since some classes were still tightly coupled to the Discovery logic and other domains, the PDP module initially resembled more of a half-measure. While we managed to relocate certain classes, the underlying dependency chains remained intact. This was a “band-aid” solution: it alleviated some pain but didn’t fundamentally solve the modularization challenges or significantly reduce the “graph height” of dependencies.

PDP 1.0: A Systematic Analysis of Dependencies

  • Realizing the limitations of our initial approach, we embarked on a more thorough analysis in late 2021. The goal was straightforward: map out all the dependencies between the PDP module and other parts of the codebase. By March 2022, we had a detailed Excel document itemizing each UI and domain layer dependency.
  • Armed with this new dependency map, we approached the problem methodically. Tasks were created and prioritized to methodically transfer classes and logic out of their scattered locations and into the PDP module. By focusing on one domain at a time — Product Detail, ReviewRating, Q&A — we gradually managed to consolidate related code under the PDP umbrella. This brought about some immediate benefits:
  • Improved Ownership: The PDP team gained clearer control over its domain, reducing accidental modifications by external teams.
  • Slightly Reduced Complexity: By centralizing PDP-related classes, we made it easier for developers to navigate and understand the code responsible for product details.

However, we quickly realized this approach, while incrementally beneficial, wouldn’t fully cure the deeper architectural issues. We had moved some pieces around but still hadn’t addressed why the dependencies were tangled in the first place.

dependency analysis

dependency analysis

From Preliminary Fixes to a More Holistic Approach At this juncture, we recognized that the root cause of many issues lay in how domains and their dependencies were structured. Simply gathering PDP classes together wasn’t enough — we needed a new architectural approach that embraced modularization thoroughly.

We decided to create a Sample App dedicated to the PDP. This Sample App would serve as a contained environment to focus solely on PDP screens, enabling faster feedback loops and build times. Yet, the mere creation of a Sample App didn’t solve all dependency problems. It highlighted them instead, showing us where modules had become too entangled to operate independently. It was time to go further.

PDP 2.0: The API-IMPL Split and Clean Architecture Inspiration

The next stage of the refactoring aimed to fully embrace the principles of Clean Architecture and modularization. We drafted an RFC (Request for Comments) to propose splitting each domain into three distinct types of modules:

  1. API Module: The API module would contain only the public interfaces, abstract classes, and data models needed to interact with that domain’s logic. Think of it as a contract that other modules can depend on. Critically, the API module would avoid Android framework dependencies, focusing purely on plain Kotlin/Java constructs. This ensured stable, inward-facing abstractions that other modules could rely on.
  2. IMPL (Implementation) Module: The IMPL module housed the actual implementations of the logic defined in the API. By separating the interface from the implementation, we prevented other modules from depending on concrete classes. This also improved testability — IMPL modules could be swapped out during testing, and changes to IMPL wouldn’t affect upstream modules that only rely on the API contracts.
  3. ViewComponent Module: This module emerged as a key innovation. Instead of allowing view-related code (e.g., Fragments, Dialogs, Custom Views) to creep into the API or IMPL modules, we segregated them into a dedicated ViewComponent module. This module would handle UI elements and Android-specific dependencies, ensuring that the API and IMPL modules remained free of platform dependencies.

By establishing these three layers, we essentially built a firewall around the core business logic. The UI could evolve, frameworks could change, and we could integrate new libraries without forcing a ripple effect through all layers. This approach resonates strongly with Uncle Bob’s Clean Architecture principles, where the outer layers adapt to changes while the inner layers remain stable and unaffected.

RFC Approval and Parallel Refactors: Coroutines, Hilt, and ViewBinding With the RFC approved, we embarked on a massive parallel effort. In addition to modularization, we tackled other technical debts:

  • Coroutines Refactor: We standardized coroutine usage throughout the codebase, ensuring consistent dispatchers, error handling, and structured concurrency. This step improved code readability and reduced runtime issues.
  • Hilt Dependency Injection Migrations: We integrated Hilt, a dependency injection framework, to simplify object creation and lifecycle management. Hilt reduced boilerplate and further decoupled modules, making it easier to swap out implementations during testing or feature development.
  • ViewBinding Migrations: By transitioning to ViewBinding for UI elements, we reduced the complexity and fragility of UI code, making screens safer and less error-prone to maintain.

All these refactors ran in parallel, demonstrating that major architectural changes can be combined with other technical improvements when planned carefully.

The Sample App Becomes a Reality Once the new modularization strategy took shape, we revisited the Sample App concept more seriously. We linked the Favorite module to this PDP-focused Sample App, creating a dedicated environment for faster iteration and UI testing. The isolation offered by the Sample App was invaluable. Rather than rebuilding the entire codebase, developers could now run just the PDP and related screens in isolation, cutting down build times and enhancing productivity.

Moreover, by connecting other modules like Favorite to the Sample App, we could simulate realistic user flows — like navigating from a product’s detail page to a list of favorites — without needing the entire production environment. This approach served as a proving ground for our new modular structure, ensuring that the PDP screens operated smoothly and efficiently.

PDP 2.1: Addressing Android Dependencies in API Modules

Although the API-IMPL split solved many issues, we discovered a lingering problem: some API modules still contained Android-related dependencies. This introduced unwanted complexity and risked making the supposedly stable API modules susceptible to platform changes.

To address this, we published a new RFC to enforce stricter rules:

  • No Android Dependencies in API Modules: The API module should remain as clean and portable as possible. This meant relying solely on Kotlin standard library constructs and pure data models, free from platform quirks.
  • ViewComponent and IMPL Modules Handle Views and Platform Code: Any UI logic or Android-specific components moved exclusively into the ViewComponent or IMPL modules. The API became the stable core, while ViewComponent dealt with all Fragment, Dialog, and custom view code. This not only enforced clean boundaries but also made testing and swapping implementations easier.

By moving platform-related code out of the API, we ensured that fundamental domain logic stood on its own, unencumbered by presentation or infrastructure details. This was modularization at its purest form: stable APIs, flexible implementations, and isolated view components.

Outcomes and Key Achievements After these extensive refactors and reorganizations, our codebase underwent a profound transformation:

  1. Reduced Build Times: Thanks to the Sample App and the separation of concerns, developers could now iterate more rapidly on PDP features. Build times shrank, helping us achieve a smoother and more satisfying development experience.
  2. Fixed Circular Dependencies: By segregating modules into API, IMPL, and ViewComponent modules and strictly following dependency direction rules, we eliminated circular dependencies. Changes in one module no longer caused unpredictable cascades throughout the codebase.
  3. Reduced Graph Length and Complexity: The code now resembled a neatly arranged library rather than a cluttered toolbox. Each module had a clear purpose and limited responsibility, simplifying onboarding for new team members and making maintenance more manageable.
  4. Simplified Implementation and Clearer Boundaries: With explicit module boundaries, teams knew exactly where to find or place functionality. The PDP team could maintain their domain without fear of unintentional interference from other teams.
  5. Facilitated Benchmarks and Performance Tracking: The clean structure allowed us to introduce micro and macro benchmark tests easily. Periodic performance assessments ensured that our refactoring efforts not only cleaned the code but also contributed to a smoother runtime experience.

Conclusion: A Cleaner, More Scalable Architecture Our journey toward PDP Modularization 2.0 was not a quick fix but a measured, phased process. By embracing Clean Architecture principles — such as dependency inversion, separation of concerns, and stable, inward-facing interfaces — we gradually untangled our codebase. The final structure, with each domain split into API, IMPL, and ViewComponent modules, now serves as a blueprint for how we approach other features in the application.

Beyond the code, this journey taught us valuable lessons about team autonomy, responsibility, and communication. We fostered a more productive, collaborative environment by carving out a dedicated PDP team and giving them both the mandate and the architectural tools to manage their domain. Changes became easier to reason about, build times dropped, and productivity soared. In short, modularization paid off.

Key Takeaways:

  • Don’t delay tackling architectural issues; they rarely fix themselves.
  • Aligning with Clean Architecture principles ensures long-term stability and scalability.
  • A dedicated Sample App can accelerate feedback loops and development times.
  • Clearly defined module boundaries reduce complexity and improve team autonomy.
  • Iterative refactoring, accompanied by parallel improvements (like Coroutines and DI migrations), can produce compounding benefits.

While modularization is never truly “finished,” we can confidently say we’re much closer to a desired ideal state. The PDP’s new structure and dedicated team set a promising precedent for future endeavors across the codebase.

To go to the previous article in the series

https://medium.com/trendyol-tech/road-to-pdp-2-0-migration-to-kotlin-coroutines-flow-5b1b4b665b14

Join Us

Do you want to be a part of our growing company? We’re hiring! Check out our open positions from the links below.

**Home — Trendyol Careers**

We believe in the power of an inclusive workplace. Our platform is for everyone, and so is our workplace. Each and…careers.trendyol.com


메타데이터
post_id
81bf54bc13be
slug
road-to-pdp-modularization-2-0-approach-81bf54bc13be
url
https://medium.com/trendyol-tech/road-to-pdp-modularization-2-0-approach-81bf54bc13be
canonical_url
https://medium.com/trendyol-tech/road-to-pdp-modularization-2-0-approach-81bf54bc13be
author_url
https://medium.com/@ozanturcan
status
ok
fetched_at
2026-07-08 07:00:21