feat: 🎸 simulation

fix dps and add the push and DPS strategy
This commit is contained in:
Julien Calixte
2023-07-26 19:33:12 +02:00
parent 1f49b0f755
commit 4af91102b8
9 changed files with 125 additions and 54 deletions

View File

@@ -8,6 +8,20 @@
display: flex; display: flex;
gap: 1rem; gap: 1rem;
padding: 0 1rem; padding: 0 1rem;
flex-wrap: wrap;
}
dl dl,
dl ol,
dl ul,
ol dl,
ol ol,
ol ul,
ul dl,
ul ol,
ul ul {
font-size: 90%;
margin: 0;
} }
ul { ul {

View File

@@ -58,7 +58,14 @@ const isLive = computed(
</div> </div>
</div> </div>
<div v-if="isLive" class="live"> <div v-if="isLive" class="live">
{{ featuresDone.length }} features live! <span v-if="featuresDone.length === 0">No features live yet</span>
<span v-else>
{{ featuresDone.length }} feature<template
v-if="featuresDone.length > 1"
>s</template
>
live!
</span>
</div> </div>
<ul class="done-list"> <ul class="done-list">
<li v-for="feature in featuresDone" :key="feature.name"> <li v-for="feature in featuresDone" :key="feature.name">

View File

@@ -10,16 +10,17 @@ onMounted(() => featureStore.initBoard())
const pullAndProblemSolving20Percent = () => { const pullAndProblemSolving20Percent = () => {
if (featureStore.meta.totalDays % 5 === 0) { if (featureStore.meta.totalDays % 5 === 0) {
featureStore.nextDay('problem-solving') featureStore.nextDay('pull-dps')
} else { } else {
featureStore.nextDay('pull') featureStore.nextDay('pull')
} }
} }
const pushAndProblemSolving20Percent = () => { const pushAndProblemSolving20Percent = () => {
if (featureStore.meta.totalDays % 5 === 0) { if (featureStore.meta.totalDays % 5 === 0) {
featureStore.nextDay('problem-solving') featureStore.nextDay('push-dps')
} else { } else {
featureStore.nextDay('pull') featureStore.nextDay('push')
} }
} }
</script> </script>

View File

@@ -57,7 +57,7 @@ export const getFeaturesForNextDay = ({
features: Feature[] features: Feature[]
steps: FeatureStep[] steps: FeatureStep[]
initialStep: number initialStep: number
strategy: Strategy strategy: Strategy | 'problem-solving'
daysWithProblemSolving: number daysWithProblemSolving: number
}): [Feature[], Feature[]] => { }): [Feature[], Feature[]] => {
features features
@@ -78,6 +78,7 @@ export const getFeaturesForNextDay = ({
const nextStep = steps.find( const nextStep = steps.find(
(step) => step.stepIndex === feature.step - 1 (step) => step.stepIndex === feature.step - 1
) )
if (!nextStep) { if (!nextStep) {
break break
} }
@@ -96,21 +97,23 @@ export const getFeaturesForNextDay = ({
feature.status = 'doing' feature.status = 'doing'
} }
if (feature.status === 'doing') { if (feature.status === 'done') {
if ( break
hasQualityIssue({ }
complexity: feature.complexity,
tasksInParallel: features.filter( if (
(f) => f.status === 'doing' && f.step === feature.step hasQualityIssue({
).length, complexity: feature.complexity,
daysWithProblemSolving tasksInParallel: features.filter(
}) (f) => f.status === 'doing' && f.step === feature.step
) { ).length,
feature.step = Math.min(4, feature.step + 1) daysWithProblemSolving
feature.qualityIssue++ })
} else { ) {
feature.step-- feature.step = Math.min(4, feature.step + 1)
} feature.qualityIssue++
} else {
feature.step--
} }
break break
} }
@@ -119,11 +122,12 @@ export const getFeaturesForNextDay = ({
if (features.length < MAX_FEATURES) { if (features.length < MAX_FEATURES) {
switch (strategy) { switch (strategy) {
case 'push': { case 'push': {
const [newFeature] = popNElement(backlog, 1) const [nextFeature] = popNElement(backlog, 1)
if (newFeature) { if (nextFeature) {
features.push({ ...newFeature, step: initialStep }) features.push({ ...nextFeature, step: initialStep })
} }
break break
} }
case 'pull': { case 'pull': {
@@ -158,21 +162,21 @@ const getOverburdenMultiplicator = (tasksInParallel: number) => {
case 1: case 1:
return 1 return 1
case 2: case 2:
return 1.05
case 3:
return 1.08
case 4:
return 1.1 return 1.1
case 3:
return 1.3
case 4:
return 1.6
case 5: case 5:
return 1.15 return 2.2
case 6: case 6:
return 1.25 return 3.2
case 7: case 7:
return 1.35 return 4.5
case 8: case 8:
return 1.4 return 6
default: default:
return 1.5 return 8
} }
} }
@@ -209,13 +213,14 @@ const getQualityProbability = (
export const nextDay = ( export const nextDay = (
state: FeatureState, state: FeatureState,
strategy: Strategy strategy: Strategy | 'problem-solving'
): FeatureState => { ): FeatureState => {
state.meta.totalDays++ state.meta.totalDays++
state.meta.strategy[strategy]++
if (strategy === 'problem-solving') { if (strategy === 'problem-solving') {
state.meta.daysWithProblemSolving++ state.meta.daysWithProblemSolving++
} else {
state.meta.strategy[strategy]++
} }
const [backlog, features] = getFeaturesForNextDay({ const [backlog, features] = getFeaturesForNextDay({
@@ -226,7 +231,6 @@ export const nextDay = (
strategy, strategy,
daysWithProblemSolving: state.meta.daysWithProblemSolving daysWithProblemSolving: state.meta.daysWithProblemSolving
}) })
state.backlog = backlog state.backlog = backlog
state.features = features state.features = features
@@ -255,11 +259,11 @@ export const simulate = (
let i = 0 let i = 0
while (!isProjectFinished(state.features) && i++ < HARD_STOP) { while (!isProjectFinished(state.features) && i++ < HARD_STOP) {
if (strategy === 'problem-solving') { if (strategy === 'pull-dps' || strategy === 'push-dps') {
if (state.meta.totalDays % 5 === 0) { if (state.meta.totalDays % 5 === 0) {
state = nextDay(state, 'problem-solving') state = nextDay(state, 'problem-solving')
} else { } else {
state = nextDay(state, 'pull') state = nextDay(state, strategy.split('-')[0] as Strategy)
} }
} else { } else {
state = nextDay(state, strategy) state = nextDay(state, strategy)

View File

@@ -19,7 +19,8 @@ const resetMeta = (): Meta => ({
strategy: { strategy: {
push: 0, push: 0,
pull: 0, pull: 0,
'problem-solving': 0 'pull-dps': 0,
'push-dps': 0
} }
}) })

View File

@@ -1 +1 @@
export type Strategy = 'push' | 'pull' | 'problem-solving' export type Strategy = 'push' | 'pull' | 'pull-dps' | 'push-dps'

View File

@@ -21,10 +21,16 @@ const NUMBER_OF_SIMULATION = 1000
</button> </button>
<button <button
class="button button-outline" class="button button-outline"
@click="simulationStore.simulate('problem-solving')" @click="simulationStore.simulate('pull-dps')"
> >
simulate pull and problem solving simulate pull and problem solving
</button> </button>
<button
class="button button-outline"
@click="simulationStore.simulate('push-dps')"
>
simulate push and problem solving
</button>
</div> </div>
<div class="row"> <div class="row">
<button <button
@@ -42,14 +48,19 @@ const NUMBER_OF_SIMULATION = 1000
<button <button
class="button button-outline" class="button button-outline"
@click=" @click="
simulationStore.multiSimulation( simulationStore.multiSimulation(NUMBER_OF_SIMULATION, 'pull-dps')
NUMBER_OF_SIMULATION,
'problem-solving'
)
" "
> >
simulate {{ NUMBER_OF_SIMULATION }} pull and problem solving simulate {{ NUMBER_OF_SIMULATION }} pull and problem solving
</button> </button>
<button
class="button button-outline"
@click="
simulationStore.multiSimulation(NUMBER_OF_SIMULATION, 'push-dps')
"
>
simulate {{ NUMBER_OF_SIMULATION }} push and problem solving
</button>
<button <button
class="button button-clear" class="button button-clear"
@click="simulationStore.clearDashboard()" @click="simulationStore.clearDashboard()"

View File

@@ -6,7 +6,7 @@ const simulationStore = useSimulationStore()
<template> <template>
<div class="simulation-dashboard"> <div class="simulation-dashboard">
<h3>Dashboard</h3> <h3>Simulation dashboard</h3>
<h4> <h4>
({{ simulationStore.simulationsDone }} / ({{ simulationStore.simulationsDone }} /
{{ simulationStore.requestedSimulation }} {{ simulationStore.requestedSimulation }}
@@ -19,6 +19,7 @@ const simulationStore = useSimulationStore()
<th>push</th> <th>push</th>
<th>pull</th> <th>pull</th>
<th>pull and DPS</th> <th>pull and DPS</th>
<th>push and DPS</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -33,6 +34,9 @@ const simulationStore = useSimulationStore()
<td class="numeric"> <td class="numeric">
{{ simulationStore.meanPullDPSLeadTime }} {{ simulationStore.meanPullDPSLeadTime }}
</td> </td>
<td class="numeric">
{{ simulationStore.meanPushDPSLeadTime }}
</td>
</tr> </tr>
<tr> <tr>
<td>Complexity</td> <td>Complexity</td>
@@ -45,6 +49,9 @@ const simulationStore = useSimulationStore()
<td class="numeric"> <td class="numeric">
{{ simulationStore.meanPullDPSComplexity }} {{ simulationStore.meanPullDPSComplexity }}
</td> </td>
<td class="numeric">
{{ simulationStore.meanPushDPSComplexity }}
</td>
</tr> </tr>
<tr> <tr>
<td>Quality issue</td> <td>Quality issue</td>
@@ -57,6 +64,9 @@ const simulationStore = useSimulationStore()
<td class="numeric"> <td class="numeric">
{{ simulationStore.meanPullDPSQuality }} {{ simulationStore.meanPullDPSQuality }}
</td> </td>
<td class="numeric">
{{ simulationStore.meanPushDPSQuality }}
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -4,6 +4,8 @@ import { Dashboard, Meta } from '@/store-type'
import { getRound } from '@/utils' import { getRound } from '@/utils'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
// Get features done per day to plot it
type Mean = { type Mean = {
leadTimeSum: number leadTimeSum: number
complexitySum: number complexitySum: number
@@ -35,7 +37,8 @@ const resetMeta = (): Meta => ({
strategy: { strategy: {
push: 0, push: 0,
pull: 0, pull: 0,
'problem-solving': 0 'pull-dps': 0,
'push-dps': 0
} }
}) })
@@ -48,7 +51,8 @@ export const useSimulationStore = defineStore('dashboard', {
mean: { mean: {
push: newMean(), push: newMean(),
pull: newMean(), pull: newMean(),
'problem-solving': newMean() 'pull-dps': newMean(),
'push-dps': newMean()
} }
} }
}, },
@@ -106,7 +110,8 @@ export const useSimulationStore = defineStore('dashboard', {
this.dashboards = [] this.dashboards = []
this.mean.push = newMean() this.mean.push = newMean()
this.mean.pull = newMean() this.mean.pull = newMean()
this.mean['problem-solving'] = newMean() this.mean['pull-dps'] = newMean()
this.mean['push-dps'] = newMean()
} }
}, },
getters: { getters: {
@@ -118,8 +123,14 @@ export const useSimulationStore = defineStore('dashboard', {
}, },
meanPullDPSLeadTime: (state) => { meanPullDPSLeadTime: (state) => {
return getRound( return getRound(
state.mean['problem-solving'].leadTimeSum, state.mean['pull-dps'].leadTimeSum,
state.mean['problem-solving'].simulations state.mean['pull-dps'].simulations
)
},
meanPushDPSLeadTime: (state) => {
return getRound(
state.mean['push-dps'].leadTimeSum,
state.mean['push-dps'].simulations
) )
}, },
meanPushComplexity: (state) => { meanPushComplexity: (state) => {
@@ -136,8 +147,14 @@ export const useSimulationStore = defineStore('dashboard', {
}, },
meanPullDPSComplexity: (state) => { meanPullDPSComplexity: (state) => {
return getRound( return getRound(
state.mean['problem-solving'].complexitySum, state.mean['pull-dps'].complexitySum,
state.mean['problem-solving'].simulations state.mean['pull-dps'].simulations
)
},
meanPushDPSComplexity: (state) => {
return getRound(
state.mean['push-dps'].complexitySum,
state.mean['push-dps'].simulations
) )
}, },
meanPushQuality: (state) => { meanPushQuality: (state) => {
@@ -154,8 +171,14 @@ export const useSimulationStore = defineStore('dashboard', {
}, },
meanPullDPSQuality: (state) => { meanPullDPSQuality: (state) => {
return getRound( return getRound(
state.mean['problem-solving'].qualityIssueSum, state.mean['pull-dps'].qualityIssueSum,
state.mean['problem-solving'].simulations state.mean['pull-dps'].simulations
)
},
meanPushDPSQuality: (state) => {
return getRound(
state.mean['push-dps'].qualityIssueSum,
state.mean['push-dps'].simulations
) )
} }
} }