A Casual Password Manager App With A Non Casual Styles
Why did I start to write a password manager app while there are tons of apps exist in the market. One of the good parts of being software engineer is you can build your own stuff when you dont trust a technology.
The application has limited functionality for the first version. It simply performs CRUD operations for passwords. Before getting details I want to show some screenshots from app to show you what it looks like.
Let’s take a look under the hood. As you guessed app is written in Flutter and I used bloc state management with freezed because I guess it feels a little bit easier. Also implemented DDD (domain driven design) architecture to make it more complex and i will explain in the following paragraph. Some packages I used in the app:
password_strength_checker: ^1.2.2 # password strength checks
flutter_secure_storage: ^8.0.0 # storing password in a secure way
localstorage: ^4.0.1+4
app_bar_with_search_switch: ^1.5.4
flutter_bloc: ^8.1.3 # state management
dartz: ^0.10.1 # functional programming support
auto_route: ^5.0.1 # simplified routing mechanism
freezed_annotation: ^2.2.0
injectable: ^2.1.1
get_it: ^7.6.0
Domain Driven Design
Domain Layer
In implementing DDD architecture with Flutter, the first step involves creating a robust domain layer that encapsulates the core business logic and entity classes. In this project I’ve implemented an ApplicationModel to streamline the transfer of password data, ensuring a structured and efficient flow. I’ve also created a StorageFailure class, designed specifically for handling errors in a more user-friendly way.
Infrastructure Layer
I typically prefer to develop this layer after the domain layer since it relies on the structures and logic established in the domain layer. This layer primarily focuses on repositories and services. Before beginning the implementation, it’s essential to identify the required functions for the application. Subsequently, I create an abstract class, which serves as a blueprint. Then, I inherit from this abstract class to create a repository class. Additionally, I implemented dependency injection, which I will explain on later in the process.
Presentation Layer
This layer is likely the most familiar, as it is purely Flutter-based. I choose to create this layer before the application layer because it allows us to define and visualize the requirements of our application layer. In this phase, we focus on building the user interface and Flutter widgets.
Application Layer
The Application Layer, also known as the heart of the application, is where all the layers come together, especially when using the bloc package for state management. Here, events triggered in the user interface lead to the execution of predefined functions. As a result, the application goes through state changes, updating the user interface accordingly. I have multiple bloc folders and each of them has its own resposibilities. You can see one of them below.
Also,if you notice that I use the dartz package, which allows Dart to incorporate functional programming concepts. This helps in writing cleaner and more expressive code. Dartz introduces functional types like Either ,Option and Fold contributing to a more organized and maintainable codebase. The use of Either, for instance, promotes better error handling by explicitly representing either a success or a failure, reducing the likelihood of unexpected issues.
Dependency Injection (DI)
Dependency injection is a software design pattern that focuses on providing components, usually classes or services, with their dependencies from external sources rather than creating them internally. This promotes a more flexible and modular code structure, making it easier to manage and maintain.
GetIt is a popular DI library in the Dart and Flutter ecosystem. It serves as a dependency injection container, allowing developers to register and retrieve instances of services throughout their application.
Injectable package is a code generation-based dependency injection library built on top of GetIt for Dart and Flutter applications. Its primary goal is to streamline and simplify the DI process by automating the generation of service registrations, reducing the need for manual configuration.
After some technical knowledge lets take a lot how I used those knowledges in the app. First of all I defined a function which you can see below. A global variable named getIt
is defined as the instance of the GetIt container, serving as a centralized location for managing various dependencies and services throughout the application. The configureDependencies
function initializes the GetIt container using the generated $initGetIt
function, automatically handling the registration of dependencies. Additionally, it is crucial to include a call to the configureDependencies()
function within the main
function before invoking the runApp()
function to ensure the proper initialization of dependencies.
Final Words
We covered all parts of the application. At first, it seemed easy, but as we went through each section, it turned out to be more detailed than expected. I plan to improve the app by adding new features and enhancing the design.
Here is the link to the code repository.
I hope you learned something today, happy coding 👊.