Low-Level Design Driven Development — Android Feature Implementation

Thaw Zin Toe
8 min readJul 6, 2024

--

As an Android developer, approaching feature development with a structured low-level design (LLD) during a sprint is very important for efficient and effective implementation. This blog outlines a methodical approach to

LLD design with Login Flow real world use case

that make good your code’s maintainability and aligns with project architecture standards based on my experience.

First thing first,

What is important when you got a ticket from Project Manager?

When you got a ticket from your PM, you need to clarify with Acceptance Criteria . It’s very important initial step to develop feature in your project.

Next , You need to categorize these steps with Pomodoro Timer flows

  1. Planning and Scope Defining ~ 1 or 2 flows
  2. System Designing ~ 1 flow
  3. Architecture and Integration Planning ~ 1 or 2 flows
  4. Detail components & Code Integration ~ unspecified flows
  5. Unit, Integration and UI Testing with Refactoring ~ unspecified flows
  6. Documentation ~ 1 flow
  7. Create Pull-Request and Learning improvement according to Comments ~ unspecified flows

These steps are important to plan based on your timeline. Above steps are recommended ways or you can call Luxury way to integrate feature for developing Android ticket.

Real-World Implementation for Login Ticket

Here is the example of Jira ticket that you are assigned

Ticket: [LLDA-1] Email and Password Login Implementation
## Acceptance Criteria

User Interface:

The login page must have fields for email and password and should have a
“Login” button to submit the credentials.
"Login" button enables only correct state of email and password input fields.
Informative error messages should be displayed for invalid inputs or authentication
failures.

Input Validation:

• The email address must be validated against a standard email format
(e.g., user@example.com).
• The password field should not accept less than 8 characters.

Authentication Process:

• Correct email and password must successfully log the user in.
• Incorrect email or password should result in an authentication failure
with an appropriate error message displayed.
• Passwords should be stored securely using hashing and salting techniques.
• Session keys alive only on when user login flow.

--- Figma UI Link --

We got the ticket from your PM or team-lead. You need to break it down with above processes.

Planning & Scope Defining

Objectives Clarification → We will separate “UI , Integration and Backend API” objectives for Login Feature implementation.

Scope Definition → Clearly define what the feature will include to avoid scope creep.

System Designing

We have Functional and Non-Functional requirements for this case.

Functional Requirements → These outline what the system should do for functional requirements

User Authentication: Validate email and password against stored credentials. (extra — sharing passkey with Google Password Manager)

Session Management: Initiate a session upon successful login.

Input Validation: Check the format of the email and password (e.g., email should match a regex pattern).

Error Handling: Provide error feedback for incorrect inputs or authentication failures.

Non- Functional Requirements → These specify how the system performs under various conditions:

Security: Securely store passwords using Passkeys.

Performance: Handle high volumes of login requests without performance degradation and reduce loading time.

Scalability: Support scaling in user authentication loads.

Availability: Ensure high availability of the login system and support device rotation with lifecycle aware.

Architecture and Integration Planning

Detailed design to implement specific features:

Login Low-level Design Flow Diagram

I will not go through details about Integration Planning.

This step is just like how to integrate the login system interact with each other and with external systems like APIs or third-party services (sometimes we are using Room Database , Firebase Analytics and some authentication library for Login System).

Detail components & Code Integration

UI Layer

LoginUI: This component is the user-facing part of the application. It includes input fields for the user’s email and password, a submit button for logging in, and possibly links for password recovery or account creation.

The design should focus on user-friendliness, ensuring that the layout is intuitive and accessible.

LoginState: It manages the different states of the login process within the UI. These states could include:

Idle: No current interaction or operation.

Loading: A login attempt is in progress.

Error: An error has occurred, which should be displayed to the user.

Success: The login was successful.

LoginViewModel: This acts as a mediator between the LoginUI and the Domain layer. It handles user inputs, triggers login processes, and manages the LoginState. It reacts to user actions, such as button clicks, by calling appropriate use cases in the Domain layer and updates the UI based on the results from the Domain layer.

Domain Layer

LoginUseCase: This is where the business logic for user authentication is handled. It orchestrates the flow of data between the UI and Data layers. Upon receiving a login request, it validates user input with the UserDataValidator before proceeding.

UserDataValidator: Responsible for validating the user input data. It checks if the provided email and password meet the required criteria for format and complexity before the login process can proceed.

EmailValidator: Utilizes the CoreRegexUnit to check if the email address is in a valid format.

CoreRegexUnit: Provides regex utilities for validating strings, used here specifically for email and password validation.

Data Layer

AuthDataSourceImpl: This component implements the AuthDataSource interface defined in the Domain layer. It connects with backend API services to authenticate the user based on the credentials provided.

AuthService: Communicates with the backend server to authenticate user credentials. It sends user data over secure channels and receives tokens or authentication results, which it passes back to the AuthDataSourceImpl .

SessionStorage: Manages session information post-authentication. If the AuthService confirms user authentication, SessionStorage will store session tokens or user-specific data with encrypted data, which are then used across the app to maintain user sessions.

Interactions Between Layers

From UI to Domain: The LoginViewModel receives user actions and uses them to call the LoginUseCase. Depending on the validation results from UserDataValidator , the LoginUseCase may interact with the Data layer.

From Domain to Data: If the user data passes validation, the LoginUseCase instructs AuthDataSourceImpl to authenticate the user via AuthService. Success or failure results are stored and managed by SessionStorage.

Back to UI: Authentication results (success or failure) are sent back up to the LoginViewModel, which updates the LoginState accordingly. The LoginUI responds to these state changes to display appropriate messages or redirect the user.

Unit, Integration and UI Testing with Refactoring

Unit Testing

UI Layer: Check each part of the user interface separately. Make sure all the visual elements appear correctly and can take user inputs as they should.

Domain Layer: Focus on testing just the business logic by itself. Make sure that the systems that check user information (like email and passwords) work correctly. They should be able to tell right from wrong based on the rules set.

Business Layer should test with unit test carefully for all business logic.

Data Layer: Test the parts where the app talks to the server (APIs) and where it saves session information. This is to make sure that the app handles all data safely and works smoothly.

Integration Testing

UI and Domain Layers: Test how well the user interface and the business logic layers work together. Check if the ViewModel (the part that connects these two layers) sends and receives data correctly and updates the app’s state as needed.

Domain and Data Layers: Make sure that the user inputs are processed correctly through the business logic and that the data reaches the backend systems correctly for authentication. Also, verify that session information is stored safely.

System Testing

End-to-End Tests: Run tests that cover the whole process from start to finish. This means checking what happens from the moment a user starts to log in until they either get into the system or receive an error message. This helps confirm that the entire login process works as it should for the user.

Security Testing

Data Layer Focus: Pay extra attention to testing how securely the app handles user data. Make sure to check for weaknesses that could let hackers steal or alter user data.

Refactoring with Test Driven Development for clean code and code smell in code implementation. Should consider naming conventions.

Documentation

Documentation is important to maintain the application effectively especially for what we are doing and how we did the decision making according to documentation, ensure that any developer can understand and work with the system.

Normally I documented with KDOC (Kotlin Code). For each layer shown in the architecture diagram:

UI Layer:

LoginUI: Document the setup and layout of user interface components including fields and buttons.

LoginState: Describe each possible state of the UI (such as idle, loading, success, error) and the conditions that trigger transitions between states.

LoginViewModel: Outline the role of the ViewModel in managing data flow between the UI and Domain layer, including event handling and state updates.

Domain Layer:

LoginUseCase: Document the sequence of operations initiated during a login attempt, interactions with data sources, and the decision-making process based on validation results.

Validators (UserDataValidator, EmailValidator, CoreRegexUnit): Provide specifics on the validation logic, including the patterns used for email validation and the criteria for accepting or rejecting user inputs.

Data Layer:

AuthDataSourceImpl: Describe how this component communicates with backend services (AuthService) to authenticate users and how it interacts with session storage.

AuthService: Detail the API endpoints used, including parameters, expected responses, and error handling mechanisms.

SessionStorage: Explain how session information is stored securely and retrieved.

Create Pull-Request and Learning improvement according to Comments

Preparing for a Pull Request

Branching: Begin by creating a new branch named feature/login from the main codebase to clearly indicate its purpose.

Committing Changes: Regularly commit your changes with clear messages that explain what you did and why. This helps reviewers understand your modifications.

Creating the Pull Request (PR)

Description: When ready, create a pull request against the main branch. The description should detail the changes, link to any relevant tasks or issues, and include testing steps and UI screenshots.

Responding to Feedback

Code Reviews: Address feedback from the pull request, which might include suggestions for improving code quality or fixing bugs.

Iterative Improvements: Update the pull request with necessary changes based on feedback. Make sure to commit each change separately with a message that explains what you changed and why.

Learning from Comments: Use the feedback as a learning opportunity to improve both the project and your development skills.

Conclusion

Above steps are Recommend way or Luxury way to plan how to implement your code implementation to your project.

It’s important to adapt them to the specific needs of your project and team. Always keep your deadlines and project goals in mind, and remember that

Best practices and recommendations are guidelines to help you maintain quality, they are not rigid rules that must be followed without flexibility

Happy coding, and may your development journey be both successful and enlightening!

--

--

Thaw Zin Toe
Thaw Zin Toe

No responses yet