Componentization Practices in NetEase News iOS Application
The NetEase News iOS team adopted a three‑layer componentization strategy—foundation, common, and business—standardizing code conventions, Git workflow, and CI‑driven reviews, encapsulating third‑party libraries, managing dependencies via injection and mediators, and distributing binary pods, which reduced the main project to a single file while expanding reusable components to over 250, achieving low coupling and high cohesion.
In recent years, componentization has become a hot topic in mobile application development. It is an architectural approach that splits a complex app into small, reusable units called components, improving team collaboration, reducing coupling, and enhancing maintainability.
This article describes how the NetEase News iOS project adopted componentization to optimize its architecture and development process.
Architecture Layers
The overall architecture is divided into three layers from bottom to top: the foundation layer (independent of product), the middle layer (product‑related but business‑agnostic), and the upper layer (specific business logic). The componentization process follows these layers: infrastructure construction, common service handling, and business componentization.
Infrastructure Construction
Team norms were established, covering code conventions, Git workflow, and review mechanisms. Code conventions include naming, formatting, and organization, enforced through iterative reviews. Git standards define commit message style, branch management, and rebase policies, supported by CI scripts. Review mechanisms assign component owners and partners, with CI handling merges.
Base libraries were refactored: third‑party libraries previously introduced via CocoaPods were encapsulated into private Pods, separating core utilities (foundation layer) from generic services (common layer) such as networking, image handling, persistence, and logging.
Common Service Handling
Common services are split into a framework layer (view framework and message framework) and a service layer (login, user, publishing, ads, payment, analytics). The view framework provides base view classes and containers (navigation, tab bar, scroll pages, lists) along with necessary context (e.g., navigationController) to keep business components loosely coupled.
Routing is implemented via a URL‑string hard‑coding scheme wrapped in a dedicated component, supporting both external (URL scheme) and internal routes. A preCondition interface abstracts login checks for pages that require authentication.
Dependency Management
To avoid circular dependencies, three strategies are used: dependency removal (e.g., using notifications), dependency injection (injecting protocol‑based references), and a mediator‑style upper‑component handling. Runtime techniques can also be employed for legacy modules.
Business Componentization
Business components are divided into a presentation layer and a business layer. For example, a comment list component is placed in the comment business module and reused across different pages (comment page, video detail page). The BaseBusiness component houses shared models, protocols, enums, and routing constants, ensuring they do not depend on any specific business.
Core business modules (list, WebView, player) were refactored to standardize their architecture, improving reuse and easing future iterations.
Implementation Tools
A custom Pod configuration file replaces the traditional Podfile, adding metadata such as owner, layer, and binary flag. Example configuration:
"NTESNetworking" => { :path => "./DevelopmentPods/NTESNetworking/NTESNetworking.podspec", :owner => "xf", :level => 2, :binary => true }Code responsibility and Merge Request (MR) standards are enforced via GitLab CI: commit analysis determines affected components, notifies owners, and requires their review before merging.
Dependency rules are checked after each pod install ; violations trigger warnings.
Binary component distribution is handled locally: after Xcode builds, component MD5 hashes are used to cache binaries, and build settings are adjusted to point to these caches. Debugging of binary components is supported via LLDB source‑map commands.
Process and Results
Metrics show a steady decrease in the number of source files in the main project (from thousands to a single main file) and an increase in the number of components (up to 268) as componentization progressed.
Conclusion
The componentization effort emphasized “low coupling, high cohesion” and demonstrated that a tailored, layered approach—rather than a one‑size‑fits‑all decoupling framework—best fits the NetEase News iOS project’s characteristics and team structure.
Sample conditional code illustrating the need for component separation:
if (场景A) { //do something } else if (场景B) { //do something }NetEase Media Technology Team
NetEase Media Technology Team
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.