2 Commits

Author SHA1 Message Date
Michał Michaluk
e7240e0c4b code references added 2018-07-14 23:58:04 +02:00
Michał Michaluk
3cd55afa37 domain explanation for demand-forecasting 2018-07-13 23:01:53 +02:00
13 changed files with 178 additions and 5 deletions

View File

@@ -12,7 +12,7 @@ On the other hand scalability or non functional requirements are different for d
To accommodate to those differences, separate architectural patterns are applied:
![Command Query CRUD Responsibility Segregation](command-query-crud.png)
![Command Query CRUD Responsibility Segregation](doc/command-query-crud.png)
**Simple Create Read Update Delete functionality** are exposed with leverage of CRUD framework.
@@ -76,7 +76,7 @@ Examples in code:
Only the most valuable part of that enterprise software is embedded in hexagonal architecture -
complex business processing modeled in form of the Domain Model.
![Domain Model embedded in hexagonal architecture](hexagon.png)
![Domain Model embedded in hexagonal architecture](doc/hexagon.png)
**Application Services** - providing entry point to Domain Model functionality,
Application Services are ports for Primary / Driving Adapters like RESTfull endpoints.
@@ -103,13 +103,13 @@ with **Model Exploration Whirlpool** and build **Ubiquitous Language** with your
Adding infrastructure and technology later is easy thanks to Hexagonal Architecture.
Simply starting from ZERO business knowledge through initial domain and opportunity exploration with **Big Picture Event Storming**:
![Big Picture Event Storming](es-big-picture-original.jpg)
![Big Picture Event Storming](doc/es-big-picture-original.jpg)
after cleaning and trimming initial model to most valuable and needed areas:
![Big Picture Event Storming](es-big-picture-cleaned.jpg)
![Big Picture Event Storming](doc/es-big-picture-cleaned.jpg)
Deep dive in **Demand Forecasting** sub-domain with **Design Level Event Storming**:
![Design Level Event Storming - Demand Forecasting](es-design-demand-forecasting.jpg)
![Design Level Event Storming - Demand Forecasting](doc/es-design-demand-forecasting.jpg)
is excellent canvas to cooperative exploration of:
- impacted and required actors,

View File

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,104 @@
# Demand forecasting
Demand forecasting refers to predicting future the sales of the product.
Demand forecasting, enables organization to take various business decision on operational level, such as:
- production planning,
- purchasing of materials,
- shortage prediction,
- product pricing,
- inventory optimization,
- business risk management.
But to benefit from being demand-driven, demanded values need to be predicted, collected and kept accurate according to dynamic conditions.
There is plenty of demand predicting approaches:
- Qualitative approaches:
- Judgemental (surveys, specialist opinion, consensus methods)
- Experimental (test marketing, customer buying database, customer panels)
- Quantitative:
- Relationship (econometric models, life cycle models, input-output models)
- Time Series (moving averages, exponential smoothing, threshold methods, GARCH, TBATS, adaptive models)
- Scenario Modeling: refining quantitative forecast with specific adjustments reflecting upcoming situation.
## Continuous demand forecasting
Continuous demand forecasting refers to automated,
continuous prediction no high granularity like demand for product-day-location.
Continuous calculation involve predictive modeling,
algorithmic modeling, pattern identification, scenario modeling and simulations
by combining selected predicting approaches depending on demands mathematical properties.
![Continuous demand forecasting](continuous-forecasting.gif)
Review example [**demand forecasting expertise**](demand-forecasting-expertise.R) leveraging FactoryAnalytics and R-language.
Expertise is generating pdf document while fetching and posting data to REST endpoints of **demand-forecasting** bounded context.
Interactions with **demand-forecasting** bounded context can be found in source code:
- External event **demand forecasting expertise** is handled by port
[DemandService.process(Document)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
- External event **forecast recalculated** is handled by port
[DemandService.process(Document)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
- Command **adjust demand** is handled by port
[DemandService.adjust(AdjustDemand)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
- Read model **stock forecast** is calculated on query time by
[StockForecastQuery.get(RefNoId)](../../app-monolith/src/main/java/io/dddbyexamples/factory/stock/forecast/StockForecastQuery.java)
## Framework agreement and calloff orders
Demands information can be collected based on framework agreement and calloff orders.
In case of high volume production of low value consumables or materials,
an framework agreement with customer specifies contracted demand (on annual, quarterly or monthly granularity).
In addition calloff orders contains commitment values in short period of time
with higher granularity like product-day-location or product-week-location.
Call-off orders and be actualized continuous even on daily basis
replacing need for in house continuous demand forecasting.
![Framework agreement and calloff orders](call-of-orders.gif)
Review example **call-of order** document:
![Calloff order](call-of-order.png)
Example document contains demand forecast for two products
- 5 weeks ahead daily demand for first
- 2 weeks ahead daily demand for second
and some weekly demands aggregates.
Interactions with **demand-forecasting** bounded context can be found in source code:
- External event **framework agreement signed** is handled by port
[DemandService.process(Document)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
- External event **call-of order** is handled by port
[DemandService.process(Document)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
- Command **adjust demand** is handled by port
[DemandService.adjust(AdjustDemand)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
- Read model **stock forecast** is calculated on query time by
[StockForecastQuery.get(RefNoId)](../../app-monolith/src/main/java/io/dddbyexamples/factory/stock/forecast/StockForecastQuery.java)
- Domain event **review required**
[ReviewRequired](../../shared-kernel-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/ReviewRequired.java)
can be published via push notification to Logistician, and is stored as read model and exposed by REST endpoint
[RequiredReviewDao.findByRefNoAndDecisionIsNull(String)](../../demand-forecasting-adapters/src/main/java/io/dddbyexamples/factory/demand/forecasting/command/RequiredReviewDao.java)
- Command **apply review decision** is handled by port
[DemandService.review(ApplyReviewDecision)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
## Custom orders
For custom goods ordered in advance, order based demand can replace demand forecasting.
In case of lack of neither continuous demand forecasting nor calloff orders,
customer orders can be treated as product-day-location demand
so any further processing requiring demand information may work normally.
![Custom orders](custom-orders.gif)
Interactions with **demand-forecasting** bounded context can be found in source code:
- External event **demand forecasting expertise** is handled by port
[DemandService.process(Document)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
- External event **order** is handled by port
[DemandService.process(Document)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
## Manual management
Ad-hoc adjustments of demands on top of any existing forecasts.
Note that **adjust demand** can change demand for multiple days atomically.
Interactions with **demand-forecasting** bounded context can be found in source code:
- Command **adjust demand** is handled by port
[DemandService.adjust(AdjustDemand)](../../demand-forecasting-model/src/main/java/io/dddbyexamples/factory/demand/forecasting/DemandService.java)
- Read model **stock forecast** is calculated on query time by
[StockForecastQuery.get(RefNoId)](../../app-monolith/src/main/java/io/dddbyexamples/factory/stock/forecast/StockForecastQuery.java)
## Propagation of demand
![Propagation of demand](demand-propagation.gif)

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 KiB

View File

@@ -0,0 +1,69 @@
#' /* setup
library(FactoryAnalytics)
productRefNo <- "3009013"
#' */
#' ---
#' title: "Initial demand forecasting expertise
#' author: "Michał Michaluk"
#' output: pdf_document
#' ---
#' # Initial demand forecasting expertise of new product release
{{productRefNo}}
#' ## Method exmplanation
#' Demand forecasting for new product will be calculated based on relationship to existing products of the same family namly *3009002* and *3009004*.
#' *3009002*, *3009004* are the most popular colors of our product _black_ and _blue_ respectivly.
#' Retailers feedback sugests that new _dark gray_ color is havly demand, but unavaliable from our manufacture.
#' Experts consensus suggests that introduction of new *3009013* _dark gray_ product will
#' increase market share of related colors (_black_, _blue_ and new _dark gray_) in that product family about 15%.
#' In addition it will take over about
#' - 25% of *3009002* _black_ demands,
#' - 40% of *3009004* _blue_ demands
#' of existing products, becoming the most popular color in family.
#' ## Calculation
#' New color will be shipped at 2018/09/01
#' forecast 60 days from release will be more than suficient.
#' fetch current demand forecast for 3009002 (black)
blackDemand <- demand.forecast.current(
refNo = "3009002",
from = as.Date("2018/09/01"),
to = as.Date("2018/10/30")
)
#' fetch current demand forecast for 3009004 (blue)
blueDemand <- demand.forecast.current(
refNo = "3009004",
from = as.Date("2018/09/01"),
to = as.Date("2018/10/30")
)
#' Experts provided calculation
expectedDemand <- (blackDemand$level + blueDemand$level) * 0.15 + blackDemand$level * 0.25 + blueDemand$level * 0.40
darkgrayDemand <- data.frame(
refNo = rep(productRefNo, 60),
date = blackDemand$date,
level = expectedDemand
)
#' Adaptation of existing products demand only for presentation purpose
blackDemand$level <- blackDemand$level * 0.25
blueDemand$level <- blueDemand$level * 0.40
#' ## Results
plot(darkgrayDemand[, c("date", "level")], type = "l", col = "darkgray", lty = 1)
lines(blueDemand[, c("date", "level")], type = "l", col = "blue", lty = 2)
lines(blackDemand[, c("date", "level")], type = "l", col = "black", lty = 2)
legend(0, 0,
legend = c(productRefNo, "3009002 (black)", "3009004 (blue)"),
col = c("darkgray", "black", "blue"),
lty = c(1,2,2), ncol=1
)
#' Demand forecast saved alongside report generation:
darkgrayDemand
demand.forecast.new(darkgrayDemand)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

View File

Before

Width:  |  Height:  |  Size: 258 KiB

After

Width:  |  Height:  |  Size: 258 KiB

View File

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

View File

Before

Width:  |  Height:  |  Size: 340 KiB

After

Width:  |  Height:  |  Size: 340 KiB

View File

Before

Width:  |  Height:  |  Size: 296 KiB

After

Width:  |  Height:  |  Size: 296 KiB