Code is so abstract, which is why we use metaphors and mental models.
Are you capable of describing some of your mental models or visualizations that form as you code?
I know, this answer may be tough to articulate, so I'm not expecting perfect answers, just a discussion.
That's an interesting question! I never thought about how my mind works when I try to solve coding problems.
My favorite thing to do when I'm stuck with a problem, is to go for a little walk and to start thinking about it.
My mental model could be described as little piles of requirements, problems and possible roads to take lying on the ground, which I can skim, sort or shuffle. Without having to think about it I tend to grab one or multiple connected problems in the process I either find most interesting or which seem to be the most important. I don't have to think it all through. Knowing that there is a solution and being able to roughly picture it is enough to go on and makes it clearer what other stuff I should or should not worry about and - also very important - what to do next once I get back to the computer.
If I'm unable to solve what I think is a major problem or at least to identify the sensible next step, I try to take a step back (which is a 100 times easier when you are NOT sitting at your computer). Very often I find that I can ignore a problem completely, that a requirement might require some clarification or rethinking or that it might not such a bad idea to go with a much simpler solution instead, clearing all the piles away, which is always a relief :)
To make sure everyone (future me included) is on the same page, I tend to make doodles out of logic and data.
Then I use mindmaps and Mermaid's Live Editor [1] to create flowcharts/sequence diagrams to keep track of my thoughts and to share it with my coworkers.
Here's a recent example of a pdf creation process [2] for this API I'm working on.
[1] mermaidjs.github.io/mermaid-live-e...
[2] bit.ly/2ksIusm
Nice, I've not see mermaid before - I've used planttext.com and draw.io for much the same purpose as well as more "formal" documentation. Whatever the tool, I definitely agree that sometimes you have to really see it to spot flaws in the logic.
Seeing the flow is so much easier for everyone else when we're trying to communicate how we think it should be done.
Nice, Mermaid looks very similar to PlantUML's notation. Maybe the inspiration was derived from PlantUML.
I've never used PlantUML but if it's similar, I'd love it ! I find it so much easier to draw graphs with such notations :/ it's easily commited within a git repository too !
Edit: I just checked out PlantUML. I'm definitely going to try it !
One thing that took me a long time to figure out is that I am a very visual thinker.
For example, in math, an equation doesn't mean anything to me until I can represent it graphically in a way that gives me the essence of what the equation means in the particular context that I care about. After that I can learn some rules for manipulating stuff algebraically, but for me the visual intuition always has to come first.
I tend to apply this even for things where maybe there isn't an obvious connection. For example, when it comes to business rules, I tend to think in terms of hierarchical structures like trees, or in terms of graphs - little boxes with arrows between them... Sometimes I also think about connecting things, or rotating them into place, or moving them around in a list...
I've also learned that for me, it's important to always start with a simple scenario and then to gradually extend it bit by bit.
If some abstraction does not match your mental model, it's likely a sign that it's simply a wrong abstraction.
The right abstraction must be obvious and laughably simple.
I have to draw out little boxes on a real life paper pad, and normally have to write out a few rough pseudocode experimental implementations to see if I'm headed in the right direction. Trying to keep the work in small-as-possible chunks helps too, but not always feasible if you're writing some huge new feature that only works when it's all done... I must admit even after many years I still find it a real struggle to split up big tasks into smaller, more manageable ones, even though I know this can often lead to issues later on...
UML gets a bad rap, as the kids say, and it's easy to forget it was carefully designed from years of experience to be the best tool people could come up with for this kind of thing.
Generating your code from UML hasn't ever taken off, but using it to document flows and structure in your code is really useful - and anyone with any experience in UML can recognise the symbology you're using instantly.
Where it falls down is in the difficulty to mesh documentation and code, and the simple fact that diagrams don't go into version control very well.
I came across PlantUML a year or so back - very late to that party. It allows developers to describe their architecture and models in a text-based declarative language, and PlantUML then spits out UML style visualisations in PNG or SVG. I've found that class diagrams, component diagrams, and sequence diagrams are amazingly useful tools to share knowledge, and the ability to place the diagram source alongside code means it can be maintained in the same step.
No more bad diagrams on a whiteboard drawn hastily!
I love PlantUML!
Also, huge +1 on UML being incredibly useful. Learning sequence diagrams was an absolute turning point for me.
I find myself almost always reaching for OOP when I'm trying to reason about code. That's because I have a Ruby background and I still think OOP is a good idea in a lot of places.
In situations where OOP doesn't make sense, I try my hardest to think about data instead of logic and abstractions. I try to reason about that data. That may not make much sense, but I like to imagine that I'm pretty decent at pulling apart implementations and putting them back together with less logic.
I completely relate to this (except I have Python background instead of Ruby).
The Rubber Duck Method!
I came to the realization that if I'm turning inward, and just silently think about structural problems, a lot of times I loose references and get lost. So the solution for this was to explain my problems in words. Loudly.
Think about it: While thinking you often just shuffle around shapeless concepts in your head, often overlooking details. But if you force yourself to articulate your problem, you end up solidifying your concepts as words, and that often leads to a realization.
In the office we call this "The Rubber Duck", because how you do it is you roll to your team members and try to explain them what your problem is. They might be able to help, but most of the time they could have been just rubber ducks, because you end up realizing your solution while explaining, without them saying anything. I'm sure many of you can relate to this.
Yup, I often will grab a co-worker and ask them to just listen to me talk this out and ask any clarifying questions they need, and I do the same for them. Having to articulate it out-loud is so helpful
I like to try to "keep the entire program in my head" if possible; which helps to visualize how changes affect different parts of the code, and what side effects I have to watch out for.
That's one reason I love React - it lets me think in components, instead of in systems; so I only have to worry about one component at a time (for the most part) when developing.
As far as visualizations... huh - I don't think I've ever thought of what I visualize when I code... but I suppose I try to understand what data there is in the program, and how that affects the output. I really like the idea that changing data directly changes the output - which is (again) why a framework like React is helpful: the output on screen only changes when the data changes.
Interesting to think about, thanks! I may edit my answer after thinking about it some more :)
I have always said that I can ”see” systems moving. I cannot actually describe that very well as I don't see code text or any diagrams. Algorithms and iterators are probably easiest to describe as they are little mechanical machines or motors whirling away. My wife can write extremely sophisticated SQL that I simply cannot as I want to ”see” how it works (the actual plan) rather than the abstract specification. She described one really complex query saying ”... and you grab both ends and pull it and ta-da it flips right side out and you have the answer!” 🤔 I wasn't able to grok it.
Just like @nestedsoftware , I'm a very visual person. If I say I understand something, you can be sure that I can draw you a model of what that thing is. When I code, it's very much like I was in Tron, I live in a visual world of code. It's hard for me to describe, but let's try. When I'm using a collection's method like map or reduce, I'm visualizing all the items very much like the illustration on reactivex.io/. I'm also able to zoom into the data structures and logic of the code. I also do a lot of blackboxing where I visualize every piece of logic as just its inputs, a label of what it does and its output. And then I recurse.
Visualizing a solution some technical architecture is quite relevant to me in my role as a tech lead. I always struggle with this, but I always look to improve my visualization skills to keep the project team's ride a smooth one. For me, translating what is in my head to paper is the most challenging aspect.
Since being diagnosed, I have attributed my ongoing visualization struggles to ADHD. That is not to say I am unique or that others do not struggle the same as I do. I always felt that I could solve problems in non-linear ways but strain when trying to replicate my path to a colleague. You could say the same of me when it comes to technical design and architecture. What is clear to me is obtuse and opaque to others based on my explanation.
I had an on and off relationship with UML, believing that it was the solution. I love structure, and boy does UML have structure. Unfortunately, one can spend an inordinate time modeling an entire system in vain before you ever communicate something useful to someone else. Not to mention that BAs, PMs, and clients love when you break out a UML diagram.
I did find something recently that seems to help me make useful visualizations for business and tech people that don't require hours (or days) of effort. It's the C4 model: c4model.com/. It's excellent in that it allows you to diagram a system in whole or part at various altitudes. It is structured enough to keep you from over-designing with enough flexibility to convey a variety of concepts.
I found it quite helpful in my current project and believe the team feels the same. I also used one of these diagrams to demonstrate a concept to business users with success. I highly recommend this model for those in a tech lead role.
A great question, an exercise in metacognition! So I would like to give an overview of a game in abstract terms:
Applying the model to itself I see that outliers are simplicity and implementability as well as maintainability
In typing this out I realized my brain follows something very similar the MVC structure, regardless of what I am building, but substituting the view for "things that concern users".
I start by either drawing or typing out the workflow, so what steps a user will go through to accomplish the task. A lot of times this looks like a bunch of IF/THEN/UNLESS/SELECT statements.
Then from there I will visualize the data models to support that workflow, usually drawing boxes for tables and lines for joins, thinking about what the application needs to know at each step of the workflow. This also sets me up for visualizing the "controllers" and logic that connects the client workflow to the data model.
Create diagram, I'm using grafcet diagram which is so much better than flowchart or UML (free figma kit grafcet.online)
I am getting to the point in my career, atleast in JavaScript, where I am starting to accurately predict the error before it happens which is an informed part of my development flow, it's undefined, but I knew that so let's do this. My head is chaos I suppose but I narrow it down to one of two potential outcomes, it's broke or it ain't.
There are many. When it comes to Git it's kind of a model of a 3D timeline made up of linkages (commits). As branches are made it's more of a graph of timelines each branch a Node containing a history of commits while following commits being linkages in that particular timeline.
When it comes to coding there are a few models one is very abstract and representational. Different parts become gears, switches, levers, etc... Helps me with debugging as I can associate more thing to more precise mechanisms and similar logic get these representations.
I also like to try and hold the data flow in my head and think about how it's moving 📦 to and from functions and the like.
There are more but these were hard enough to convey and that was still done poorly lmao
Enumerate requirements so I'm clear about the problem.
And draw pictures. Pen and paper. Have a laptop, but it's just easier sketching things out in a notebook. Translates nicely to a whiteboard.
Small prototypes when I want it a little more concrete or am uncertain about technical/framework implications.
I'm pretty sure I mentally model my code as a map.
When I'm reading through the code I'm think about where it will take me, the next land mark, the final destination.
If I take a wrong turn is that because I've read the map wrong or because the code is leading me up the garden path? So I backtrack and look for a familiar place to see if I can get on the straight and narrow.
When I'm writing code, I'm trying to leave good signposts for me when I follow in my footsteps.
Here is what happened recently to me: I completely underestimated the complexity of one requirement and started coding all the abstractions coming out of my mind, hoping this will resolve the task. Of course, after few hours I realized that I am producing a pile of crap which does not correspond to the requirement at all. Here is how I mitigated this:
Somewhere at this moment I reinvented the Test Driven Development, huh? LoL :)
This is an exceedingly cool question!
I don't think I really have one, overarching mental model. However, I definitely have a bunch of models I tend to reach for a lot as tools. I've tried to condense a couple of them here:
ASSEMBLY LINE and ORCHESTRATORS
This is a metaphor I tend to use quite a lot, particularly for data transformation. I've used it successfully with scripts, functions, and classes.
I try to structure code so that one top-level component orchestrates lower-level components, but doesn't do any actual work its self. This lets me separate the sequencing or wiring of things from the actual implementation.
For visualizations, I tend to think of my orchestrators as the controls on a puppet, and the parameters to that orchestrator being the strings.
AXIES OF SEPARATION
When trying to subdivide problems, I try to keep in mind that there are multiple axies it can be split on. Some examples are:
1) By system (database, ui, theme, etc.)
2) By use case
3) By business object
I usually end up visualizing this as some sort of geometric thing (a cube or some such thing that I slice up).
Thanks for the awesome thought experiment!
I find that an unreasonable number of useful mental models boil down to graphs (the graph theory kind and not the line plot kind) where nodes depict system components and edges depict interactions between those components. Alternatively, nodes may depict states and edges the transitions between states (a state machine.)
It's like playing Advent or Zork. I did once spend a week learning JCL on a mainframe and had nightmares of flying though multi-coloured COND double negatives.
I write notes as I go, sometimes they can be raw input for a blog post, usually they are a rambling record of wrong turns and dead ends. I outline, rather than mind map, though sometimes that helps too.
Remember the old erector set? That's one way I mentally visualize infrastructure.
It depends on what you are working with.
Some possible models:
dev.to/almenon/the-shape-of-the-co...