tab = everyone can set it to how many space you are comfortable with
just don’t use ; if you can
human don’t read semicolon if machine also don’t need it so what does it for?
if there are possibility for unexpected behavior, it may be worth to put it for safety but consider before if that is from bad writing format or from the language itself
const groupOfLogic = () => {
a
a
b
b
}
otherBlock()
can provider better outline for seperation of code
when function have many arguments it should expand to multiple line but let’s the human decide how it should be written
new line can provide a grouping of arguments
const processEntityWithPosition = (
entity, entityRelated,
vectorX, vectorY, vectorZ,
other
) => {}
when you want to call or construct something with multiple lines allow to put first or any number of arguments on same line
there are many cases that it will easier to read
// seperate data from logics
pipe(data,
fn1,
fn2
)
the longer the variable/function/class live the longer (descriptive) the name should be
// itemValidator.js
const filterItemOnlyInStock = (items) =>
items.filter((item) => {
stocks = Stock.getAllStocks(item)
return stocks.filter((s) => s.quantity > 0)
})
additional 1 key right after you finish a line or maintaining the only last line to be without comma
treat acronym same as single word, no matter what it is any character long in this way, the rule will be simple and the same in every case style
example word: HTML, IO
in camel case: html
io
htmlIo
ioHtml
in pascal case: Html
Io
HtmlIo
IoHtml
in snake case: html
io
html_io
io_html
infix
obj
.something()
.another()
prefix
pipe(obj,
X.something(),
Y.another()
)
easier to tap between pipeline by transforming function
pipe(obj,
debug(log.info)(X.something),
Y.another()
)
and you can still chain functions even they are not in the same class
big chunk
const buildProduct = (params) => ({
name: params.name,
isActive: params.isActive || true,
price: params.price || 0,
brand: params.brandId
? BrandRepo.find(params.brandId)
: null
})
chained
const buildProduct = (name) => ({
name,
isActive: true,
price: 0,
})
const setActive = (isActive) => (product) => ({
...product, isActive
})
const setPrice = (price) => (product) => ({
...product, price
})
const setBrand = (brandId) => (product) => ({
...product,
brand: BrandRepo.find(brandId)
})
product = pipe(buildProduct(),
setActive(true),
setPrice(100),
setBrand(1)
)
don’t need to remember parameter key easier to seperate big building logic
my suggestion
find
try to retrieve something but it may not found
+so return type will be the thing or null
get
just retrieve something and it should be exists
so return type will be only the thing and may raise exception if not found
or you can use other words you want, but be consistent and explicit
for example in Laravel there are find
and findOrFail
or in elixir you may use get
and get!
only use boolean parameter as a data, never use it for beheaviour
// isActive is the boolean flag for data strucure
function setActive(isActive) {
row.isActive = isActive
}
// isHungry is the boolean flag (maybe) read from data structure
// but use to define behavior
function eatFood(isHungry) {
if (isHungry) {
// eat
} else {
// not eat
}
}
for readability and also understandability when calling the function
for setActive(true)
you can know right away that true
is mean for active
but for eatFood(true)
it hard to know what true
mean
create data structure to model the data try not to create one for config behavior
data strucutre for data is obvious, but data structure for behavior may look like this
type PurchaseParam {
isIncludeTax: boolean,
shippingFee: number | undefined,
}
function purchase(param: PurchaseParam) {
if (param.isIncludeTax) {
}
if (param.shippingFee) {
}
}
const param = {
isIncludeTax: // some specific 'Shop'
shippingFee: // total price of 'Item[]' over something
}
purchase(param)
making this kind of structure is a sign that you separate the decision logic and execution logic in different place
obviously the PurchaseParam
isn’t represent any kind of data or model
but just used do define the behavior of this specific purchase()
function
you can see from example that the actual data is Shop
and Item[]
and it better to just use the actual data
function purchase(shop: Shop, items: Item[]) {
if (shop) { // specific Shop
// include tax
}
if (items) { // total price over something
// add shipping fee
}
}
for language like js, you can use index file to be root file of directly so that you can write import with that directory name
- module - index.js - something.js - else.js // when use import 'module'
but you can do this instead
- module.js - module - something.js - else.js // when use import 'module'
because with this you can start with just
- module.js
and when the module grow larger you don’t need any renaming and just create the directory with sub module
- module.js - module - something.js - else.js
if the test fail, that means it actually is executed
I have an article for this here
when defining route, don’t define prefix in subpath
// base.js
router.use(subRoute)
// subRoute.js
router.prefix('/sub')
router.get('/', controller.get)
instead define it in base path
// base.js
router.use('/sub', subRoute)
// subRoute.js
router.get('/', controller.get)
when you digging a code of some api it’s easier to start from top level which is base path by defining prefix in base you can see which file you need to go next without jumping to that file firsts
and if you start from sub route, you can still guess prefix from file/module name