refacto: specify simulation to prepare the heijunka simulation
This commit is contained in:
@@ -3,14 +3,14 @@ import SeparatorIcon from '@/icons/SeparatorIcon.vue'
|
|||||||
import type { Feature } from '@/modules/pull-system/feature/feature'
|
import type { Feature } from '@/modules/pull-system/feature/feature'
|
||||||
import FeatureSteps from '@/modules/pull-system/feature/FeatureSteps.vue'
|
import FeatureSteps from '@/modules/pull-system/feature/FeatureSteps.vue'
|
||||||
import FlowDashboard from '@/modules/pull-system/feature/FlowDashboard.vue'
|
import FlowDashboard from '@/modules/pull-system/feature/FlowDashboard.vue'
|
||||||
import SimulationControls from '@/modules/pull-system/simulation/SimulationControls.vue'
|
import PullSystemSimulationControls from '@/modules/pull-system/simulation/PullSystemSimulationControls.vue'
|
||||||
import SimulationDashboard from '@/modules/pull-system/simulation/SimulationDashboard.vue'
|
import PullSystemSimulationDashboard from '@/modules/pull-system/simulation/PullSystemSimulationDashboard.vue'
|
||||||
// [dps] import ProblemSolvingIcon from '@/icons/ProblemSolvingIcon.vue'
|
// [dps] import ProblemSolvingIcon from '@/icons/ProblemSolvingIcon.vue'
|
||||||
import PullSystemIcon from '@/icons/PullSystemIcon.vue'
|
import PullSystemIcon from '@/icons/PullSystemIcon.vue'
|
||||||
import PushSystemIcon from '@/icons/PushSystemIcon.vue'
|
import PushSystemIcon from '@/icons/PushSystemIcon.vue'
|
||||||
import FeatureItem from '@/modules/pull-system/feature/FeatureItem.vue'
|
import FeatureItem from '@/modules/pull-system/feature/FeatureItem.vue'
|
||||||
import QualityIssue from '@/modules/pull-system/feature/QualityIssue.vue'
|
import QualityIssue from '@/modules/pull-system/feature/QualityIssue.vue'
|
||||||
import { useSimulationStore } from '@/modules/pull-system/simulation/simulation-store'
|
import { usePullSystemSimulationStore } from '@/modules/pull-system/simulation/pull-system-simulation-store'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
const feature: Feature = {
|
const feature: Feature = {
|
||||||
@@ -22,7 +22,7 @@ const feature: Feature = {
|
|||||||
step: 2
|
step: 2
|
||||||
}
|
}
|
||||||
|
|
||||||
const simulationStore = useSimulationStore()
|
const simulationStore = usePullSystemSimulationStore()
|
||||||
const meanLeadTimeDeltaFloat = computed(
|
const meanLeadTimeDeltaFloat = computed(
|
||||||
() =>
|
() =>
|
||||||
parseFloat(simulationStore.meanLeadTime('push')) -
|
parseFloat(simulationStore.meanLeadTime('push')) -
|
||||||
@@ -218,8 +218,8 @@ const createdAt = new Date('2025-01-08').toLocaleDateString(undefined, {
|
|||||||
system.
|
system.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<SimulationControls type="single" />
|
<PullSystemSimulationControls type="single" />
|
||||||
<SimulationDashboard />
|
<PullSystemSimulationDashboard />
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<p>
|
<p>
|
||||||
Okay, we generally see that the <PullSystemIcon /> pull system is a bit
|
Okay, we generally see that the <PullSystemIcon /> pull system is a bit
|
||||||
@@ -232,7 +232,7 @@ const createdAt = new Date('2025-01-08').toLocaleDateString(undefined, {
|
|||||||
news mobile apps! Are patterns the same?
|
news mobile apps! Are patterns the same?
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<SimulationControls type="multiple" />
|
<PullSystemSimulationControls type="multiple" />
|
||||||
<div class="flow-multiple-simulation text">
|
<div class="flow-multiple-simulation text">
|
||||||
<p v-if="displaySimulationConclusion">
|
<p v-if="displaySimulationConclusion">
|
||||||
Now we’re pretty confident! As quality issues increase in the
|
Now we’re pretty confident! As quality issues increase in the
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useSimulationStore } from '@/modules/pull-system/simulation/simulation-store'
|
import { usePullSystemSimulationStore } from '@/modules/pull-system/simulation/pull-system-simulation-store'
|
||||||
import { popNElement } from '@/utils'
|
import { popNElement } from '@/utils'
|
||||||
import chartXkcd from 'chart.xkcd'
|
import chartXkcd from 'chart.xkcd'
|
||||||
import { onMounted, ref, watch } from 'vue'
|
import { onMounted, ref, watch } from 'vue'
|
||||||
|
|
||||||
const simulationStore = useSimulationStore()
|
const simulationStore = usePullSystemSimulationStore()
|
||||||
const SAMPLE = 15
|
const SAMPLE = 15
|
||||||
const svgElement = ref<HTMLInputElement | null>(null)
|
const svgElement = ref<HTMLInputElement | null>(null)
|
||||||
const isChartInit = ref(false)
|
const isChartInit = ref(false)
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Strategy } from '@/modules/pull-system/lean/strategy'
|
import type { Strategy } from '@/modules/pull-system/lean/strategy'
|
||||||
import { useSimulationStore } from '@/modules/pull-system/simulation/simulation-store'
|
import { usePullSystemSimulationStore } from '@/modules/pull-system/simulation/pull-system-simulation-store'
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
type: 'single' | 'multiple'
|
type: 'single' | 'multiple'
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const simulationStore = useSimulationStore()
|
const simulationStore = usePullSystemSimulationStore()
|
||||||
const NUMBER_OF_SIMULATION = 500
|
const NUMBER_OF_SIMULATION = 500
|
||||||
|
|
||||||
// [dps]
|
// [dps]
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
import PullSystemIcon from '@/icons/PullSystemIcon.vue'
|
import PullSystemIcon from '@/icons/PullSystemIcon.vue'
|
||||||
import PushSystemIcon from '@/icons/PushSystemIcon.vue'
|
import PushSystemIcon from '@/icons/PushSystemIcon.vue'
|
||||||
import type { Strategy } from '@/modules/pull-system/lean/strategy'
|
import type { Strategy } from '@/modules/pull-system/lean/strategy'
|
||||||
import { useSimulationStore } from '@/modules/pull-system/simulation/simulation-store'
|
import { usePullSystemSimulationStore } from '@/modules/pull-system/simulation/pull-system-simulation-store'
|
||||||
|
|
||||||
const simulationStore = useSimulationStore()
|
const simulationStore = usePullSystemSimulationStore()
|
||||||
|
|
||||||
const strategies: Strategy[] = ['push', 'pull']
|
const strategies: Strategy[] = ['push', 'pull']
|
||||||
// [dps]
|
// [dps]
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
/// <reference types="vite-plugin-comlink/client" />
|
||||||
|
|
||||||
|
import { featureSteps } from '@/modules/pull-system/feature/feature-steps'
|
||||||
|
import type { Strategy } from '@/modules/pull-system/lean/strategy'
|
||||||
|
import type { Dashboard, Meta } from '@/store-type'
|
||||||
|
import { getRound } from '@/utils'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
type Mean = {
|
||||||
|
leadTimeSum: number
|
||||||
|
minLeadTime: number
|
||||||
|
maxLeadTime: number
|
||||||
|
cycleTimeSum: number
|
||||||
|
complexitySum: number
|
||||||
|
qualityIssueSum: number
|
||||||
|
teamWorkExperienceSum: number
|
||||||
|
totalDaysSum: number
|
||||||
|
simulations: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
dashboards: Dashboard[]
|
||||||
|
requestedSimulation: number
|
||||||
|
simulationsDone: number
|
||||||
|
mean: Record<Strategy, Mean>
|
||||||
|
}
|
||||||
|
|
||||||
|
const initMean = (): Mean => ({
|
||||||
|
leadTimeSum: 0,
|
||||||
|
minLeadTime: Infinity,
|
||||||
|
maxLeadTime: 0,
|
||||||
|
cycleTimeSum: 0,
|
||||||
|
complexitySum: 0,
|
||||||
|
qualityIssueSum: 0,
|
||||||
|
teamWorkExperienceSum: 0,
|
||||||
|
totalDaysSum: 0,
|
||||||
|
simulations: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const instance = new ComlinkWorker<typeof import('../feature/feature-board')>(
|
||||||
|
new URL('../feature/feature-board', import.meta.url)
|
||||||
|
)
|
||||||
|
|
||||||
|
const resetMeta = (): Meta => ({
|
||||||
|
totalDays: 0,
|
||||||
|
teamWorkExperience: 0,
|
||||||
|
featuresDonePerDay: [],
|
||||||
|
strategy: {
|
||||||
|
push: 0,
|
||||||
|
pull: 0,
|
||||||
|
'pull-dps': 0,
|
||||||
|
'push-dps': 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const usePullSystemSimulationStore = defineStore(
|
||||||
|
'pull-system-dashboard',
|
||||||
|
{
|
||||||
|
state: (): State => {
|
||||||
|
return {
|
||||||
|
dashboards: [],
|
||||||
|
requestedSimulation: 0,
|
||||||
|
simulationsDone: 0,
|
||||||
|
mean: {
|
||||||
|
push: initMean(),
|
||||||
|
pull: initMean(),
|
||||||
|
'pull-dps': initMean(),
|
||||||
|
'push-dps': initMean()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
async simulate(strategy: Strategy) {
|
||||||
|
const steps = featureSteps
|
||||||
|
const backlog = await instance.newBacklog()
|
||||||
|
const features = await instance.initBoard(steps, backlog, true)
|
||||||
|
|
||||||
|
const newState = await instance.simulate(
|
||||||
|
{
|
||||||
|
backlog,
|
||||||
|
steps,
|
||||||
|
features,
|
||||||
|
meta: resetMeta()
|
||||||
|
},
|
||||||
|
strategy
|
||||||
|
)
|
||||||
|
|
||||||
|
const [worstFeature] = newState.features.sort((a, b) =>
|
||||||
|
a.qualityIssue > b.qualityIssue ? -1 : 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const dashboard: Dashboard = {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dashboards.push(dashboard)
|
||||||
|
this.mean[strategy].leadTimeSum += dashboard.analysis.meanLeadTime
|
||||||
|
this.mean[strategy].minLeadTime = Math.min(
|
||||||
|
this.mean[strategy].minLeadTime,
|
||||||
|
...newState.features.map((f) => f.leadTime)
|
||||||
|
)
|
||||||
|
this.mean[strategy].maxLeadTime = Math.max(
|
||||||
|
this.mean[strategy].maxLeadTime,
|
||||||
|
...newState.features.map((f) => f.leadTime)
|
||||||
|
)
|
||||||
|
this.mean[strategy].cycleTimeSum +=
|
||||||
|
dashboard.meta.totalDays / newState.features.length
|
||||||
|
this.mean[strategy].complexitySum += dashboard.analysis.meanComplexity
|
||||||
|
this.mean[strategy].qualityIssueSum +=
|
||||||
|
dashboard.analysis.meanQualityIssue
|
||||||
|
// this.mean[strategy].teamWorkExperienceSum +=
|
||||||
|
// dashboard.meta.teamWorkExperience
|
||||||
|
this.mean[strategy].totalDaysSum += dashboard.meta.totalDays
|
||||||
|
this.mean[strategy].simulations++
|
||||||
|
},
|
||||||
|
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 = []
|
||||||
|
this.mean.push = initMean()
|
||||||
|
this.mean.pull = initMean()
|
||||||
|
this.mean['pull-dps'] = initMean()
|
||||||
|
this.mean['push-dps'] = initMean()
|
||||||
|
this.simulationsDone = 0
|
||||||
|
this.requestedSimulation = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
meanLeadTime: (state) => (strategy: Strategy) =>
|
||||||
|
getRound(
|
||||||
|
state.mean[strategy].leadTimeSum,
|
||||||
|
state.mean[strategy].simulations
|
||||||
|
),
|
||||||
|
minLeadTime: (state) => (strategy: Strategy) =>
|
||||||
|
state.mean[strategy].minLeadTime,
|
||||||
|
maxLeadTime: (state) => (strategy: Strategy) =>
|
||||||
|
state.mean[strategy].maxLeadTime,
|
||||||
|
meanCycleTime: (state) => (strategy: Strategy) =>
|
||||||
|
getRound(
|
||||||
|
state.mean[strategy].cycleTimeSum,
|
||||||
|
state.mean[strategy].simulations
|
||||||
|
),
|
||||||
|
meanComplexity: (state) => (strategy: Strategy) =>
|
||||||
|
getRound(
|
||||||
|
state.mean[strategy].complexitySum,
|
||||||
|
state.mean[strategy].simulations
|
||||||
|
),
|
||||||
|
meanQuality: (state) => (strategy: Strategy) =>
|
||||||
|
getRound(
|
||||||
|
state.mean[strategy].qualityIssueSum,
|
||||||
|
state.mean[strategy].simulations
|
||||||
|
),
|
||||||
|
meanTeamWorkExperience: (state) => (strategy: Strategy) =>
|
||||||
|
getRound(
|
||||||
|
state.mean[strategy].teamWorkExperienceSum,
|
||||||
|
state.mean[strategy].simulations
|
||||||
|
),
|
||||||
|
meanTotalDays: (state) => (strategy: Strategy) =>
|
||||||
|
getRound(
|
||||||
|
state.mean[strategy].totalDaysSum,
|
||||||
|
state.mean[strategy].simulations
|
||||||
|
),
|
||||||
|
hasSimulationFinished: (state) =>
|
||||||
|
state.requestedSimulation > 0 &&
|
||||||
|
state.requestedSimulation === state.simulationsDone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
/// <reference types="vite-plugin-comlink/client" />
|
|
||||||
|
|
||||||
import { featureSteps } from '@/modules/pull-system/feature/feature-steps'
|
|
||||||
import type { Strategy } from '@/modules/pull-system/lean/strategy'
|
|
||||||
import type { Dashboard, Meta } from '@/store-type'
|
|
||||||
import { getRound } from '@/utils'
|
|
||||||
import { defineStore } from 'pinia'
|
|
||||||
|
|
||||||
type Mean = {
|
|
||||||
leadTimeSum: number
|
|
||||||
minLeadTime: number
|
|
||||||
maxLeadTime: number
|
|
||||||
cycleTimeSum: number
|
|
||||||
complexitySum: number
|
|
||||||
qualityIssueSum: number
|
|
||||||
teamWorkExperienceSum: number
|
|
||||||
totalDaysSum: number
|
|
||||||
simulations: number
|
|
||||||
}
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
dashboards: Dashboard[]
|
|
||||||
requestedSimulation: number
|
|
||||||
simulationsDone: number
|
|
||||||
mean: Record<Strategy, Mean>
|
|
||||||
}
|
|
||||||
|
|
||||||
const initMean = (): Mean => ({
|
|
||||||
leadTimeSum: 0,
|
|
||||||
minLeadTime: Infinity,
|
|
||||||
maxLeadTime: 0,
|
|
||||||
cycleTimeSum: 0,
|
|
||||||
complexitySum: 0,
|
|
||||||
qualityIssueSum: 0,
|
|
||||||
teamWorkExperienceSum: 0,
|
|
||||||
totalDaysSum: 0,
|
|
||||||
simulations: 0
|
|
||||||
})
|
|
||||||
|
|
||||||
const instance = new ComlinkWorker<typeof import('../feature/feature-board')>(
|
|
||||||
new URL('../feature/feature-board', import.meta.url)
|
|
||||||
)
|
|
||||||
|
|
||||||
const resetMeta = (): Meta => ({
|
|
||||||
totalDays: 0,
|
|
||||||
teamWorkExperience: 0,
|
|
||||||
featuresDonePerDay: [],
|
|
||||||
strategy: {
|
|
||||||
push: 0,
|
|
||||||
pull: 0,
|
|
||||||
'pull-dps': 0,
|
|
||||||
'push-dps': 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export const useSimulationStore = defineStore('dashboard', {
|
|
||||||
state: (): State => {
|
|
||||||
return {
|
|
||||||
dashboards: [],
|
|
||||||
requestedSimulation: 0,
|
|
||||||
simulationsDone: 0,
|
|
||||||
mean: {
|
|
||||||
push: initMean(),
|
|
||||||
pull: initMean(),
|
|
||||||
'pull-dps': initMean(),
|
|
||||||
'push-dps': initMean()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
async simulate(strategy: Strategy) {
|
|
||||||
const steps = featureSteps
|
|
||||||
const backlog = await instance.newBacklog()
|
|
||||||
const features = await instance.initBoard(steps, backlog, true)
|
|
||||||
|
|
||||||
const newState = await instance.simulate(
|
|
||||||
{
|
|
||||||
backlog,
|
|
||||||
steps,
|
|
||||||
features,
|
|
||||||
meta: resetMeta()
|
|
||||||
},
|
|
||||||
strategy
|
|
||||||
)
|
|
||||||
|
|
||||||
const [worstFeature] = newState.features.sort((a, b) =>
|
|
||||||
a.qualityIssue > b.qualityIssue ? -1 : 1
|
|
||||||
)
|
|
||||||
|
|
||||||
const dashboard: Dashboard = {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dashboards.push(dashboard)
|
|
||||||
this.mean[strategy].leadTimeSum += dashboard.analysis.meanLeadTime
|
|
||||||
this.mean[strategy].minLeadTime = Math.min(
|
|
||||||
this.mean[strategy].minLeadTime,
|
|
||||||
...newState.features.map((f) => f.leadTime)
|
|
||||||
)
|
|
||||||
this.mean[strategy].maxLeadTime = Math.max(
|
|
||||||
this.mean[strategy].maxLeadTime,
|
|
||||||
...newState.features.map((f) => f.leadTime)
|
|
||||||
)
|
|
||||||
this.mean[strategy].cycleTimeSum +=
|
|
||||||
dashboard.meta.totalDays / newState.features.length
|
|
||||||
this.mean[strategy].complexitySum += dashboard.analysis.meanComplexity
|
|
||||||
this.mean[strategy].qualityIssueSum += dashboard.analysis.meanQualityIssue
|
|
||||||
// this.mean[strategy].teamWorkExperienceSum +=
|
|
||||||
// dashboard.meta.teamWorkExperience
|
|
||||||
this.mean[strategy].totalDaysSum += dashboard.meta.totalDays
|
|
||||||
this.mean[strategy].simulations++
|
|
||||||
},
|
|
||||||
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 = []
|
|
||||||
this.mean.push = initMean()
|
|
||||||
this.mean.pull = initMean()
|
|
||||||
this.mean['pull-dps'] = initMean()
|
|
||||||
this.mean['push-dps'] = initMean()
|
|
||||||
this.simulationsDone = 0
|
|
||||||
this.requestedSimulation = 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
meanLeadTime: (state) => (strategy: Strategy) =>
|
|
||||||
getRound(
|
|
||||||
state.mean[strategy].leadTimeSum,
|
|
||||||
state.mean[strategy].simulations
|
|
||||||
),
|
|
||||||
minLeadTime: (state) => (strategy: Strategy) =>
|
|
||||||
state.mean[strategy].minLeadTime,
|
|
||||||
maxLeadTime: (state) => (strategy: Strategy) =>
|
|
||||||
state.mean[strategy].maxLeadTime,
|
|
||||||
meanCycleTime: (state) => (strategy: Strategy) =>
|
|
||||||
getRound(
|
|
||||||
state.mean[strategy].cycleTimeSum,
|
|
||||||
state.mean[strategy].simulations
|
|
||||||
),
|
|
||||||
meanComplexity: (state) => (strategy: Strategy) =>
|
|
||||||
getRound(
|
|
||||||
state.mean[strategy].complexitySum,
|
|
||||||
state.mean[strategy].simulations
|
|
||||||
),
|
|
||||||
meanQuality: (state) => (strategy: Strategy) =>
|
|
||||||
getRound(
|
|
||||||
state.mean[strategy].qualityIssueSum,
|
|
||||||
state.mean[strategy].simulations
|
|
||||||
),
|
|
||||||
meanTeamWorkExperience: (state) => (strategy: Strategy) =>
|
|
||||||
getRound(
|
|
||||||
state.mean[strategy].teamWorkExperienceSum,
|
|
||||||
state.mean[strategy].simulations
|
|
||||||
),
|
|
||||||
meanTotalDays: (state) => (strategy: Strategy) =>
|
|
||||||
getRound(
|
|
||||||
state.mean[strategy].totalDaysSum,
|
|
||||||
state.mean[strategy].simulations
|
|
||||||
),
|
|
||||||
hasSimulationFinished: (state) =>
|
|
||||||
state.requestedSimulation > 0 &&
|
|
||||||
state.requestedSimulation === state.simulationsDone
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user