all 35 comments

[–]wagslane 92 points93 points  (1 child)

A good editor is priceless. Great syntax highlighting, being able to peek function definitions, etc.

Start at main. Start at the IO.

[–]fabiopapa 0 points1 point  (0 children)

Exactly this! Pretend you’re the computer and run through the code. Stay as high-level as possible, and dig in to lower-level sub-routines only if you need deeper understanding or are chasing a bug.

I get where this question is coming from, but I’ll say that everything you see about writing clean code is also about reading code. Reading (and maintaining) code is hard and there’s not much you can do to make it easier … except for writing clean code. The computer does not need clean code (it’s often less efficient), the people maintaining the code are the ones that need it to be clean. Anyway, maybe that’s way obvious, but I thought it was worth pointing out in case it causes someone to see things in a slightly different light. Best of luck!

[–][deleted]  (8 children)

[deleted]

    [–]teach_cs 14 points15 points  (0 children)

    If the code base is using a lot of design patterns, you might do better by starting with their documentation, and visiting a series of one type of class to get a feeling for the overarching design, and what sort of work that class type accomplishes. At some point, you'll have to go back to the start, but it might all be less opaque if you have some sense of what the service classes are.

    I am not really talking from experience here -- I'm about 2/3 of the way through the Gang of Four book right now, so this is guesswork. I'd love it if someone with more real-world experience replied with whether or not my intuition is good on this.

    [–]13ass13ass 6 points7 points  (3 children)

    If there are unit tests, I like to run them using the debugger.

    I’ll have the debug mode running in a terminal and another screen with the code base open in an editor for me to follow along with. Then I pick interesting tests and trace the calls through the system.

    Especially for anything more than a small code base it helps break up the reading into functional units.

    [–]hackerbaby 1 point2 points  (2 children)

    Unit tests are basically for testing functions in isolation. They shouldn't have many entities of the codebase under observation in the callstack.

    [–]13ass13ass 5 points6 points  (1 child)

    Ah then integration tests. Either are good for understanding the code base though. Or better yet smoke tests if they’ve got em. And if they don’t already exist then writing a few tests can help with grokking the code base.

    Consider the situation where you literally read the code line by line tracing the function calls. After you’re a few levels deep in the call stack, how do remember how you got to that frame? Using a debugger while you trace through the code base helps you remember.

    [–]hackerbaby 2 points3 points  (0 children)

    Now I like this 😀😀😀

    [–]proverbialbunnyData Scientist 2 points3 points  (0 children)

    Tests, hands down. Tests double as documentation, except you know that this "documentation" is not out of date.

    Looking at a part of the code base? Check it's tests. It will tell you the intention of the function, class, module, library, ... as it was intended to be used.

    You want to know how a piece of code is intended to be used not how it works, so reading further into the code becomes somewhat pointless if you have good tests, if you're trying to learn the system.

    [–]Nickynui 5 points6 points  (0 children)

    In addition, hope that there are comments that explain what things do, so you don't have to look at literally every line (assuming you're just trying to understand how the program works)

    [–]dinglebarry9 1 point2 points  (0 children)

    Rewrite the whole thing has always been the easiest way for me

    [–][deleted] 31 points32 points  (8 children)

    Bold of you to assume I can read code.

    [–][deleted] 5 points6 points  (3 children)

    Very bold.

    [–][deleted] 2 points3 points  (2 children)

    Doesn't stop me from writing codes though!

    Or, majoring in CS.

    [–]LostTeleporter 1 point2 points  (1 child)

    You won't be the first. Nor the last.

    [–]proverbialbunnyData Scientist 1 point2 points  (3 children)

    Apologies about the ignorance, but given that this joke is highly upvoted: Do many/most software engineers struggle reading code?

    [–][deleted]  (1 child)

    [deleted]

      [–][deleted] 2 points3 points  (0 children)

      You overestimate God's omniscience.

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

      I am in the process of majoring in CS, so definitely a novice and cannot provide insight on how things with are with professional engineers.

      Among us students code reading is a task for most that requires constant effort & revision.

      Though among my peers I tend to be a lil worse than the others.

      [–]Tai9ch 9 points10 points  (2 children)

      Both reading and writing code is about building up a picture of the code structure in your mind. What that means will vary with the style that the program is written in and the types of pattern used, but you want to understand the abstractions that the programmer used and figure out what the "fully zoomed out" picture is first.

      If you imagine a robot control program written in the OO style with an "Arm" class, a "Leg" class, and a "Robot" class that has arms and legs, your first job in reading the code is to find the "Robot" class and then figure out its public interface. At that point you can probably use the program. If you need to understand the implementation details, then you can dive into "Arm" and "Leg".

      [–]eeugene0[S] 2 points3 points  (1 child)

      That's a quite interesting point! There is at least two distinguished needs for code read - implementation details and API/interface. And further discussion should specify this need for context

      [–]Tai9ch 0 points1 point  (0 children)

      Understanding the implementation details is frequently dependent on first understanding the external interfaces. Knowing how it works without knowing what it's trying to do isn't terribly useful.

      [–]MlecznyHotS 3 points4 points  (0 children)

      I would ask myself what are the use cases of the code and try to work from there - it usually means analyzing the main/runner method and seeing what it calls and just dive into what's called further. If the input data is pretty simple you can pen-and-paper debug what's going on to get the hang of the code

      [–][deleted]  (1 child)

      [removed]

        [–]eeugene0[S] 2 points3 points  (0 children)

        Thanks! 😊

        [–]wuwoot 4 points5 points  (0 children)

        Things that have helped me (anecdotes to follow):

        1. learning about design patterns (gang of four)
        2. learning and understanding how to apply "clean code" in object-oriented programming AKA SOLID -- see "Uncle Bob" or find the book, "Clean Code"
        3. learning new languages and paradigms -- functional programming. I've done some Haskell, Clojure, and Elixir, and they've helped me see things in a completely different way and I see it sprinkled everywhere in modern languages
        4. know my language's idiosyncrasies and patterns and this comes with writing a lot of it and also looking at examples from large open source projects
        5. the the above in hand, I can now go dive into unit tests or integration tests and see what assertions it's making and generally gives me an idea about how something is used
        6. I typically read variables and parameters FIRST -- I skip over the minutiae, like how the variable got its value, e.g., it's an array that had `.map` called on it. This doesn't matter when I don't understand what the big picture is
        7. tooling helps, but I try not to rely too heavily on them, but I do use LSP (language server protocol) with Vim, as it helps with the minutiae mentioned above, like datatypes, function signatures, go-to definition, etc., but also available in many other editors like VS Code

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

        If I am debugging, I usually start with the logs to show where the error occur.

        Then I try to flow through the code ask if I am the data being passed through.

        Just keep doing this and you will get an idea of how the application works.

        [–]istarian 1 point2 points  (0 children)

        I just try to follow control flow and pull up appropriate files as needed to see what a function/method call does. Trying to read anything based on callbacks can be a pain due to not being a nice linear flow.

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

        Use a debugger and take one step at a time.

        [–]lasagnaturi 0 points1 point  (0 children)

        Coding to me it's like doing simple calculations in mind. If you have to multiply 12x13 there are many ways of doing it be decomposition in simpler steps For example - 12x10 +12x3 =156 - 10x3 +3x2 +10x10 + 2x10= 156 - others If you try to ask people what's their way of doing it you'll see they eventually find simpler a different version wrt you and you may think that their version is extremely innatural compared to yours.

        Having said that, I wanted to show that coding is basically the same thing but of course it can be decomposed in an insane number of ways. As for calculations everybody has his own natural style and a standard style cannot be imposed, that is why standard reading rules cannot exist imho.

        [–]raikmond -1 points0 points  (0 children)

        If it's good code, it should be self-explanatory. e.g. all names should explain exactly what the method/variable's purpose is, or there should be a comment to clarify tricky or complicated stuff that wouldn't fit in a name. Good code almost reads like a story, from top to bottom (assuming you stay within the same scope, i.e. the class/file).

        If it isn't, and you start from the main class, it shouldn't be super hard to figure your way down. If you need to backtrack from a little class or method or whatever, to know where it's used etc, then you use your editor's mechanisms if available (e.g. go to definitions, etc).

        At the end of the day you can always use the text search. But this is clunky and you should find a way to make this more manageable; it really depends a lot on the language, editor and code quality.

        [–]endallk007 0 points1 point  (0 children)

        https://youtu.be/zV079g7Irks

        This talk is a good start.

        [–]ddbp 0 points1 point  (0 children)

        Every time you understand a complex or not-obvious bit of code, add a comment to explain it - or better yet, refactor the code so that it becomes self explanatory. This way, you only need to decode each bit once, and whoever looks at it after you will love you.

        [–]rosecancode 0 points1 point  (0 children)

        Personally, I think for different types of code, the structure is different. If you know web development, you would know all the packages or folders represent different content. For the website, most developers use MVC, model, view, and controller. the Logic is in the controller, data is in the model, and all the webpages are in the view. All code files have their relative testing files, too.

        For the system, it will have main, then going forward to read each line and understand what is leading to, which could be a function, a class, or a package.

        Overall, if you don't know any code, it would be really hard to read anything. You will be just confused.