More Related Content Similar to Dlaczego DDD skutecznie zapobiega chorobie legacy ? (20) Dlaczego DDD skutecznie zapobiega chorobie legacy ? 1. Dlaczego DDD pomaga
skutecznie zapobiegać
chorobie legacy
Szymon Janikowski
Marcin Markowski
https://github.com/itlibrium
Szymon: @szjanikowski
Marcin: @technites_pl
http://itlibrium.com @itlibriun
40. public class ServiceService {
[…]
public void finish(int serviceId, Collection<Integer> sparePartIds)
throws BusinessException {
Service service = serviceRepository.Get(serviceId);
if (service.getStatus() != ServiceStatus.Scheduled) {
throw new BusinessException("Nieprawidłowy status usługi");
}
List<SparePart> spareParts = new ArrayList<>();
for (int sparePartId : sparePartIds) {
spareParts.add(sparePartRepository.Get(sparePartId));
}
service.setSpareParts(spareParts);
BigDecimal sparePartsCost = BigDecimal.valueOf(0);
for (SparePart sparePart : service.getSpareParts()) {
sparePartsCost = sparePartsCost.add(sparePart.Price);
}
PricingCategory pricingCategory =
service.getClient().getEquipmentModel().getPricingCategory();
BigDecimal labourCost = pricingCategory.getPricePerHour()
.multiply(BigDecimal.valueOf(service.getDuration()));
service.setPrice(pricingCategory.getMinPrice().max(labourCost)
.add(sparePartsCost));
service.setStatus(ServiceStatus.Done);
serviceRepository.Save(service);
}
}
45. JAK TO NIE DA SIĘ
WPROWADZIĆ PŁATNEJ
NAPRAWY PODCZAS
PRZEGLĄDU
GWARANCYJNEGO !!!
46. JAK TO NIE DA SIĘ
WPROWADZIĆ PŁATNEJ
NAPRAWY PODCZAS
PRZEGLĄDU
GWARANCYJNEGO !!!
48. blic void finish(int serviceId, Collection<Integer> sparePartIds) throws BusinessException {
Service service = serviceRepository.Get(serviceId);
if (service.getStatus() != ServiceStatus.Scheduled)
throw new BusinessException("Nieprawidłowy status usługi");
List<SparePart> spareParts = new ArrayList<>();
for (int sparePartId : sparePartIds)
{
spareParts.add(sparePartRepository.Get(sparePartId));
}
service.setSpareParts(spareParts);
BigDecimal price = BigDecimal.ZERO;
if (service.isWarranty())
{
price = BigDecimal.valueOf(0);
}
else
{
EquipmentModel equipmentModel = service.getClient().getEquipmentModel();
PricingCategory pricingCategory = equipmentModel.getPricingCategory();
Contract contract = service.getClient().getContract();
BigDecimal sparePartsCost = BigDecimal.valueOf(0);
for (SparePart sparePart : service.getSpareParts())
{
sparePartsCost = sparePartsCost.add(sparePart.Price);
}
if (contract == null)
{
price = pricingCategory.getMinPrice().max(pricingCategory.getPricePerHour()
.multiply(BigDecimal.valueOf(service.getDuration()))).add(sparePartsCost);
}
else
{
49. blic void finish(int serviceId, Collection<Integer> sparePartIds) throws BusinessException {
Service service = serviceRepository.Get(serviceId);
if (service.getStatus() != ServiceStatus.Scheduled)
throw new BusinessException("Nieprawidłowy status usługi");
List<SparePart> spareParts = new ArrayList<>();
for (int sparePartId : sparePartIds)
{
spareParts.add(sparePartRepository.Get(sparePartId));
}
service.setSpareParts(spareParts);
BigDecimal price = BigDecimal.ZERO;
if (service.isWarranty())
{
price = BigDecimal.valueOf(0);
}
else
{
EquipmentModel equipmentModel = service.getClient().getEquipmentModel();
PricingCategory pricingCategory = equipmentModel.getPricingCategory();
Contract contract = service.getClient().getContract();
BigDecimal sparePartsCost = BigDecimal.valueOf(0);
for (SparePart sparePart : service.getSpareParts())
{
sparePartsCost = sparePartsCost.add(sparePart.Price);
}
if (contract == null)
{
price = pricingCategory.getMinPrice().max(pricingCategory.getPricePerHour()
.multiply(BigDecimal.valueOf(service.getDuration()))).add(sparePartsCost);
}
else
{
101. def "Labour cost calculated correctly"() {
given:
_minPrice = minPrice;
_pricePerHour = pph;
_sparePartsPrices = [ 158 : Money.fromDouble(30),
333 : Money.fromDouble(40)];
_duration = duration;
_usedParts = usedPartsIds;
_actionType = actionType;
when:
serviceIsFinished();
then:
getInterventionPrice() == Money.fromDouble(price);
where:
minPrice | pph | duration | usedPartsIds | actionType || price
200 | 100 | 4 | [] | Review || 400
200 | 100 | 1 | [158, 333] | Repair || 270
200 | 100 | 1 | [] | Review || 200
200 | 100 | 0 | [333] | Repair || 240
300 | 100 | 0 | [] | Review || 300
400 | 0 | 10 | [158] | Repair || 430
}
104. public class FinishInterventionHandler {
[…]
public void finish(FinishInterventionCommand command) throws BusinessException {
Intervention intervention = interventionRepository
.get(command.getInterventionId());
PricePolicy pricePolicy = this.pricePolicyFactory.createFor(intervention);
intervention.finish(command.getServiceActions(), pricePolicy);
interventionRepository.save(intervention);
}
}
DDD v1
106. public class Intervention {
[…]
public void finish(Collection<ServiceAction> serviceActions, PricePolicy pricePolicy)
throws BusinessException {
if (this.serviceActions != null)
throw new BusinessException("Nie można zakończyć interwencji więcej niż raz");
this.serviceActions = new ArrayList<>(serviceActions);
price = this.serviceActions.stream()
.map(pricePolicy::apply)
.reduce(Money.ZERO, Money::sum);
}
}
DDD v1
108. public class PricePolicies {
public static PricePolicy labour(Money pricePerHour, Money minPrice) {
return serviceAction ->
Money.max(
Money.multiply(pricePerHour, serviceAction.getDuration().getHours()),
minPrice);
}
public static PricePolicy sparePartsCost(Map<Integer, Money> sparePartPrices) {
return serviceAction ->
serviceAction.getSparePartIds().stream()
.map(sparePartPrices::get)
.reduce(Money.ZERO, Money::sum);
}
[…]
}
DDD v1
110. public class PricePolicyFactory implements IPricePolicyFactory {
[…]
public PricePolicy createFor(Intervention intervention) {
[…]
return PricePolicies.sum(
PricePolicies.labour(
Money.fromDecimal(pricingCategory.getPricePerHour()),
Money.fromDecimal(pricingCategory.getMinPrice())),
PricePolicies.sparePartsCost(sparePartPrices));
}
}
DDD v1
121. def "Labour cost calculated correctly"() {
given:
_minPrice = minPrice;
_pricePerHour = pph;
_sparePartsPrices = [ 158 : Money.fromDouble(30),
333 : Money.fromDouble(40)];
_duration = duration;
_usedParts = usedPartsIds;
_actionType = actionType;
when:
serviceIsFinished();
then:
getInterventionPrice() == Money.fromDouble(price);
where:
minPrice | pph | duration | usedPartsIds | actionType || price
200 | 100 | 4 | [] | Review || 400
200 | 100 | 1 | [158, 333] | Repair || 270
200 | 100 | 1 | [] | Review || 200
200 | 100 | 0 | [333] | Repair || 240
300 | 100 | 0 | [] | Review || 300
400 | 0 | 10 | [158] | Repair || 430
400 | 0 | 1 | [] | WarrantyReview || 0
200 | 100 | 2 | [158] | WarrantyRepair || 0
}
123. public class PricePolicies {
public static PricePolicy labour(Money pricePerHour, Money minPrice) {
return serviceAction ->
Money.max(
Money.multiply(pricePerHour, serviceAction.getDuration().getHours()),
minPrice);
}
public static PricePolicy sparePartsCost(Map<Integer, Money> sparePartPrices) {
return serviceAction ->
serviceAction.getSparePartIds().stream()
.map(sparePartPrices::get)
.reduce(Money.ZERO, Money::sum);
}
public static PricePolicy free() {
return serviceAction -> Money.ZERO;
}
}
DDD v2
124. public class PricePolicies {
public static PricePolicy labour(Money pricePerHour, Money minPrice) {
return serviceAction ->
Money.max(
Money.multiply(pricePerHour, serviceAction.getDuration().getHours()),
minPrice);
}
public static PricePolicy sparePartsCost(Map<Integer, Money> sparePartPrices) {
return serviceAction ->
serviceAction.getSparePartIds().stream()
.map(sparePartPrices::get)
.reduce(Money.ZERO, Money::sum);
}
public static PricePolicy free() {
return serviceAction -> Money.ZERO;
}
}
JEDNA NOWA
POLITYKA
DDD v2
126. DDD v2
public class PricePolicyFactory implements IPricePolicyFactory {
[…]
public PricePolicy CreateFor(Intervention intervention) {
[…]
return PricePolicies.sum(
PricePolicies.when(
PricePolicyFactory::isRegularAction,
PricePolicies.sum(
PricePolicies.labour(
pricingCategory.getPricePerHour(),
pricingCategory.getMinPrice(),
PricePolicies.sparePartsCost(sparePartPrices))),
PricePolicies.when(
PricePolicyFactory::isWarrantyAction,
PricePolicies.free()));
}
}
127. DDD v2
public class PricePolicyFactory implements IPricePolicyFactory {
[…]
public PricePolicy CreateFor(Intervention intervention) {
[…]
return PricePolicies.sum(
PricePolicies.when(
PricePolicyFactory::isRegularAction,
PricePolicies.sum(
PricePolicies.labour(
pricingCategory.getPricePerHour(),
pricingCategory.getMinPrice(),
PricePolicies.sparePartsCost(sparePartPrices))),
PricePolicies.when(
PricePolicyFactory::isWarrantyAction,
PricePolicies.free()));
}
}
130. • BARDZO SZYBKIE DOSTARCZENIE
• WYKORZYSTANIE ELASTYCZNOŚCI
MODELU
• WZROST ZAUFANIA
136. public class PricePolicies {
public static PricePolicy labour(Money pricePerHour, Money minPrice) {
return serviceAction ->
Money.max(
Money.multiply(pricePerHour, serviceAction.getDuration().getHours()),
minPrice);
}
public static PricePolicy sparePartsCost(Map<Integer, Money> sparePartPrices) {
return serviceAction ->
serviceAction.getSparePartIds().stream()
.map(sparePartPrices::get)
.reduce(Money.ZERO, Money::sum);
}
public static PricePolicy free() {
return fixed(Money.ZERO);
}
public static PricePolicy fixed(BigDecimal value) {
return fixed(Money.fromDecimal(value));
}
public static PricePolicy fixed(Money value) {
return serviceAction -> value;
}
}
DDD v2
137. public class PricePolicies {
public static PricePolicy labour(Money pricePerHour, Money minPrice) {
return serviceAction ->
Money.max(
Money.multiply(pricePerHour, serviceAction.getDuration().getHours()),
minPrice);
}
public static PricePolicy sparePartsCost(Map<Integer, Money> sparePartPrices) {
return serviceAction ->
serviceAction.getSparePartIds().stream()
.map(sparePartPrices::get)
.reduce(Money.ZERO, Money::sum);
}
public static PricePolicy free() {
return fixed(Money.ZERO);
}
public static PricePolicy fixed(BigDecimal value) {
return fixed(Money.fromDecimal(value));
}
public static PricePolicy fixed(Money value) {
return serviceAction -> value;
}
}
POLITYKA
ZMIENIAJĄCA
UMOWĘ?
DDD v2
138. public class PricePolicies {
public static PricePolicy labour(Money pricePerHour, Money minPrice) {
return serviceAction ->
Money.max(
Money.multiply(pricePerHour, serviceAction.getDuration().getHours()),
minPrice);
}
public static PricePolicy sparePartsCost(Map<Integer, Money> sparePartPrices) {
return serviceAction ->
serviceAction.getSparePartIds().stream()
.map(sparePartPrices::get)
.reduce(Money.ZERO, Money::sum);
}
public static PricePolicy free() {
return fixed(Money.ZERO);
}
public static PricePolicy fixed(BigDecimal value) {
return fixed(Money.fromDecimal(value));
}
public static PricePolicy fixed(Money value) {
return serviceAction -> value;
}
}
DDD v2
151. def "Contracts allows certain number of free interventions"() {
given:
_interventionsLimit = i10nsLimit;
_interventionsUsed = i10nsUsedBefore;
_actionType = actionType;
when:
serviceIsFinished();
then:
getInterventionPrice() == Money.fromDouble(total);
getInterventionsLimitUsed() == i10sUsedAfter;
where:
i10nsLimit | i10nsUsedBefore | actionType || total | i10sUsedAfter
2 | 0 | Repair || 0 | 1
2 | 0 | WarrantyReview || 0 | 0
2 | 2 | Repair || 300 | 2
0 | 0 | Repair || 300 | 0
}
152. def "Contracts allows spare parts usage up to a limit"() {
given:
_sparePartsPrices = [ 5 : Money.fromDouble(50),
2 : Money.fromDouble(20)]
_sparePartsLimit = partsLimit
_sparePartsLimitUsed = limitBefore
labourIsFree()
_usedParts = usedParts;
_actionType = actionType;
when:
serviceIsFinished();
then:
getInterventionPrice() == Money.fromDouble(total);
getSparePartsLimitUsed() == Money.fromDouble(limitAfter);
where:
partsLimit | limitBefore | actionType | usedParts || total |limitAfter
100 | 0 | Repair | [5,5] || 0 | 100
100 | 0 | Repair | [5,5,2] || 20 | 100
100 | 20 | Repair | [2] || 0 | 40
100 | 50 | WarrantyRepair| [5] || 0 | 50
0 | 0 | Repair | [5,2] || 70 | 0
}
154. DDD v3
public class Intervention {
[…]
public void Finish(Collection<ServiceAction> serviceActions,
InterventionPricing interventionPricing)
throws BusinessException {
if (this.serviceActions != null)
throw new BusinessException("Nie można zakończyć interwencji więcej niż raz");
this.serviceActions = new ArrayList<>(serviceActions);
price = interventionPricing.getTotalPrice();
}
}
155. DDD v3
public class Intervention {
[…]
public void Finish(Collection<ServiceAction> serviceActions,
InterventionPricing interventionPricing)
throws BusinessException {
if (this.serviceActions != null)
throw new BusinessException("Nie można zakończyć interwencji więcej niż raz");
this.serviceActions = new ArrayList<>(serviceActions);
price = interventionPricing.getTotalPrice();
}
}
ZMIANA PARAMETRU
157. public class PricingService implements IPricingService {
private IPricePolicyFactory pricePolicyFactory;
public PricingService(IPricePolicyFactory pricePolicyFactory) {
this.pricePolicyFactory = pricePolicyFactory;
}
public InterventionPricing GetPricingFor(Intervention intervention,
Collection<ServiceAction> serviceActions,
ContractLimits contractLimits) {
PricePolicy pricePolicy = pricePolicyFactory.CreateFor(intervention);
Money totalPrice = Money.ZERO;
for (ServiceAction serviceAction : serviceActions) {
PricingContext context = new PricingContext(serviceAction, contractLimits);
Pricing pricing = pricePolicy.apply(context);
contractLimits = pricing.getContractLimits();
totalPrice = Money.sum(totalPrice, pricing.getValue());
}
return new InterventionPricing(totalPrice, contractLimits);
}
}
DDD v3
159. public static PricePolicy labour(Money pricePerHour, Money minPrice,
InterventionDuration freeInterventionTimeLimit) {
return context ->
{
FreeInterventionsLimit freeInterventionsLimit =
context.getContractLimits().getFreeInterventionsLimit();
if (freeInterventionsLimit.usedInCurrentIntervention()) {
Money labourOverLimit =
labourOverLimit(context, pricePerHour, freeInterventionTimeLimit);
return new Pricing(context.getContractLimits(), labourOverLimit);
}
if (freeInterventionsLimit.canUse()) {
ContractLimits modifiedContractLimits =
context.getContractLimits().UseFreeIntervention();
Money labourOverLimit =
labourOverLimit(context, pricePerHour, freeInterventionTimeLimit);
return new Pricing(modifiedContractLimits, labourOverLimit);
}
Money labour = labour(context, pricePerHour, minPrice);
return new Pricing(context.getContractLimits(), labour);
};
}
DDD v3
161. public class PricePolicyFactory implements IPricePolicyFactory {
[…]
public PricePolicy CreateFor(Intervention intervention) {
[…]
return PricePolicies.sum(
PricePolicies.when(
PricePolicyFactory::isRegularAction,
PricePolicies.sum(
PricePolicies.labour(
pricingCategory.getPricePerHour(),
pricingCategory.getMinPrice(),
freeInterventionTimeLimit,
PricePolicies.sparePartsCost(sparePartPrices))),
PricePolicies.when(
PricePolicyFactory::isWarrantyAction,
PricePolicies.free()));
}
}
DDD v3
162. public class PricePolicyFactory implements IPricePolicyFactory {
[…]
public PricePolicy CreateFor(Intervention intervention) {
[…]
return PricePolicies.sum(
PricePolicies.when(
PricePolicyFactory::isRegularAction,
PricePolicies.sum(
PricePolicies.labour(
pricingCategory.getPricePerHour(),
pricingCategory.getMinPrice(),
freeInterventionTimeLimit,
PricePolicies.sparePartsCost(sparePartPrices))),
PricePolicies.when(
PricePolicyFactory::isWarrantyAction,
PricePolicies.free()));
}
}
DDD v3
166. public void finish(FinishInterventionCommand command) throws BusinessException {
Intervention intervention = interventionRepository.Get(command.getInterventionId());
IContract contract = contractRepository.GetForClient(intervention.getClientId());
ContractLimits contractLimits = contract.GetContractLimits();
InterventionPricing interventionPricing =
pricingService.GetPricingFor(intervention, command.getServiceActions(),
contractLimits);
intervention.Finish(command.getServiceActions(), interventionPricing);
interventionRepository.Save(intervention);
contract.AddUsage(interventionPricing.getContractLimits());
contractRepository.Save(contract);
}
DDD v3
167. public void finish(FinishInterventionCommand command) throws BusinessException {
Intervention intervention = interventionRepository.Get(command.getInterventionId());
IContract contract = contractRepository.GetForClient(intervention.getClientId());
ContractLimits contractLimits = contract.GetContractLimits();
InterventionPricing interventionPricing =
pricingService.GetPricingFor(intervention, command.getServiceActions(),
contractLimits);
intervention.Finish(command.getServiceActions(), interventionPricing);
interventionRepository.Save(intervention);
contract.AddUsage(interventionPricing.getContractLimits());
contractRepository.Save(contract);
}
DDD v3
2 AGREGATY
W TRANSAKCJI ?
175. IT - PODSUMOWANIE
• SKUPIENIE NA ABSTRAKCJACH
BIZNESOWYCH
• PORZĄDEK I STRUKTURA W KODZIE
• WSPÓLNE CELE Z BIZNESEM
179. Postaci SouthPark - SP-STUDIO.DE
Flooded office:
http://cdn.abclocal.go.com/content/wtvd/images/cms/automation/vod/991300_1280x720.jpg
AIR CONDITIONING PHOTOS:
https://commons.wikimedia.org/wiki/File:Industrial_air_conditioning_unit_(DFdB).JPG#filelinks
https://commons.wikimedia.org/wiki/File:2008-08-23_Durham_Regional_Hospital_air_conditioner.jpg
https://commons.wikimedia.org/wiki/File:2008-07-11_Air_conditioners_at_UNC-CH.jpg
https://commons.wikimedia.org/wiki/File:Centralized_Air_conditioning.jpg
Icons made by:
• http://www.freepik.com
• https://www.flaticon.com/authors/nikita-golubev
• https://www.flaticon.com/authors/smashicons