Recalling complex logical flows?
Posted by heavymetalengineer@reddit | ExperiencedDevs | View on Reddit | 23 comments
I've found myself struggling lately with more complex logical flows and remembering what all the conditions are. Especially if there are multiple methods called in the same file so I find myself jumping around. Debugging can help as I can have the call stack, but sometimes things are set asynchronously and referred to later down the line making this trickier. IMO there is little room for improvement in the code, these flows just require a lot of context.
Often I find I'll just start copying methods with their locations and condition branches into a text file as I can't hold it all in my head. Is there a better way to do this or is this just how everyone does it? Any tips or tools that help? (I write Python and currently use VSCode)
jepperepper@reddit
if it's that complex, the code is bad. fix it.
Inside_Dimension5308@reddit
My primary strategy is to reduce complexity. So, if a requirement comes to implement a complex flow, I ask the concerned person the reason to make it complex.
Don't increase the complexity of your product. There is always a simpler solution. You are trying to create an unstable product. With increased complexity, comes more bugs.
It is difficult to recall complex logical flows. The real skill is to reduce them not to work with them.
gomihako_@reddit
TBH most of this just sounds like poor architectural design and past devs in your project trying to be clever and making things DRY when they didn't have to be. Now you're stuck with a spaghetti mess where you need to open 10 files and understand the flow between 20+ function calls just to see how your api call got consumed.
Assuming you're stuck in the current architecture, your two options are adding things on top of the knowledge base (docs, flow charts), or easing the burden of cognitive load by improving your navigation skills. You can use something like harpoon2 in vim https://github.com/ThePrimeagen/harpoon/tree/harpoon2 but to my knowledge I have not encountered any set of plugins in vscode that match the breadth and DX of vim-land plugins.
Dimencia@reddit
I run into this all the time, what I usually do is just start rewriting all of the code piece by piece to try to make it easier to understand and follow, break it entirely, put it in a TODO branch that I never look at again, and then start my actual work a few days late
... I mean, I wouldn't recommend it, that's just what I do
coyoteazul2@reddit
Why not make a flow diagram?
heavymetalengineer@reddit (OP)
That might be better than copying notes into a text file. Do you just use something like Excalidraw for this? Or what’s your preference?
coyoteazul2@reddit
I use this one, since it was what was recommended when I went to college
https://app.diagrams.net/
Now a days maybe you can give your code to an Ai and ask it to make the diagram for you. If you know what you are doing you'll be able to tell if the Ai is spewing shit or if it's reasonable. (this is not aimed to you in particular, but to other readers who may find themselves in a similar scenario)
Veuxdo@reddit
If you do this, keep your expectations low. AI is pretty good at "whiteboarding" when you iteratively described a diagram and ask for changes. It has no real capacity to look at a codebase and generate a meaningful diagram.
DootDootWootWoot@reddit
Honestly it depends. I've been able to generate workflow diagrams of orchestration code, CI/CD pipelines, arch diagrams from terraform.
Maybe 9mo ago some of the tooling may have struggled in these areas but it's pretty good with minor to moderate level complexity in diagramming as of late.
boring_pants@reddit
My reaction would be to push back on the "welp, nothing to be done in the code itself".
Better naming might help. Rewrite methods to have fewer side effects. Move code out into separate files.
In particular, I'd ask why you need to think about code "setting things asynchronously to be referre3d to later down the line". Why is it "setting things", and not calling a logically named method which describes the conceptual operation being performed? Why do you need to think about so many condition branches? If you're trying to understand the larger flow you shouldn't need to think about if-statements and variables. Those should only be relevant when zooming in and looking at simpler, smaller flows, like the implementation of a single method.
Make them require less context. That's obviously easier said than done, but that's what it boils down to. Context is bad. Look into functional programming for inspiration. Avoid or minimize side effects, so that functions do one thing and one thing only, and that thing is, as far as possible, expressed by their return value. Limit the scope of shared variables and member variables. Make sure each is used in as few places as possible, and if possible, make it impossible to access it elsewhere. Again, this limits the amount of context you need to hold in your head. If a variable can't be accessed from these methods, then it is not relevant and you don't need to think about it.
ImYoric@reddit
Depending on the kind of flows and what you need to remember, this can be where (very) strong typing becomes useful.
For instance, in Rust (or the handful of other languages with affine types), you can easily encode the steps of protocols within the type system, which further serves as statically-checked documentation (you need to do A before B and if you've done C, don't do D, etc.)
koreth@reddit
I’ve even done that in Java, though it is tedious and repetitive (lots of overlapping interfaces with even more implementation classes) and not something I’d recommend except in cases where you’re very sure the extra safety is worth the trouble. But in that specific case it was a big help and prevented a critical class of bugs that had been popping up repeatedly.
Chevaboogaloo@reddit
I would challenge your conclusion that there is little room for improvement to the code. I know it sounds idealistic but if you have to jump around too much in a file there are probably bits you can extract to make it simpler.
Ask an LLM for suggestions to get some inspiration. It might give bad suggestions but I bet it’ll also have some useful ideas.
heavymetalengineer@reddit (OP)
This is probably somewhat true, but even to get to an understanding of what can be simplified I need an understanding of the flow. Using Copilot to generate simple flows and make initial suggestions is a good idea though.
Chevaboogaloo@reddit
You can get your LLM to make mermaid diagrams of the flow too
heavymetalengineer@reddit (OP)
Funnily I’ve just been doing this. Any recommended mermaid vscode plugin? I’m trying a few right now but zooming and sizing doesn’t work
jedilowe@reddit
Part of the struggle in helping is the lack of context. It would be easy to throw out abstract answers like... look at the Command pattern, but so much of programming is intuitive so without the details it is hard to suggest an accurate refactoring that might help.
Too often CS professors only give the first half of Einstein advice... Keep it as simple as possible... and forget the rest.... but no simpler. Sometimes it just is complex and you can only make it so simple and that's why we are paid well ;)
heavymetalengineer@reddit (OP)
Yeh I don't even think it's a case of refactoring or using a different pattern. There are just a lot of pieces of information that need to be known to make a decision in code.
It doesn't feel dissimilar to how navigating slack to answer a question can feel - sometimes there are just different people in different functions providing pieces of information in threads which were the correct place to discuss that specific facet of the problem. But you now need to hop between these threads and pick up all the context.
This can be unwieldy to store in your head all at once. So is the solution just to have some sort of notes where you can keep all the context jotted down - or is there a better way? It seems likely, especially when dealing with code in an editor.
jedilowe@reddit
Yes, but save yourself some work in the moment by defining running test cases. If you use the same inputs for a long time it sets expectations in your head that is just one fewer thing to remember
s0ftware-dev@reddit
Every time you write an IF statement you need to ask yourself is this the right approach or is there an underlying abstraction needed to encapsulate the branches logic.
What you’ll often find in super complex flows in that there are multiple abstractions or “things” squashed into the same flow with multiple of the same if statement trying to apply logic for each abstraction. Better to pull them apart even if there is a bit of duplication.
heavymetalengineer@reddit (OP)
There’s definitely a little of that going on. Different methods deciding essentially the same thing using slightly varied logic. I’m just trying to pull all the context together to even understand what the nuance is and why that duplication of logic may exist.
opx22@reddit
I try to leave comments for complex flows - much easier than debugging
heavymetalengineer@reddit (OP)
To be fair the comments and class/method/variable names tend to be pretty spot on and informative. I’m just hitting a point where there’s too much context for making one decision for me to keep in my head.