Neo HarmonyOS App Architecture Explained: A Four-Layer Design for Maintainable ArkTS Clients

[AI Readability Summary] Neo is a four-layer architecture for HarmonyOS applications designed to solve flat client-side development, unclear responsibilities, and change propagation. By separating code into entry, features, domains, and infra, it reduces coupling, creates a more stable evolution path, and lays the groundwork for service orchestration and progressive startup. Keywords: HarmonyOS architecture, ArkTS, domain modeling.

The technical specification snapshot clarifies Neo at a glance

Parameter Information
Project Name Neo
Target Platform HarmonyOS applications
Primary Language ArkTS / ETS
Architecture Pattern Four-layer structured architecture
Core Layers entry, features, domains, infra
Problems It Solves Flat development, cross-layer coupling, shotgun changes
Code Organization Pages, services, infrastructure, module registration
GitHub Stars Not provided in the source article
License CC 4.0 BY-SA (source article license)
Core Dependencies Routing, domain services, infrastructure services, third-party SDKs

Neo replaces uncontrolled client-side sprawl with accessible layering

HarmonyOS client development is not just about building pages. Requirement reviews, third-party SDK fallbacks, testing, automation, and CI/CD all continuously amplify the impact of architecture quality.

When a system lacks clear boundaries, pages, networking, state, and business rules become tightly entangled. Iteration may look fast in the short term, but over time every new requirement consumes more maintenance capacity.

Flat development usually reveals four recurring symptoms

  1. Pages send requests directly, and callbacks update the UI directly.
  2. The code appears object-oriented, but still behaves like a linear procedural flow.
  3. New requirements rely on if-else branches and patch-style extensions.
  4. A small change requires synchronized edits across multiple files.
Page logic + data logic + SDK state + global variables
= a single change triggers a global chain reaction

This formula summarizes the root cause of client-side instability: responsibilities are not constrained, so change cannot be localized.

Neo converges complexity into a four-layer structure that teams can reason about

Neo does not propose heavyweight DDD. Instead, it provides a practical baseline design that small and mid-sized teams can adopt. It has two goals: preserve structural completeness while keeping the learning cost low, and reserve space for module startup ordering and service orchestration.

The four layers each serve a distinct responsibility

┌──────────────────────────────┐
│ entry    App entry and route orchestration │
├──────────────────────────────┤
│ features Page features and interaction handling │
├──────────────────────────────┤
│ domains  Business domains and data orchestration │
├──────────────────────────────┤
│ infra    Infrastructure and third-party capabilities │
└──────────────────────────────┘

The value of these four layers is not layering for its own sake. The real value is that page behavior, business modeling, and foundational capabilities move from implicit coupling to explicit collaboration.

Each layer needs a clearly defined responsibility rather than a verbal agreement

The entry layer handles application entry and adaptation orchestration

The entry layer is the application facade. It manages page entry points, route management, and one-to-many adaptation strategies. It focuses on how the system is entered, not on concrete business computation.

If a project has multi-end differences, entry is also the right adaptation point because it is naturally closer to assembly than implementation.

The features layer handles page interaction only and should not own core business logic

The features layer is responsible for page- and component-level interactions. It can consume data returned by domain services, but it should not directly handle raw state from servers, local storage, or SDKs.

A simple rule of thumb is this: if a capability must continue to exist after the current page is gone, it does not belong in features.

// The feature layer triggers business actions only and does not orchestrate low-level details directly
class ChatPageViewModel {
  constructor(private chatService: ChatService) {}

  async send(text: string) {
    // Call the domain service to send a message
    await this.chatService.sendMessage(text)
    // The page layer only cares about the interaction result and UI refresh
    this.refreshView()
  }

  refreshView() {
    // Refresh the UI
  }
}

This code shows that the page layer drives interaction, but does not own message delivery details or state persistence.

The domains layer owns business rules, data retrieval, and cross-feature services

The domains layer is the core of Neo. It does not require strict use of full DDD terminology, but it does require that the business rules most likely to change be concentrated here.

Take authentication as an example. Login state, authentication flow, and result distribution should stay cohesive inside the same domain, instead of splitting data structures, flow control, and notification mechanisms across multiple layers.

The infra layer should stay stateless and portable

The infra layer includes networking, databases, caches, meeting SDKs, and other foundational capabilities. Its key principle is not genericity, but statelessness.

Statelessness means infra does not actively hold login state or business context. Upper layers pass in the required parameters explicitly. This prevents infrastructure from contaminating the domain layer in reverse.

Layer boundaries can be penetrated, but you must know exactly where it happens

Real-world projects are rarely absolutely pure, so Neo emphasizes boundary penetration rather than dogmatic isolation. The goal is not to eliminate all penetration, but to identify high-risk areas.

The boundary between features and domains determines whether pages can evolve sustainably

Scenarios such as calling, chat, and media playback are often implemented incorrectly inside pages. In reality, these capabilities may continue running after the page is destroyed, so they belong in domains.

Pages can subscribe to state, but they should not own the source of that state. Otherwise, floating windows, background recovery, and multi-entry reuse all become difficult.

The boundary between domains and infra is the most common source of architectural drift

Many projects mistakenly treat business-stateful SDK wrappers as infrastructure. The result is that infra becomes increasingly heavy, hard to replace, hard to test, and highly risky during regression.

// Correct direction: the domain layer passes state in, and infra only executes capabilities
class MeetingSdkGateway {
  joinMeeting(token: string, roomId: string) {
    // Consume only the externally provided state here
    return sdk.join({ token, roomId })
  }
}

class MeetingDomainService {
  constructor(private gateway: MeetingSdkGateway) {}

  async enter(roomId: string, token: string) {
    // The domain layer orchestrates login state and meeting logic
    await this.gateway.joinMeeting(token, roomId)
  }
}

This code demonstrates state lifting: business state belongs to the domain layer, while execution capability belongs to the infrastructure layer.

Neo becomes real only when the codebase structure reflects the architecture

In the source example, pages are placed in the page interaction area, while business, feature, and lazy services belong to the domain layer. NetworkService, DatabaseService, and CacheService are placed in infra.

At the same time, AppModule serves as the unified orchestration entry point and takes responsibility for service registration. This kind of directory structure is not about looking neat. It makes responsibilities visible, reviewable, and enforceable in the repository.

A typical directory split looks like this

entry/src/main/ets/
├── pages/             # Page interactions
├── services/business/ # Core business domains
├── services/feature/  # Feature services
├── services/lazy/     # Non-critical lazy-loaded services
├── services/infra/    # Network/database/cache/SDK
├── modules/           # Module registration and orchestration entry
└── data/              # Cross-layer shared data models

This organization directly supports later mechanisms such as ServiceManager, module registration, and progressive startup.

Neo gives small and mid-sized teams the most important benefit: controlling the radius of change

Neo does not promise to solve every engineering problem at once. What it does solve first are the most common sources of instability: pages swallowing business logic, infrastructure holding state, and blurred responsibility boundaries.

For a client technology stack like HarmonyOS, which is still evolving rapidly, this kind of layering—clear enough without becoming overly complex—is often more practical than heavyweight architecture.

![Neo architecture article image](https://kunyu.csdn.net/1.png?p=56&adId=1071043&adBlockFlag=0&a=1071043&c=0&k=Neo 构建鸿蒙应用【一】:架构困境与四层结构化设计&spm=1001.2101.3001.5000&articleId=160711350&d=1&t=3&u=b2de891d9bd54e57b3d3b0b3620c41e3) AI Visual Insight: This image is an advertisement-style illustration and does not present code, topology, or interaction details useful for architectural analysis, so no technical interpretation is provided.

The FAQ clarifies the architectural intent behind Neo

Q: Is Neo just a direct port of DDD to HarmonyOS?

A: No. Neo borrows from domain modeling, but its goal is to lower the adoption barrier for small and mid-sized teams. It emphasizes responsibility convergence and maintainable layering rather than a full copy of DDD methodology.

Q: Why should the features layer not operate on networking and SDKs directly?

A: Because page lifecycles are short and page reuse is limited. Once a page depends directly on low-level state, the business logic becomes tightly bound to that page, making floating windows, background recovery, and cross-page reuse much harder.

Q: Why must the infra layer stay as stateless as possible?

A: Stateless infrastructure is easier to test, replace, and migrate. It also prevents login state and business context from leaking downward into foundational layers, which reduces coupling and the risk of chain-reaction changes.

Core Summary: This article reconstructs Neo’s four-layer architecture for HarmonyOS applications, focusing on the responsibilities, boundary penetration, and code placement of entry, features, domains, and infra. It helps small and mid-sized teams build a maintainable and scalable client-side engineering structure with low cognitive overhead.