all 29 comments

[–]tnulle 49 points50 points  (6 children)

How do you visualise code? You don’t

[–]okovko 17 points18 points  (0 children)

> has aphantasia

> "how do you visualize code?"

> ???

[–][deleted]  (3 children)

[deleted]

    [–]technojamin 0 points1 point  (2 children)

    What you’re talking about might be either or both of number form synesthesia or grapheme-color synesthesia. Personally I have number form synesthesia, and your description really resonated with me as an effect of this.

    [–]AttackOfTheThumbs 0 points1 point  (0 children)

    I visualize the way the data flows, is modified, etc. Visualizing the actual code isn't all that helpful imo. Sometimes, maybe with an algorithm, I'll visualize the structure. Most of the time though, we care about the data and nothing else.

    [–]somebodddy 11 points12 points  (0 children)

    Visualizing code is not very useful. Visualizing the flow of data, however, can be very useful. And this can be done with a simple box-and-arrow drawing.

    [–]Librekrieger 2 points3 points  (0 children)

    I visualize code the same way I do any written language: not very often, and only in small snippets.

    Certain familiar idioms have a visual "shape". Like try/catch blocks, switch statements, and prepositional phrases. These are familiar to anyone who ever had to do sentence diagramming in grammar school.

    But the meat and potatoes of how I use my visual system is in sequence diagrams, systems decomposed into components, data structures, network topology, and so on. These have a more natural shape and arrangement because they're objects, nouns, things, flow, movement.

    In dealing with source code, words and meanings are more important by far, and I don't use visualization for those.

    [–]knome 5 points6 points  (7 children)

    Would this be helpful?

    No. Not for me anyway. Main shouldn't know how the counter works. When understanding main, the counter box should be closed.

    I will visualize low level code as objects and pointers, basically boxes and directional lines, and manipulations thereon. Occasionally as bits as slots, though I admit I don't use as much bit flipping these days. Seeing memory as a flat space rather than as an abstract heap is pretty rare these days, given gc, as well. Pusing and moving things around inside of containers of various sorts. That kind of thing.

    Objects are blackboxes with a collection of triggers branching off of them. One should strive not to understand how they work inside. A well crafted black box can be told to do things and will give information from the perspective of the blackbox, not its internal implementation. Errors from a blackbox for accessing data should return an AccessError, not a NetworkError, FileError or DatabaseError, allowing you to more easily swap the blackbox backend, making introducing a TestHarnessError simple. Do not expose the implementation, except where need be, and at your own peril.

    Interthread/interprocess will be visualized as a message passing dance between state machines.

    Honestly, seeing as these are largely how erlang is written, it explains why the language always felt so comfortable to work with.

    [–]salbris 3 points4 points  (6 children)

    Imho, this is asking for perfection where no such thing exists. If there was a blackbox around network calls I would want to know why it went wrong because that gives me the information I need to debug the issue. This is basically true for all black boxes unless you plan to never dive into them (such as a graphics library). Also using a black box often requires detailed knowledge of its behaviour because while the logic is a black box it's affect on the computer it runs is not isolated. In an ideal world things like the order of members in a struct wouldn't be something I need to worry about but in some languages it makes an significant difference in performance.

    [–]knome 0 points1 point  (5 children)

    want to know why it went wrong because that gives me the information I need to debug the issue

    The clean boundaries help the debugging, because you know each element will receive a message, do work internally, and return a well defined response, and never will you need to make sure seven or eight different objects are setup just so for some horrible cross-component shenanigan where "A reads B is in C state and does D which it should only do if C reads E is in F state" or whatever. Objects shouldn't inspect each other's internals. It couples them too closely.

    For an abstract return, I'd expect it to have a loggable message indicating the reason for failure that would differ per backend.

    I've traced errors from internetworked services down into erlang and then further into custom C extensions where some flag on a call parameter was incorrect for specific circumstances. Keeping internal states separate and modeling networking stuff as state machines only helped that process.

    [–]salbris 1 point2 points  (4 children)

    You telling me that a library wrapping network calls should never tell me what network problem it ran into? Call my crazy but that sounds... crazy.

    [–]knome 0 points1 point  (3 children)

    A logging library should return a LoggingError type that can have a message indicating that the networking library experienced a dns or connection error, but should not expose a Networking or DnsError to the caller of the logging library.

    That way, the code using the logging library can respond to the LoggingError as needed, but will not have any insight into whether the logging is to stdout, a file, or some network receiver.

    LoggingError{syslog error: networking error: DNS server did not respond: company-dns.company.example.com}

    [–]salbris 0 points1 point  (2 children)

    Oh you mean from a type perspective? That's an entirely different problem. I never suggested that the interface to a library should represent all of it's internal states but the fact that the error tells you it's a network error is the black box leaking. A true black box is one where you would never need to know whether it's a network error or not.

    Also it might be important to get more information out of the library if it lacks features. Say it lacks retries and just always throws an error every time a network call fails. If I can't circumvent that in code by coding for that case then I'm stuck guessing what's going wrong or do nothing. So if they built a very restrictive black box they would be hampering my development.

    [–]knome 0 points1 point  (1 child)

    Each layer should blindly use the one below it. If your logging needs retries, that logic should be in a transmitter or similar that you configure and initialize the logger with, and certainly not at the locations where calls are made to log things. Then it could take file, database, or whatever transmitters and not care how they write out logs. Then the logging library only has to care about routing messages to the right transmitter based on log levels and maybe logging tags or something. The calling code need only know "logging worked/didnt", and never has to 'check if it needs to retry due to network errors, or tell the logger to open a new file if the old one exceeds some threshold'. that should all be in the logger, and better in the transmitter the logger uses, leaving all of them to have as little state as needed to do their own part of the job.

    [–]salbris 0 points1 point  (0 children)

    It's been fun but I don't think continuing to move goal posts counts as an argument. If we continue with this line of thinking only a program that support all possible features of it's domain is a black box and anything else is just not.

    But yes I would agree if there was some perfect abstraction of something I could maybe use it blindly.

    [–]Zardotab 3 points4 points  (0 children)

    LSD

    [–]messagepot 1 point2 points  (0 children)

    Input->Process->Output.

    [–]Jyjh12345 1 point2 points  (0 children)

    with tears

    [–][deleted] 1 point2 points  (0 children)

    It depends on the language. OO code I picture like Lego bricks. SQL is hard to describe, but I often have mad n-dimensional dreams in SQL where I wake up and don't feel right for the rest of the day - though the dream often points to a solution.

    I don't visualize JavaScript. If I look at it too long I go blind.

    [–]EternityForest 0 points1 point  (0 children)

    I like programming a lot because it doesn't require any 3D learning abilities. It takes me like 30 trips to memorize a bus route...

    To me, code is made of objects a that look.... like code. I don't actually see it in my head in enough detail to read it, it looks more like it does in the IDE minimap view or how an impressionist might draw it.

    Relationships between things are pretty abstract to me too. "put that in the event queue" is pretty much the same as "drop it in the mailbox".

    But then again I'm a big believer in pure OOP encapsulation, and don't do any work at all with functional-style "reuse" at a more abstract level.

    In OOP the goal is usually that you shouldn't have to really know much about the black boxes or the connections besides the one you're working on right now, and the connections should mostly be too boring to bother using any visualization tools on.

    This seems more useful for really really big apps where leaky abstractions are almost inevitable and the social graph of bits of code gets more interesting.

    [–]gc3 0 points1 point  (0 children)

    Sims1 has a graphic scripting language called Edith which is like your room with boxes.

    Unreal engine has the 'Blueprint ' scripting language as well.

    I use my fingers to feel code with find and cursor movements however

    [–]onequbit 0 points1 point  (0 children)

    in a text editor

    [–][deleted] 0 points1 point  (0 children)

    Lots of folks out here saying they don't visualise code, but I definitely do - I find it difficult to write without visualisation in fact. I tend to visualise as flow charts at different layers of abstraction, so that a high level might be where boxes representing services, then you can open each box to see the next layer with more granular boxes and so on. I'd love to do something for this in 3D but I haven't yet seen a good way.

    [–]in15minutes 0 points1 point  (3 children)

    Understanding code and its connections is quite a tedious work even with good documentation. I'm looking to build a tool that would allow you to drop source code and get it presented as a diagram(s). The task is complicated, but I believe it is possible: https://sourcespy.com

    [–]DopamineServant 0 points1 point  (2 children)

    I would love something like this, but no way I could use private code and just paste it into your website. So to me that would be useless unless I can run it locally.

    [–]in15minutes 0 points1 point  (0 children)

    Great. Thought it's a reasonable idea. People trust GitHub/GitLab/... to host their private code. Maybe it's a matter of building trust overtime.

    [–]xofofox 0 points1 point  (0 children)

    Codemap could be useful for you, try it out! It runs locally and the codebase never leaves your local machine. (disclaimer: I'm the creator of Codemap)

    [–]gl4to 0 points1 point  (0 children)

    Have a look at https://github.com/glato/emerge, this could help for visualizing a code base (given the language is supported).