4 ms·
> Only break it down into sub-functions when re-use requires it. Don't do it solely for the sake of organization What about for testing? What about for reducin
by ryanjshaw 3y ago
> Only break it down into sub-functions when re-use requires it. Don't do it solely for the sake of organization
What about for testing? What about for reducing state you need to keep in mind? What about releasing resources? What about understanding the impact of a change? Etc.
Consider an end of day process with 10 non-reusable steps that must run in order and each step is 100 lines. Each step uses similar data to the step before it so variables are similar but not the same. You would really choose a 1000 line single function?
- jonahx 3y ago> What about for testing? For "use-case" code like this with many steps, you are typically testing how things wire together, and so will either be injecting mocks to unit test, in which case it is not a problem, or wanting to integration or e2e test, in which case it is also not a problem. If complex, purely logical computation is part of the larger function, and you can pull that part out into a pure function which can be easily unit tested without mocks, that is indeed a valid factoring which I support, and an exception to the general rule. > What about for reducing state you need to keep in mind? Typically not a problem because if the function corresponds to a business use-case, you and everybody else is already thinking about it as "one thing". > What about releasing resources? Not a problem I have ever once run into with backend programming in garbage collected languages. Obviously if you are in a different situation, YMMV. > Consider an end of day process with 30 non-reusable steps that must run in order and each step is 100 lines. I would use my judgement and might break it down. Again, I have never encountered such a situation in many years of programming. You seem to be trying to find the (ime) rare exceptions as if those disprove the general rule. But in practice the "explode your holistic function unnecessarily into 10 parts" is a much more common error than taking "don't break it down" too far.
- syntheweave 3y agolet DebugFlags = {StepOne=false, StepTwo=false, StepThree=true}; if (DebugFlags.StepOne) { ... } if (DebugFlags.StepTwo) { ... } if (DebugFlags.StepThree) { ... } Your training in structured, DRY and OOP will recoil at this: More branches! Impossible. But your spec says "must run in order". It does this by design. Every resource can be tracked by reading it top to bottom, and the only way in which you can miss it is through a loop, which you can also aim to minimize usage of. The spec also says "uses similar data to the step before it". If variables are similar-not-same, enclose them in curly braces so that you get some scope guarding. The debug flags contain the information needed to generate whatever test data is necessary. They can alternately be organized as enumerated state instead of booleans: {All, TestOne, TestTwo, TestThree}. Long, bespoke linear sequences can be hairy, but the tools to deal with them are present in current production languages without atomizing the code into tiny functions. Occasionally you can find a useful pattern that does call for a new function, and do a "harvest" on the code and get its size down. But you have to be patient with it before you have a good sense of where a new parameterized function gets the right effect, and where inlining and flagging an existing one will do better.