I got a weird error running a workflow in GitHub Actions
Error response from daemon: Head "https://registry-1.docker.io/v2/library/postgres/manifests/16-alpine": unauthorized: incorrect username or password
I googled it, but could not find any relevant web pages. Somehow, retrying after 20 minutes worked. Very Strange.
The other day, Dependabot would not perform actios such as rebasing.
Those kinds of anomalies seem to happen from time to time.
Unfortunately, I left GoF at my parents' house and cannot check it. Instead, I browsed some web pages.
I'm forced to decode Java code and had some doubts on the design pattern. There are so many Repository classes that some of my brain cells were killed instantly.
As a Python programmer, it's kind of rare to encounter this pattern.
The Repository Design Pattern is a software design pattern that acts as an intermediary layer between an application's business logic and data storage.
Its primary purpose is to provide a structured and standardized way to access, manage, and manipulate data while abstracting the underlying details of data storage technologies.
This pattern promotes a clear separation of concerns, making software more maintainable, testable, and adaptable to changes in data sources, without entangling the core application logic with data access intricacies.
In essence, the Repository Design Pattern is a blueprint for organizing and simplifying data access, enhancing the efficiency and flexibility of software systems.
Advantages of Repository Design Pattern
- Centralized Data Access: The pattern centralizes and abstracts adata access logic, allowing the rest of application to interact with data through a consistent interface. This simplifies code maintenance by managing all data-related operations in one place.
- Enhanced Testability: Separating data access logic from the business logic facilitates easier unit testing. With a clear interface for data operations, mocking or substituting the repository makes it simpler to test other parts of the application independently.
It sounds familiar… I feel that Dependency Injection's advantage is the same.
- Improve Code maintenability: The repository design pattern promotes clean code by isolating data access logic. This separation allows developers to make changes or optimize data access without affecting the rest of the application.
- Reusability and Extensibility: By adhering to the repository contract, multiple parts of the application can reuse the same data access methods. It allows for easy addition of new data sources or technologies without having to change the main logic of the application.
Disadvantages of Repository Design Pattern
- Overhead for Simple Applications: Implementing the repository design pattern might introduce unnecessary complexity in smaller or straightforward applications. In such cases, the added layers of abstraction might be more cumbersome than beneficial.
- Learning Curve and Development Time: Adopting the repository design pattern might require additional time for development, as it involves creating interfaces, defining contracts, and implementing concrete repository classes. This learning curve could impact project timelines.
- Potential Abstraction Leaks: In some cases, the repository design pattern might leak underlying implementation details to higher layers, making the abstraction less effective. This can happen if the repository needs to cater to complex queries or operations.
Use Cases for Repository Design Pattern
- Web Applications: Repositories are commonly used in web applications to manage data access to databases. They abstract the interaction with the database and make it easier to switch to a different database system.
- APIs and Services: When building APIs or microservices, the Repository Pattern can help manage data access in a clean and organized way. It enables multiple services to interact with data consistently.
It just makes sense. I now remember all the patterns with Python.
In FastAPI, it is a very common pattern to have intermediate functions whose responsibility is to read data from database.
fastapi/full-stack-fastapi-template
For example, functions to CRUD user records are defined in
crud.py
.
def create_user(*, session: Session, user_create: UserCreate) -> User:
db_obj = User.model_validate(
user_create, update={"hashed_password": get_password_hash(user_create.password)}
)
session.add(db_obj)
session.commit()
session.refresh(db_obj)
return db_obj
def get_user_by_email(*, session: Session, email: str) -> User | None:
statement = select(User).where(User.email == email)
session_user = session.exec(statement).first()
return session_user
Now, the functions are used in creating API endpoints
@router.post(
"/", dependencies=[Depends(get_current_active_superuser)], response_model=UserPublic
)
def create_user(*, session: SessionDep, user_in: UserCreate) -> Any:
"""
Create new user.
"""
user = crud.get_user_by_email(session=session, email=user_in.email)
if user:
raise HTTPException(
status_code=400,
detail="The user with this email already exists in the system.",
)
user = crud.create_user(session=session, user_create=user_in)
if settings.emails_enabled and user_in.email:
email_data = generate_new_account_email(
email_to=user_in.email, username=user_in.email, password=user_in.password
)
send_email(
email_to=user_in.email,
subject=email_data.subject,
html_content=email_data.html_content,
)
return user
By doing this, it's easier to test the API endpoint because we only
need to mock crud.get_user_by_email()
. If we write db logic
in the API endpint, it would be a nightmare to mock.
Also, we can improve portability; now we only need to update the database operations in repositories when migrating to a new database. I don't think it often happens tho.
Puchao 200 Chicken wings 600 Sushi bowl 800 Protein shake 200
Total 1800 kcal
MUST:
TODO: