add simulation module

This commit is contained in:
Julien Calixte
2023-07-24 23:36:54 +02:00
parent 532ce13796
commit eaac5520e8
11 changed files with 209 additions and 156 deletions

View File

@@ -1,76 +0,0 @@
import { featureSteps } from '@/modules/feature/feature-steps'
import { Strategy } from '@/modules/lean/strategy'
import { Dashboard, Meta } from '@/store-type'
import { defineStore } from 'pinia'
type State = {
dashboards: Dashboard[]
}
const instance = new ComlinkWorker<typeof import('../feature/feature-board')>(
new URL('../feature/feature-board', import.meta.url)
)
const resetMeta = (): Meta => ({
totalDays: 0,
daysWithProblemSolving: 0,
strategy: {
push: 0,
pull: 0,
'problem-solving': 0
}
})
export const useDashboardStore = defineStore('dashboard', {
state: (): State => {
return {
dashboards: []
}
},
actions: {
newDashboard(dashboard: Dashboard) {
this.dashboards.push(dashboard)
},
async simulate(strategy: Strategy) {
const backlog = await instance.newBacklog()
const steps = featureSteps
const features = await instance.initBoard(steps, backlog)
const newState = await instance.simulate(
{
backlog,
steps,
features,
meta: resetMeta()
},
strategy
)
const [worstFeature] = newState.features.sort((a, b) =>
a.qualityIssue > b.qualityIssue ? -1 : 1
)
this.newDashboard({
uuid: new Date().getTime().toString(),
meta: newState.meta,
analysis: {
meanComplexity: await instance.meanComplexity(newState.features),
meanLeadTime: await instance.meanLeadTime(newState.features),
meanQualityIssue: await instance.meanQualityIssue(newState.features),
worstFeature,
mainStrategy: Object.entries(newState.meta.strategy).sort((a, b) =>
a[1] > b[1] ? -1 : 1
)[0][0]
}
})
},
async simulate100(strategy: Strategy) {
for (let i = 0; i < 100; i++) {
await this.simulate(strategy)
}
},
clearDashboard() {
this.dashboards = []
}
}
})

View File

@@ -1,26 +0,0 @@
<script setup lang="ts">
import { useDashboardStore } from '@/modules/dashboard/dashboard-store'
const dashboardStore = useDashboardStore()
</script>
<template>
<div class="feature-dashboard">
Dashboard
<ul>
<li v-for="dashboard in dashboardStore.dashboards" :key="dashboard.uuid">
{{ dashboard.analysis.mainStrategy }}: mean lead time
{{ dashboard.analysis.meanLeadTime }} | worst feature for quality
{{ dashboard.analysis.worstFeature.qualityIssue }} [{{
dashboard.analysis.worstFeature.complexity
}}]
</li>
</ul>
</div>
</template>
<style scoped lang="scss">
.feature-dashboard {
color: var(--background-color);
}
</style>

View File

@@ -1,13 +1,10 @@
<script setup lang="ts">
import { useDashboardStore } from '@/modules/dashboard/dashboard-store'
import FeatureDashboard from '@/modules/feature/FeatureDashboard.vue'
import FeatureStep from '@/modules/feature/FeatureStep.vue'
import { featureSteps } from '@/modules/feature/feature-steps'
import { useFeatureStore } from '@/modules/feature/feature-store'
import { onMounted } from 'vue'
const featureStore = useFeatureStore()
const dashboardStore = useDashboardStore()
onMounted(() => featureStore.initBoard())
@@ -47,19 +44,6 @@ const pushAndProblemSolving20Percent = () => {
<button @click="featureStore.nextDay('problem-solving')">
problem solving
</button>
<button @click="dashboardStore.simulate('push')">
simulate push system
</button>
<button @click="dashboardStore.simulate('pull')">
simulate pull system
</button>
<button @click="dashboardStore.simulate100('pull')">
simulate 100 pull system
</button>
<button @click="dashboardStore.simulate('problem-solving')">
simulate pull and problem solving
</button>
<button @click="dashboardStore.clearDashboard()">clear dashboard</button>
</div>
</div>
<ul class="features-steps">
@@ -70,7 +54,6 @@ const pushAndProblemSolving20Percent = () => {
:features="featureStore.featuresGroupedByStep[step.stepIndex] ?? []"
/>
</ul>
<FeatureDashboard />
</template>
<style scoped lang="scss">

View File

@@ -3,12 +3,7 @@ import { FeatureStep } from '@/modules/feature/feature-steps'
import { features as initialFeatures } from '@/modules/feature/feature.fixture'
import { Strategy } from '@/modules/lean/strategy'
import { FeatureState } from '@/store-type'
import {
pickRandomElement,
popNElement,
shuffleArray,
sumElements
} from '@/utils'
import { getMean, pickRandomElement, popNElement, shuffleArray } from '@/utils'
const MAX_FEATURES = 30
const HARD_STOP = 5000
@@ -241,34 +236,16 @@ export const nextDay = (
export const isProjectFinished = (features: Feature[]) =>
features.every((feature) => feature.step === 0 && feature.status === 'done')
export const meanComplexity = (features: Feature[]) => {
return (
Math.round(
100 *
(sumElements(features.map((feature) => feature.complexity)) /
features.length)
) / 100
)
export const getMeanComplexity = (features: Feature[]) => {
return getMean(features.map((feature) => feature.complexity))
}
export const meanLeadTime = (features: Feature[]) => {
return (
Math.round(
100 *
(sumElements(features.map((feature) => feature.leadTime)) /
features.length)
) / 100
)
export const getMeanLeadTime = (features: Feature[]) => {
return getMean(features.map((feature) => feature.leadTime))
}
export const meanQualityIssue = (features: Feature[]) => {
return (
Math.round(
100 *
(sumElements(features.map((feature) => feature.qualityIssue)) /
features.length)
) / 100
)
export const getMeanQualityIssue = (features: Feature[]) => {
return getMean(features.map((feature) => feature.qualityIssue))
}
export const simulate = (

View File

@@ -1,9 +1,9 @@
import { Feature } from '@/modules/feature/feature'
import {
getMeanComplexity,
getMeanLeadTime,
getMeanQualityIssue,
initBoard,
meanComplexity,
meanLeadTime,
meanQualityIssue,
newBacklog,
nextDay
} from '@/modules/feature/feature-board'
@@ -50,9 +50,9 @@ export const useFeatureStore = defineStore('feature', {
}
},
getters: {
meanComplexity: (state) => meanComplexity(state.features),
meanLeadTime: (state) => meanLeadTime(state.features),
meanQualityIssue: (state) => meanQualityIssue(state.features),
meanComplexity: (state) => getMeanComplexity(state.features),
meanLeadTime: (state) => getMeanLeadTime(state.features),
meanQualityIssue: (state) => getMeanQualityIssue(state.features),
featuresGroupedByStep: (state) => {
const groupedByStep: Record<number, Feature[]> = {}

View File

@@ -0,0 +1,37 @@
<script setup lang="ts">
import { useSimulationStore } from '@/modules/simulation/simulation-store'
const simulationStore = useSimulationStore()
const NUMBER_OF_SIMULATION = 300
</script>
<template>
<div class="simulation-controls">
<button @click="simulationStore.simulate('push')">
simulate push system
</button>
<button @click="simulationStore.simulate('pull')">
simulate pull system
</button>
<button @click="simulationStore.simulate('problem-solving')">
simulate pull and problem solving
</button>
<button
@click="simulationStore.multiSimulation(NUMBER_OF_SIMULATION, 'push')"
>
simulate {{ NUMBER_OF_SIMULATION }} push system
</button>
<button
@click="simulationStore.multiSimulation(NUMBER_OF_SIMULATION, 'pull')"
>
simulate {{ NUMBER_OF_SIMULATION }} pull system
</button>
<button
@click="
simulationStore.multiSimulation(NUMBER_OF_SIMULATION, 'problem-solving')
"
>
simulate {{ NUMBER_OF_SIMULATION }} pull and problem solving
</button>
<button @click="simulationStore.clearDashboard()">clear dashboard</button>
</div>
</template>

View File

@@ -0,0 +1,43 @@
<script setup lang="ts">
import { useSimulationStore } from '@/modules/simulation/simulation-store'
const simulationStore = useSimulationStore()
</script>
<template>
<div class="simulation-dashboard">
Dashboard ({{ simulationStore.simulationsDone }} /
{{ simulationStore.requestedSimulation }}
simulations)
<table>
<thead>
<tr>
<th>#</th>
<th>push</th>
<th>pull</th>
<th>pull and DPS</th>
</tr>
</thead>
<tbody>
<tr>
<td>lead time</td>
<td>
{{ simulationStore.meanPushLeadTime }}
</td>
<td>
{{ simulationStore.meanPullLeadTime }}
</td>
<td>
{{ simulationStore.meanPullDPSLeadTime }}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<style scoped lang="scss">
.simulation-dashboard {
color: var(--background-color);
}
</style>

View File

@@ -0,0 +1,108 @@
import { featureSteps } from '@/modules/feature/feature-steps'
import { Strategy } from '@/modules/lean/strategy'
import { Dashboard, Meta } from '@/store-type'
import { getMean } from '@/utils'
import { defineStore } from 'pinia'
type State = {
dashboards: Dashboard[]
requestedSimulation: number
simulationsDone: number
}
const instance = new ComlinkWorker<typeof import('../feature/feature-board')>(
new URL('../feature/feature-board', import.meta.url)
)
const resetMeta = (): Meta => ({
totalDays: 0,
daysWithProblemSolving: 0,
strategy: {
push: 0,
pull: 0,
'problem-solving': 0
}
})
export const useSimulationStore = defineStore('dashboard', {
state: (): State => {
return {
dashboards: [],
requestedSimulation: 0,
simulationsDone: 0
}
},
actions: {
newDashboard(dashboard: Dashboard) {
this.dashboards.push(dashboard)
},
async simulate(strategy: Strategy) {
const steps = featureSteps
const backlog = await instance.newBacklog()
const features = await instance.initBoard(steps, backlog)
const newState = await instance.simulate(
{
backlog,
steps,
features,
meta: resetMeta()
},
strategy
)
const [worstFeature] = newState.features.sort((a, b) =>
a.qualityIssue > b.qualityIssue ? -1 : 1
)
this.newDashboard({
uuid: new Date().getTime().toString(),
meta: newState.meta,
analysis: {
meanComplexity: await instance.getMeanComplexity(newState.features),
meanLeadTime: await instance.getMeanLeadTime(newState.features),
meanQualityIssue: await instance.getMeanQualityIssue(
newState.features
),
worstFeature,
strategy
}
})
},
async multiSimulation(simulations: number, strategy: Strategy) {
this.requestedSimulation += simulations
for (let i = 0; i < simulations; i++) {
await this.simulate(strategy)
this.simulationsDone++
}
},
clearDashboard() {
this.dashboards = []
}
},
getters: {
meanPushLeadTime: (state) => {
return getMean(
state.dashboards
.filter((dashboard) => dashboard.analysis.strategy === 'push')
.map((dashboard) => dashboard.analysis.meanLeadTime)
)
},
meanPullLeadTime: (state) => {
return getMean(
state.dashboards
.filter((dashboard) => dashboard.analysis.strategy === 'pull')
.map((dashboard) => dashboard.analysis.meanLeadTime)
)
},
meanPullDPSLeadTime: (state) => {
return getMean(
state.dashboards
.filter(
(dashboard) => dashboard.analysis.strategy === 'problem-solving'
)
.map((dashboard) => dashboard.analysis.meanLeadTime)
)
}
}
})