Sto refactoring un modulo di insediamenti in una grande applicazione sanitaria. Sto cercando di seguire DDD.
Lascia che ti dia una descrizione breve e semplificata del codice refactored:
- Un paziente ha un appuntamento durante il quale si sottopongono a diverse procedure mediche. Ogni procedura ha il suo prezzo.
- Il paziente può pagare soldi alla clinica (sia per le procedure che per alcuni prodotti medici)
- Quando pagano le procedure, le procedure diventano contabilizzate
- Viene emessa una fattura o una ricevuta
- Alcuni dei soldi che il paziente paga sono assegnati al dottore
I punti sopra riportati definiscono fondamentalmente i processi principali ei processi dei miei refactoring 2-5.
I processi sono più complicati di quanto sembri (carichi di logica di dominio). Per disaccoppiare la logica ho deciso di trattare ogni processo come un piccolo sottosistema. E per ogni sottosistema ho creato un aggregato separato. Consentitemi di presentarlo con qualche pseudo-codice:
// Patient pays for whatever they're charged for
class PatientForPayments : AggregateRoot {
private Payment[] Payments
public Pay(amount){...}
}
// You can use the payment to account procedures in an appointment
class Appointment : AggregateRoot {
private Procedure[] Procedures
public IsFullyAccounted(){...}
public Account(payment){...} // use the payment to account as many procedures as possible with the money paid
}
// An invoice can be issued
class PatientForInvoices : AggregateRoot {
private Invoice[] Invoices
public IssueInvoice(payment, procedures[]){...}
}
// Settle the money with a doctor
class ProcedureForSettlements : AggregateRoot {
private Payment Payment
private Doctor Doctor
private Procedure Procedure
private decimal Value
}
Mi chiedo quale sia il modo migliore per orchestrarlo.
- Alcuni passaggi sono facoltativi: dipendono dall'input dell'utente (ad esempio emettendo una fattura)
- C'è ancora un accoppiamento temporale (ad es. non è possibile emettere una fattura per un pagamento che non esiste ancora)
- Alcune delle operazioni dovrebbero andare insieme (ad esempio quando una procedura viene contabilizzata, dovremmo accontentarci del medico)
Per ora l'ho orchestrato in un servizio di dominio, chiamato direttamente dall'interfaccia utente (codice nascosto in un'app di WinForms legacy). Qualche altro pseudo-codice:
class PatientPaymentDomainService {
public void HandlePayment(bool isInvoiceNeeded, PaymentDto paymentDto){
payment = CreatePayment(paymentDto)
database.Save(payment)
appointment = database.GetAppointment(paymentDto.AppointmentId)
appointment.Account(payment)
database.Save(appointment)
if(isInvoiceNeeded){
patient = database.GetPatient(paymentDto.PatientId)
patient.IssueInvoice(payment)
database.Save(patient)
}
for(procedureDto in paymendDto.ProceduresDtos) {
doctorSettlement = CreateDoctorSettlement(procedureDto, payment)
database.Save(doctorSettlement)
}
}
...
}
Il codice sopra incapsula sicuramente alcune logiche di dominio (il flusso di lavoro), quindi credo che appartenga al livello del dominio e vorrei che not lo collochi ViewModel / CodeBehind.
Mettere tutto in un singolo aggregato non ha molto senso. Probabilmente finirò dove ho iniziato, un enorme groviglio di logica aggrovigliata e accoppiata.
Tuttavia, orchestrarlo con gli eventi e i gestori di domini ha senso.
Che ne pensi? Come lo modellerai?