Based on the requirements and use cases, identify the main objects of the system and analyze how they interact and relate to each other...
class Customer{
id primary key,
name,
email,
List address, (one user have multiple address like office address and home address)
List
//one user can have multiple accounts like saving and checking
}
class Account{
Fields :-
The Account class should include such as :-
accountId primary key,
accountNumber,
BigDecimal balance,
List
enum account_type, (current account/ saving account)
branch_name,
IFSC_code,
customer_id foreign key reference (customer(id)),
These above fields store the current state of the account;
Behaviour :-
Key methods should include here :-
deposit(BigDecimal amount);
withdraw(BigDecimal amount);
transfer(Account toAccount, BigDecimal amount){
//to ensure atomicity, the transfer method hold a locking mechanism (like ordered on Account IDs) (Pessimistic Locking) to prevent deadlocks and ensure both debit and credit occur as a single atomic unit.
}
These methods modify the account state and ensure that operations respect business rules such as preventing overdrafts,
}
public class BankService {
private Map<Integer, User> users;
private Map<Integer, Account> accounts;
public void performTransfer(int fromAccountId, int toAccountId, BigDecimal amount) {
Account from = accounts.get(fromAccountId);
Account to = accounts.get(toAccountId);
if (from != null && to != null) {
from.transfer(to, amount);
}
}
}
class Transaction{
int transactionId primary key,
enum transactionType, (cash / UPI / netbanking)
double amount,
Date timestamp,
enum status, (SUCCESS / FAILED / PENDING)
string transactionDetails,
int transaction_account_id foreign key reference (account(account_id))
// Transaction records are immutable to ensure data integrity.
}
For each class, define the attributes (data) it will hold and the methods (functions) that operate on the attributes. Ensure they align with the object's responsibilities and adhere to the principle of encapsulation. Write your code in the code editor below.
Explain design tradeoffs you considered. Check and explain whether your design adheres to SOLID principles. Explain how your design can handle changes in scale and whether it would be easy to extend with new functionalities. Identify areas for future improvement...
My design follow
SOLID principles :-
===============
Single Responsiblities - all classes serve single responsiblities no other things are there
Open/Closed - we have added enum for status , accountType & transactionType , where we can add new things, without modifying existing .
Liskov substitution - if you were to subclass Account into SavingAccount, it should be replace the parent without breaking the system.
Interface segregation - We can impliment bankService interface and we can also split into transaction service and accountManagementService.
Design Trade-Off :-
===============
Pessimistic vs Optimistic Locking :- We have choose Ordered Locking (Pessimistic) for the transfer method to ensure strict data consistency , even though it might be slightly slower than optimistic locking under high contention.
Double vs BigDecimal :- We have used Double for balance for simplicity in this excercise, but in real production system, we should use BigDecimal to avoid floating point rounding errors in currency.
Scalability :-
=================
Thread safety :- We have used synchronized methods or AtomicInteger to ensure that if two people withdraw the same amount at the same millisecond, the balance remain accurate.
Database Scaling :- when the number of users grows, we could shard the database based on userId to distribute the load.
Future Improvement :-
=====================
Double to BigDecimal: - I would replace Double with BigDecimal for precison
Strategy Pattern:- In future i would include Strategy design pattern for different intrest calculation logic based on the AccountType.
Audit Logging :- Adding a separate service to track single API call for security audits.
Notification Service :- Integrating a system to send SMS/email alerts after each transaction.
Caching:- Using Redis to store frequently accessed account balance to reduce database load.