diesis
Solve code complexity. Easily
Goals:
Keep the code "familiar"
Easiness
Remove code complexity
Simplicity
Easy
adjacent = lie near
const aFunction = (arg1, arg2) => {
// return something
}
Our building block
You need an higher level abstraction
For your application
Dependency: a higher level abstraction
const { dependency } = require('diesis')
const aDependency = dependency([getArg1, getArg2], (arg1, arg2) => {
// return something
})
const res = await aDependency()
const getGarlic = dependency(() => {/* ... */})
const getOliveOil = dependency(() => {/* ... */})
const getWater = dependency(() => {/* ... */})
const getSalt = dependency(() => {/* ... */})
const getDriedPasta = dependency(() => {/* ... */})
const getCondiments = dependency([getGarlic, getOliveOil],
(garlic, oliveOil) => {/* ... */})
const getPasta = dependency([getDriedPasta, getWater, getSalt],
(driedPasta, water, salt) => {/* ... */})
const pastaAglioOlio = dependency([getCondiments, getPasta],
(condiments, pasta) => {/* ... */})
Pasta aglio and olio
const dish = await pastaAglioOlio()
Sort out execution order
Ensure a dependency is only executed once
Deal with sync/async
What diesis does:
const aDependency = dependency(['local', getDep], (local, dep) => {/* ... */})
Injecting arguments
await aDependency({ local: 3 })
const getGarlic = dependency(() => {/* ... */})
const getOliveOil = dependency(['servings'], (servings) => {/* ... */})
const getWater = dependency(() => {/* ... */})
const getSalt = dependency(() => {/* ... */})
const getDriedPasta = dependency(['servings'], (servings) => {/* ... */})
const getCondiments = dependency([getGarlic, getOliveOil],
(garlic, oliveOil) => {/* ... */})
const getPasta = dependency([getDriedPasta, getWater, getSalt],
(driedPasta, water, salt) => {/* ... */})
const pastaAglioOlio = dependency([getCondiments, getPasta],
(condiments, pasta) => {/* ... */})
Pasta aglio and olio for n servings
const dish = await pastaAglioOlio({ servings: 3 })
diesis design
- Low cognitive load
- no "framework"
- no centralised registry
- no reimplementing language features
Simple
sim – plex = one braid
Code complexity explained with pasta
Spaghetti
you pull one, you get too many
Lasagne
To find what you search you have to dig through many layers
Copy/pasta
Solving problems adding more pasta
const numberOfVegetarianDishes = await countVegetarianDishes({ menuId: 123456 })
API: first iteration
const getDishes = (menuId) => {
// ...
return Promise.resolve([
{ name: 'Pasta Bolognese', vegetarian: false },
{ name: 'Pasta with tomato', vegeratian: true },
{ name: 'Pasta aglio olio', vegeratian: true },
{ name: 'Pasta with meatballs', vegeratian: false }
])
}
const countVegetarianDishes = async ({ menuId }) => {
const dishes = await getDishes(menuId)
return dishes.filter((dish) =>
dish.vegetarian).length
}
Without Diesis
const getDishes = dependency(['menuId'], (menuId) => {
// ...
return Promise.resolve([
{ name: 'Pasta Bolognese', vegetarian: false },
{ name: 'Pasta with tomato', vegeratian: true },
{ name: 'Pasta aglio olio', vegeratian: true },
{ name: 'Pasta with meatballs', vegeratian: false }
])
})
const countVegetarianDishes = dependency([getDishes], (dishes) =>
dishes.filter((dish) => dish.vegetarian).length)
With Diesis
const numberOfVegetarianDishes = await countVegetarianDishes({ menuId: 123456 })
API: Second iteration
const numberOfDishes = await countDishes({ menuId: 123456 })
const getDishes = (menuId) => {
// ...
return Promise.resolve([
{ name: 'Pasta Bolognese', vegetarian: false },
{ name: 'Pasta with tomato', vegeratian: true },
{ name: 'Pasta aglio olio', vegeratian: true },
{ name: 'Pasta with meatballs', vegeratian: false }
])
}
const countVegetarianDishes = async ({ menuId }) => {
const dishes = await getDishes(menuId)
return dishes.filter((dish) =>
dish.vegetarian).length
}
const countDishes = async ({ menuId }) => {
const dishes = await getDishes(menuId)
return dishes.length
}
Without Diesis
const getDishes = dependency(['menuId'], (menuId) => {
// ...
return Promise.resolve([
{ name: 'Pasta Bolognese', vegetarian: false },
{ name: 'Pasta with tomato', vegeratian: true },
{ name: 'Pasta aglio olio', vegeratian: true },
{ name: 'Pasta with meatballs', vegeratian: false }
])
})
const countVegetarianDishes = dependency([getDishes], (dishes) =>
dishes.filter((dish) => dish.vegetarian).length)
const countDishes = dependency([getDishes], (dishes) => {
return dishes.length
})
With Diesis
API: third iteration
const numberOfVegetarianDishes = await countVegetarianDishes({ menuId: 123456 })
const numberOfDishes = await countDishes({ menuId: 123456 })
const vegetarianDishesRatio = await getVegetariaDishesRatio({ menuId: 123456 })
Without Diesis
const getDishes = (menuId) => {
// ...
return Promise.resolve([
{ name: 'Pasta Bolognese', vegetarian: false },
{ name: 'Pasta with tomato', vegeratian: true },
{ name: 'Pasta aglio olio', vegeratian: true },
{ name: 'Pasta with meatballs', vegeratian: false }
])
}
const countVegetarianDishes = async ({ menuId }) => {
const dishes = await getDishes(menuId)
return dishes.filter((dish) =>
dish.vegetarian).length
}
const countDishes = async ({ menuId }) => {
const dishes = await getDishes(menuId)
return dishes.length
}
const getVegetarianDishesRatio = async ({ menuId }) => {
const nDishes = await countDishes({ menuId })
const nVeg = await vegetarianDishesCourses({ menuId })
return nVeg / nDishes
}
Without Diesis (now correct)
const getDishes = (menuId) => {
// ...
return Promise.resolve([
{ name: 'Pasta Bolognese', vegetarian: false },
{ name: 'Pasta with tomato', vegeratian: true },
{ name: 'Pasta aglio olio', vegeratian: true },
{ name: 'Pasta with meatballs', vegeratian: false }
])
}
const countVegetarianDishesFromList = (dishes) =>
dishes.filter((d) => m.vegetarian).length
const countVegetarianDishes = async ({ menuId }) => {
const dishes = await getDishes(menuId)
return countVegetarianDishesFromList(dishes)
}
const countDishesFromList = (dishes) => dishes.length
const countDishes = async ({ menuId }) => {
const dishes = await getDishes(menuId)
return countDishesFromList(dishes)
}
const getVegetarianDishesRatio = async ({ menuId }) => {
const dishes = await getDishes(manuId)
const nDishes = countDishesFromList(dishes)
const nVegs = countVegetarianDishesFromList(dishes)
return nVegs / nDishes
}
With Diesis
const getDishes = dependency(['menuId'], (menuId) => {
// ...
return Promise.resolve([
{ name: 'Pasta Bolognese', vegetarian: false },
{ name: 'Pasta with tomato', vegeratian: true },
{ name: 'Pasta aglio olio', vegeratian: true },
{ name: 'Pasta with meatballs', vegeratian: false }
])
})
const countVegetarianDishes = dependency([getDishes], (dishes) =>
dishes.filter((dish) => dish.vegetarian).length)
const countDishes = dependency([getDishes], (dishes) => {
return dishes.length
})
const getMainCourseRatio = dependency([countVegetarianDishes, countDishes],
(nVegs, nDishes) => {
return nVegs / nDishes
})
Testing without Diesis
const countDishes = async ({ menuId }) => {
const dishes = await getDishes(menuId)
return dishes.length
}
// :-(
const countDishesFromList = (dishes) => dishes.length
const countDishes = async ({ menuId }) => {
const dishes = await getDishes(menuId)
return countDishesFromList(dishes)
}
countDishesFromList(['pasta1', 'pasta2', 'pasta3'])
.then(n => {
assert(n === 3)
})
// :-|
Testing with Diesis
const countDishes = dependency([getDishes], (dishes) => {
return dishes.length
})
assert(countDishes.dep.func(['pasta1', 'pasta2', 'pasta3']) === 3)
run multiple dependencies
// Don't do that!
const [vegetarianDishesRatio, vegetarianDishes] = await Promise.all([
run(getVegetarianDishesRatio, { menuId: 123456 }),
run(countVegetarianDishes, { menuId: 123456 })
])
// Do that instead!
const { run } = require('diesis')
const [vegetarianDishesRatio, vegetarianDishes] = await run([
getVegetarianDishesRatio,
countVegetarianDishes
], { menuId: 123456 })
Memoize dependencies
const { dependencyMemo } = require('diesis')
const database = dependencyMemo([], () => {
// ...
})
@sithmel
Thanks and buon appetito
diesis
By Maurizio Lupo
diesis
A dependency injection library
- 763