0x05 abstract logic capability
With my increasing experience in writing JavaScript applications, the technologies and scenarios I try are becoming more and more complex. When the logic code becomes more and more complex, I gradually find a new problem. Many times, the logic code I write is similar, but some details are different, and these codes often have the highest maintenance cost in the later stage. This makes me feel very confused. How to make my code write less cumbersome without losing the due logic of the original code? This reminds me of the frameworks I learned before. Their implementation principle is to compress the logic code that we originally wrote very cumbersome, so that we can write it more concise and intuitive?
This is the code written by a school recruitment candidate I interviewed. Its background is used to quickly judge the establishment status of different buffs in self-propelled chess games. But obviously, such code is absolutely not allowed to exist in actual development:
- Code logic is too redundant;
- Once the general judgment logic changes, each one needs to be maintained manually;
- No good maintainability;
So I put forward how to make these codes written more "elegant" and easy to maintain.
export default { beastBuff: (state) => { let arr = []; if (state.raceCount[0]['beast'] == 2 || state.raceCount[0]['beast'] == 3) { console.log(`you got 2 beast`) arr.push(state.racebuffdata[8]) } else if (state.raceCount[0]['beast'] == 4 || state.raceCount[0]['beast'] == 5) { console.log(`you got 4 beast`) arr.pop() arr.push(state.racebuffdata[9]) } else if (state.raceCount[0]['beast'] == 6) { console.log(`you got 6 beast`) arr.pop() arr.push(state.racebuffdata[10]) } else if (state.raceCount[0]['beast'] < 2 && arr.length == 1) { arr.pop() } return arr; }, caveclanBuff: (state) => { let arr = []; if (state.raceCount[1]['caveclan'] == 2 || state.raceCount[1]['caveclan'] == 3) { console.log(`you got 2 caveclan`) arr.push(state.racebuffdata[11]) } else if (state.raceCount[1]['caveclan'] == 4) { console.log(`you got 4 caveclan`) arr.pop() arr.push(state.racebuffdata[12]) } else if (state.raceCount[1]['caveclan'] < 2 && arr.length == 1) { arr.pop() } return arr; }, demonBuff: (state) => { let arr = []; if (state.raceCount[2]['demon'] == 1) { console.log(`you got 1 demon`) arr.push(state.racebuffdata[5]) } else if (state.raceCount[2]['demon'] < 1 && arr.length == 1) { arr.pop() } return arr; } // ... }
It is not difficult to find that the logic in these xbuff functions is very close, but they are also different. So how can we optimize and abstract this code? I gave TA a sample code:
const beastConfig = [ [2, [2, 3], 8], [4, [4, 5], 9], [6, [6], 10], [2] ]
Each number in this code can be found one by one in the beastBuff function above, so how to reuse them into the logic code to realize the same function as the original code?


I also wrote him a reference answer:
const generateBuff = (rate, configArr) => { return state => { const arr = [] for (const [ output, conditions, index ] of configArr) { if (conditions && index) { // Buff calculating const isHit = conditions.some(condition => state.raceCount[0][race] == condition) if (isHit) { console.log(`you got ${output} ${race}`) arr.pop() arr.push(state.racebuffdata[index]) break } } else if (state.raceCount[0][race] < output && arr.length === 1) { // Last condition arr.pop() } } return arr } } export default { beastBuff: generateBuff('beast', [ [2, [2, 3], 8], [4, [4, 5], 9], [6, [6], 10], [2] ]), caveclanBuff: generateBuff('caveclan', [ [2, [2, 3], 11], [4, [4], 12], [2] ]), // ... }