article: better agencement

This commit is contained in:
Julien Calixte
2025-01-03 18:15:53 +01:00
parent 82d16ef0cc
commit cb3e6acc87
8 changed files with 93 additions and 45 deletions

View File

@@ -18,7 +18,7 @@ import SimulationDashboard from '@/modules/pull-system/simulation/SimulationDash
<!-- <h2>Ekiden (駅伝): long-distance running relay race</h2> --> <!-- <h2>Ekiden (駅伝): long-distance running relay race</h2> -->
<FlowIntro class="text" /> <FlowIntro class="text" />
<SeparatorIcon /> <SeparatorIcon />
<!-- <FlowHypothesis class="text" /> --> <FlowHypothesis class="text" />
<!-- <SeparatorIcon /> --> <!-- <SeparatorIcon /> -->
<FlowSetup class="text" /> <FlowSetup class="text" />
<FlowDashboard class="above" /> <FlowDashboard class="above" />

View File

@@ -1,23 +1,40 @@
<script setup lang="ts">
import PullSystemIcon from '@/icons/PullSystemIcon.vue'
</script>
<template> <template>
<div class="flow-conclusion"> <div class="flow-conclusion">
<p>
The fact that
<a
target="_blank"
rel="noopener noreferrer"
href="https://journals.aps.org/pre/abstract/10.1103/PhysRevE.96.052303#:~:text=The%20%E2%80%9Cfaster%2Dis%2Dslower,evacuation%20time%20can%20be%20achieved"
>faster is slower</a
>
is counter-intuitive but it is a fact. The more we push the more we are
slowing down the system.
</p>
<p> <p>
When money and pressure are in the game, fear, uncertainty, and doubt When money and pressure are in the game, fear, uncertainty, and doubt
spread out rapidly. So we rush, as fast as we can, and when a team has spread out rapidly. So we rush, as fast as we can, and when a team has
nothing to do, it becomes a disaster: money are being burned. nothing to do, it becomes a disaster: money are being burned.
</p> </p>
<p> <p>
Teams will overproduce. They will do every pieces they can as they are Teams will overproduce. They will do every pieces they can as they can:
autonomous: product team will pitch their features, designers will design product team will prepare their features, designers will design every
every pages, developers will rush to code forgetting why the customer screens, developers will rush to code. Then, they struggle to get these
needs this precise feature. They will then struggle to get these pieces to pieces to the very end. So the fear of having nothing to give to the next
the very end when they will transfer them to the others teams. So the fear team pushes us to produce just in case. Bugs lead to more bugs that lead
of having nothing to give to the next team pushes us to produce just in to more bugs. The productivity drops.
case. Bugs lead to more bugs that lead to more bugs. Multitasking will
drastically drop the productivity.
</p> </p>
<p> <p>
But the best way to succeed is to ask: "Is this what you need? How can I So the <PullSystemIcon /> pull system is here to change our priority.
help you?". Developpers are the clients of the Designer team, as well as Designers are
the client of the Product team. Focusing on the lead time is asking to the
next team: "Is this what you need? How can we help each other?". This is
the question of team work.
<!-- Just like in Ekiden, handovers are where the real struggles <!-- Just like in Ekiden, handovers are where the real struggles
happen but we're on the same race, together. --> happen but we're on the same race, together. -->
</p> </p>

View File

@@ -2,7 +2,18 @@
<template> <template>
<div class="flow-hypothesis"> <div class="flow-hypothesis">
<p>Here our hypothesis:</p> We need some hypothesis to start with. Here are ours:
<ol>
<li>
The more feature done in parallel, the more it is difficult to focus and
it is more likely to introduce a defect.
</li>
<li>
it takes the same amount of time for each team to complete a task
<span class="meaning">same task time</span>
</li>
</ol>
<!-- <p>Here our hypothesis:</p>
<ol> <ol>
<li> <li>
it takes the same amount of time for each team to complete a task it takes the same amount of time for each team to complete a task
@@ -19,7 +30,7 @@
</li> </li>
<li>release team never fails</li> <li>release team never fails</li>
<li>there is no limit on how many defects a feature can have.</li> <li>there is no limit on how many defects a feature can have.</li>
</ol> </ol> -->
</div> </div>
</template> </template>

View File

@@ -1,3 +1,8 @@
<script setup lang="ts">
import PullSystemIcon from '@/icons/PullSystemIcon.vue'
import PushSystemIcon from '@/icons/PushSystemIcon.vue'
</script>
<template> <template>
<div class="flow-conclusion"> <div class="flow-conclusion">
<!-- TODO: Mettre ici le comportement en pull system et en push system. <!-- TODO: Mettre ici le comportement en pull system et en push system.
@@ -5,20 +10,26 @@
En pull system, on voit petit à petit du danse avec une passation de plus en plus facile. En pull system, on voit petit à petit du danse avec une passation de plus en plus facile.
Il n'empêche que dans les deux systèmes il y ai de la création de défaut --> Il n'empêche que dans les deux systèmes il y ai de la création de défaut -->
<p> <p>
Pull system wins! The fact that Not so obvious... So what can we learn? What are the patterns we can
<a identify?
target="_blank" </p>
rel="noopener noreferrer" <p>
href="https://journals.aps.org/pre/abstract/10.1103/PhysRevE.96.052303#:~:text=The%20%E2%80%9Cfaster%2Dis%2Dslower,evacuation%20time%20can%20be%20achieved" In a primarly <PushSystemIcon /> push system, we see teams struggling and
>faster is slower stuck reworking the same features again and again to finally having all
</a> features live all at once.
is counter-intuitive but it is a fact. The more we push the more we are </p>
slowing down the system. <p>
In a primarly <PullSystemIcon /> pull system however, we see a smoother
flow of work with teams able to pass on features more easily and
continuously, leading to a more steady and predictable delivery. It's not
perfect, but you may have see a balai of features when teams work and
finish at the same time. 💃🏽
<!-- TODO complete this sentence -->
</p> </p>
<p> <p>
Before any conclusion, comparing two simulations is not enough. Let's be Before any conclusion, comparing two simulations is not enough. Let's be
more scientific here and let's generate 200 projects delivering 200 more scientific here and let's generate 200 projects delivering the 20
features each and see what happens. features of the Newsletter app and see what happens.
</p> </p>
</div> </div>
</template> </template>

View File

@@ -10,6 +10,20 @@ const featureStore = useFeatureStore()
<div class="flow-dashboard"> <div class="flow-dashboard">
<SeparatorIcon /> <SeparatorIcon />
<div class="row cards"> <div class="row cards">
<div class="card">
Days
<div class="data">
<span class="numeric">{{ featureStore.meta.totalDays }}</span
>d
</div>
</div>
<div class="card">
ETA
<div class="data">
<span class="numeric">{{ featureStore.eta }}</span>
days
</div>
</div>
<div class="card"> <div class="card">
Features Features
<span class="numeric"> <span class="numeric">
@@ -24,10 +38,6 @@ const featureStore = useFeatureStore()
{{ featureStore.meta.teamWorkExperience.toFixed(2) }} {{ featureStore.meta.teamWorkExperience.toFixed(2) }}
</span> </span>
</div> --> </div> -->
<div class="card">
Mean complexity
<div class="numeric">{{ featureStore.meanComplexity }}</div>
</div>
<div class="card"> <div class="card">
Mean lead time Mean lead time
<div class="data"> <div class="data">
@@ -43,18 +53,12 @@ const featureStore = useFeatureStore()
</div> </div>
</div> </div>
<div class="card"> <div class="card">
Days Quality issues
<div class="data"> <div class="numeric">{{ featureStore.qualityIssues }}</div>
<span class="numeric">{{ featureStore.meta.totalDays }}</span
>d
</div>
</div> </div>
<div class="card"> <div class="card">
ETA Mean complexity
<div class="data"> <div class="numeric">{{ featureStore.meanComplexity }}</div>
<span class="numeric">{{ featureStore.eta }}</span>
days
</div>
</div> </div>
</div> </div>
<FlowControls /> <FlowControls />

View File

@@ -23,11 +23,11 @@ const HARD_STOP = 5000
const getQualityIssue = ({ const getQualityIssue = ({
complexity, complexity,
tasksInParallel, featuresInParallel,
teamWorkExperience teamWorkExperience
}: { }: {
complexity: number complexity: number
tasksInParallel: number featuresInParallel: number
teamWorkExperience: number teamWorkExperience: number
}): boolean => { }): boolean => {
const qualityProbability = getQualityProbability( const qualityProbability = getQualityProbability(
@@ -35,7 +35,7 @@ const getQualityIssue = ({
teamWorkExperience teamWorkExperience
) )
const multiplicator = getOverburdenMultiplicator(tasksInParallel) const multiplicator = getOverburdenMultiplicator(featuresInParallel)
const quality = randomFloat(0, 1) const quality = randomFloat(0, 1)
return quality > qualityProbability / multiplicator return quality > qualityProbability / multiplicator
@@ -91,7 +91,7 @@ export const initBoard = (
initialFeatures.forEach((feature) => { initialFeatures.forEach((feature) => {
const step = pickRandomElement(steps) const step = pickRandomElement(steps)
feature.status = pickRandomElement(['doing', 'done']) feature.status = pickRandomElement(['doing', 'done'])
feature.step = Math.max(step.stepIndex, 1) feature.step = step.stepIndex
feature.qualityIssue = 0 feature.qualityIssue = 0
}) })
@@ -141,7 +141,7 @@ export const getFeaturesForNextDay = ({
const hasQualityIssue = getQualityIssue({ const hasQualityIssue = getQualityIssue({
complexity: feature.complexity, complexity: feature.complexity,
tasksInParallel: features.filter( featuresInParallel: features.filter(
(f) => f.status === 'doing' && f.step === feature.step (f) => f.status === 'doing' && f.step === feature.step
).length, ).length,
teamWorkExperience teamWorkExperience

View File

@@ -37,7 +37,10 @@ export const useFeatureStore = defineStore('feature', {
async initBoard(type: 'bird' | 'mobile-app', limit?: number) { async initBoard(type: 'bird' | 'mobile-app', limit?: number) {
this.backlog = newBacklog(type, limit) this.backlog = newBacklog(type, limit)
this.steps = featureSteps this.steps = featureSteps
this.features = initBoard(this.steps, this.backlog) const initialSteps = featureSteps.filter(
(step) => step.title !== 'Release' && step.title !== 'Development'
)
this.features = initBoard(initialSteps, this.backlog)
this.backlog = this.backlog.filter( this.backlog = this.backlog.filter(
(l) => !this.features.find((f) => f.name === l.name) (l) => !this.features.find((f) => f.name === l.name)
@@ -56,6 +59,8 @@ export const useFeatureStore = defineStore('feature', {
isProjectFinished: (state) => isProjectFinished(state.features), isProjectFinished: (state) => isProjectFinished(state.features),
meanComplexity: (state) => getMeanComplexity(state.features), meanComplexity: (state) => getMeanComplexity(state.features),
meanLeadTime: (state) => getMeanLeadTime(state.features), meanLeadTime: (state) => getMeanLeadTime(state.features),
qualityIssues: (state) =>
state.features.map((f) => f.qualityIssue).reduce((a, b) => a + b, 0),
meanQualityIssue: (state) => getMeanQualityIssue(state.features), meanQualityIssue: (state) => getMeanQualityIssue(state.features),
taktTime: (state): string => { taktTime: (state): string => {
const taktTime = ( const taktTime = (

View File

@@ -66,7 +66,7 @@ export const useSimulationStore = defineStore('dashboard', {
actions: { actions: {
async simulate(strategy: Strategy) { async simulate(strategy: Strategy) {
const steps = featureSteps const steps = featureSteps
const backlog = await instance.newBacklog('bird') const backlog = await instance.newBacklog('mobile-app')
const features = await instance.initBoard(steps, backlog) const features = await instance.initBoard(steps, backlog)
const newState = await instance.simulate( const newState = await instance.simulate(