
Corporate Hotel Booking
Construí un motor de reservas de hotel corporativo usando TDD Outside-In
Enunciado
Construí un motor de reservas de hotel corporativo. Este motor tiene que cubrir las necesidades de 3 tipos de actores distintos:
- Hotel Manager: Define todos los tipos de habitaciones de su hotel y la cantidad de cada uno.
- Company Admin: Agrega y elimina empleados, y crea políticas de reserva para su empresa y sus empleados.
- Employee: Reserva una habitación de hotel.
Para lograrlo, el motor tiene que proveer 4 servicios principales que trabajan en estrecha colaboración entre sí.
Los cuatro servicios se describen más abajo. El <?> indica que podés usar el tipo primitivo o el tipo que quieras.
Hotel Service
Lo usa el hotel manager para definir los tipos de habitaciones del hotel y la cantidad de habitaciones de cada tipo. También puede devolver la información de un hotel a partir de su ID.
public class HotelService {
// Collaborators(?)
void addHotel(<?> hotelId, <?> hotelName);
void setRoom(<?> hotelId, <?> number, <?> roomType);
<?> findHotelBy(<?> hotelId);
}Reglas
El método addHotel(...) tiene que tirar una excepción si el ID de hotel ya existe; si no, crea el hotel.
El método setRoom(...) tiene que tirar una excepción si el hotel no existe. Tiene que insertar o actualizar una
habitación según su número.
findHotelBy(<?> hotelId) tiene que devolver toda la información sobre la cantidad de habitaciones del ID indicado.
Company Service
Les permite a los company admins agregar y eliminar empleados.
public class CompanyService {
// Collaborators(?)
void addEmployee(<?> companyId, <?> employeeId);
void deleteEmployee(<?> employeeId);
}Reglas
- No puede haber empleados duplicados.
- Al eliminar un empleado, también hay que eliminar del sistema todas las reservas y políticas asociadas a ese empleado.
Booking Policy Service
Les permite a los company admins crear políticas de reserva para su empresa y sus empleados. Las políticas de reserva determinan si la empresa permite el pedido de reserva de un empleado. Hay dos tipos de política de reserva:
- Company Booking Policy: Indica qué tipos de habitación se pueden reservar. Por ejemplo, una empresa puede permitir solo habitaciones estándar (single/double). O puede permitir habitaciones estándar y junior suite.
- Employee Booking Policy: Indica qué tipos de habitación puede reservar un empleado en particular. Por ejemplo, un empleado puede tener permitido reservar solo habitaciones estándar, mientras que otro puede reservar estándar, junior suite y master suite.
public class BookingPolicyService {
// Collaborators(?)
void setCompanyPolicy(<?> companyId, <?> roomTypes);
void setEmployeePolicy(<?> employeeId, <?> roomTypes);
boolean isBookingAllowed(<?> employeeId, <?> roomType);
}Reglas de negocio
- Las políticas de empleado tienen prioridad sobre las de empresa. Si hay una política para un empleado, se tiene que respetar más allá de lo que diga la política de la empresa (si la hay).
- Si no existe una política de empleado, hay que revisar la política de la empresa.
- Si no existe ni política de empleado ni de empresa, el empleado puede reservar cualquier habitación.
Reglas técnicas
- Los métodos
setCompanyPolicy(...)ysetEmployeePolicy(...)tienen que crear una política nueva o actualizar una existente. No se permiten políticas duplicadas de empresa ni de empleado. - El método
isBookingAllowed(...)tiene que tener en cuenta al empleado y a la empresa para la que trabaja.
Booking Service
Les permite a los empleados reservar habitaciones en hoteles.
public class BookingService {
// Collaborators (?)
Booking book(<?> employeeId, <?> hotelId, <?> roomType, Date checkIn, Date checkOut);
}Reglas
- La reserva tiene que tener un ID único, employeeId, hotelId, roomType, checkIn y checkOut.
- La fecha de check out tiene que ser al menos un día posterior a la de check in.
- Validar que el hotel exista y que ofrezca el tipo de habitación pedido.
- Verificar que la reserva esté permitida según las políticas de reserva definidas, si las hay. Para más detalle, mirá Booking Policy Service.
- La reserva solo se permite si hay al menos una habitación de ese tipo disponible durante todo el período de la reserva.
- Llevar registro de todas las reservas. Por ejemplo, si el hotel tiene 5 habitaciones estándar, no puede haber más de 5 reservas el mismo día.
- Las habitaciones se pueden reservar muchas veces siempre que no haya conflictos de fechas.
- Devolverle al empleado la confirmación de la reserva o, si no, un error (también se pueden usar excepciones).
Pautas de la kata
- Usá TDD Outside-In.
- Arrancá por los tests de aceptación, de a uno.
- Definí tus tests de aceptación como vertical slices chicos, que involucren al menos dos servicios.
- Cuando un test de aceptación compila y falla por los motivos correctos (los servicios no están implementados), empezá a hacer los unit tests de los servicios, de a un método público por vez.
Pautas de diseño
- No se puede cambiar la interfaz pública de los servicios, salvo sus constructores para inyectar colaboradores.
<?>se puede reemplazar por el tipo o primitivo que prefieras.- Los servicios no pueden tener dependencias circulares: si el servicio A usa a B, el servicio B no puede usar a A.
- Los servicios no pueden tener estado.
- Los datos persistentes se guardan en un repositorio (en memoria).
- Armá una buena estructura de paquetes, que respete los distintos usuarios y áreas de la aplicación.
Variantes de la kata
Abajo hay algunas variantes de esta kata que podés mezclar y combinar.
1. Servicios definidos, interfaces sin definir En esta variante tenés que seguir usando los 4 servicios definidos arriba, pero sos totalmente libre de crear los métodos que quieras en cada uno.
2. Diseño inicial sin definir (Avanzado) En esta variante, todos los requisitos de negocio para los 3 tipos de actores se mantienen, pero sos libre de diseñarlo como quieras. No hace falta atarse a los 4 servicios.
3. Políticas de reserva por hotel En los requisitos originales solo se tiene en cuenta el tipo de habitación. En esta variante también se puede indicar qué hoteles permite cada empresa o cada empleado. Por ejemplo, una empresa puede permitir reservas de habitaciones estándar y junior suites en el hotel "1", pero solo habitaciones estándar en el hotel "2". Lo mismo para las políticas de empleado.
4. Política de overbooking Algunos hoteles pueden permitir un porcentaje chico de overbooking. Por ejemplo, 5% o 10%.
5. Límites estrictos entre componentes En esta variante, cada servicio representa la interfaz pública de un componente de negocio. Ningún otro servicio puede acceder a sus internals. Los componentes solo pueden interactuar a través de su interfaz pública. Por ejemplo, el Service A puede hablar con el Service B, pero no con el Repository B.
6. Solo diagrama de secuencia En esta variante no tenés que escribir ningún test ni código. Solo tenés que armar un diagrama de secuencia a nivel código (colaboradores, métodos, parámetros, tipos de retorno, estructuras de datos, etc.) que represente la solución en detalle. El diagrama de secuencia tiene que mostrar la interacción de los 3 actores con los servicios y el funcionamiento interno de cada servicio, incluyendo su colaboración con otros servicios y con sus colaboradores internos.
Soluciones
- Java de Sandro Mancuso