| title | impact | impactDescription | tags |
|---|---|---|---|
Repository Method Naming Conventions |
HIGH |
Improves code discoverability and reusability |
data, repository, naming, conventions, methods |
Impact: HIGH
Repository methods should follow consistent naming conventions to improve discoverability and promote code reuse across different features.
Method names should be concise and avoid redundancy since the repository class name already indicates the entity type.
// Good - Concise method names
class BookingRepository {
findById(id: string) { ... }
findByUserId(userId: string) { ... }
create(data: BookingCreateInput) { ... }
delete(id: string) { ... }
}
// Bad - Redundant entity name in methods
class BookingRepository {
findBookingById(id: string) { ... }
findBookingByUserId(userId: string) { ... }
createBooking(data: BookingCreateInput) { ... }
deleteBooking(id: string) { ... }
}When a method retrieves additional related entities, make this explicit in the method name using keywords like include, with, or andRelations.
// Good - Clear indication of included relations
class EventTypeRepository {
findById(id: string) {
return prisma.eventType.findUnique({
where: { id },
});
}
findByIdIncludeHosts(id: string) {
return prisma.eventType.findUnique({
where: { id },
include: { hosts: true },
});
}
findByIdIncludeHostsAndSchedule(id: string) {
return prisma.eventType.findUnique({
where: { id },
include: { hosts: true, schedule: true },
});
}
}
// Bad - Unclear what data is included
class EventTypeRepository {
findById(id: string) {
return prisma.eventType.findUnique({
where: { id },
include: { hosts: true, schedule: true },
});
}
findByIdForReporting(id: string) {
return prisma.eventType.findUnique({
where: { id },
include: { hosts: true },
});
}
}Repository methods should be general-purpose and describe what data they return, not how or where it's used. This promotes code reuse across different features.
// Good - Generic, reusable methods
class BookingRepository {
findByUserIdIncludeAttendees(userId: string) {
return prisma.booking.findMany({
where: { userId },
include: { attendees: true },
});
}
findByDateRangeIncludeEventType(startDate: Date, endDate: Date) {
return prisma.booking.findMany({
where: {
startTime: { gte: startDate },
endTime: { lte: endDate },
},
include: { eventType: true },
});
}
}
// Bad - Use-case-specific method names
class BookingRepository {
findBookingsForReporting(userId: string) {
return prisma.booking.findMany({
where: { userId },
include: { attendees: true },
});
}
findBookingsForDashboard(startDate: Date, endDate: Date) {
return prisma.booking.findMany({
where: {
startTime: { gte: startDate },
endTime: { lte: endDate },
},
include: { eventType: true },
});
}
}Repositories should only handle data access. Business logic, validations, and complex transformations belong in the Service layer.
// Good - Repository only handles data access
class BookingRepository {
findByIdIncludeAttendees(id: string) {
return prisma.booking.findUnique({
where: { id },
include: { attendees: true },
});
}
updateStatus(id: string, status: BookingStatus) {
return prisma.booking.update({
where: { id },
data: { status },
});
}
}
class BookingService {
async confirmBooking(bookingId: string) {
const booking = await this.bookingRepository.findByIdIncludeAttendees(bookingId);
if (!booking) {
throw new Error("Booking not found");
}
if (booking.status !== "PENDING") {
throw new Error("Only pending bookings can be confirmed");
}
await this.emailService.sendConfirmationToAttendees(booking.attendees);
return this.bookingRepository.updateStatus(bookingId, "CONFIRMED");
}
}
// Bad - Business logic in repository
class BookingRepository {
async confirmBooking(bookingId: string) {
const booking = await prisma.booking.findUnique({
where: { id: bookingId },
include: { attendees: true },
});
if (!booking) {
throw new Error("Booking not found");
}
if (booking.status !== "PENDING") {
throw new Error("Only pending bookings can be confirmed");
}
await sendEmailToAttendees(booking.attendees);
return prisma.booking.update({
where: { id: bookingId },
data: { status: "CONFIRMED" },
});
}
}- Method names should be concise:
findByIdnotfindBookingById - Use
include/withkeywords when fetching relations:findByIdIncludeHosts - Keep methods generic and reusable:
findByUserIdIncludeAttendeesnotfindBookingsForReporting - No business logic in repositories - that belongs in Services
Reference: Cal.com Engineering Blog