Live data from Hacker News

An Experiment on Code Structure

pboyd.io

41–50 of 62 posts

Re: An Experiment on Code Structure

#41

According to GitHub, the totals are: backendA: 11 files, 1 directory, 799 lines (676 sloc), 23.56KB backendB: 23 files, 5 directories, 1578 lines (1306 sloc), 42.26KB It's approximately twice as big for the same functionality, and I had to spend a lot more time "digging" through the second one to get an overall idea of how everything works. Jumping around between lots of tiny files is a big waste of time and overhead…

There’s not one perfect answer, the eye is in the beholder.

I personally have a harder time coming up to speed on things that don’t break things down into fairly small chunks. I have an easier time dealing with abstraction and would rather implementation details of what I’m looking at to be hidden until I drill in another level. IDEs make that latter part easy.

However I’ve come to realize that there’s not a one size fits all here. I’ve worked with people who are the exact opposite, and everything in between.

The best one can do is try to find the happiest medium for everyone involved and power on

Re: An Experiment on Code Structure

#42
post #34

I have a pet theory that there are two different ways that people think about and approach programs. Group 1 likes highly decomposed programs which they feel results have clearer code since hiding the details makes it easier to focus on the behavior. Group 2 likes to keep code together which they feel results in clearer code since the details of the implementation are readily apparent. I suspect that these groups may…

I am not so sure that pitting to tendencies against each other is such a good idea. The thing is that the good programming is somewhere in the middle of all of these things because if any of these tendencies goes too far we run into problems. I think we should all be able to belong to each of these three tribes depending on the circumstances.

I definitely agree! Going too far in one direction or the other is likely to both result in poorer code and to antagonize whichever side isn't compatible with that approach.

I think what I was trying to get at is that one of the reasons that teams often don't find balance is because the differences are dismissed as being just differences of opinion. I was trying to show that they are often much more significant than that since they can make it difficult for one side or the other to understand and work with the codebase.

Re: An Experiment on Code Structure

#43

I've become a big fan of not worrying about architecture until the rewrite. The first version is always an exploration of the problem domain, and treating it as that has always made my projects go quicker. This is going to trigger some people, so here's some caveats: - there's always a rewrite. Even with perfect architecture. Usually because nobody understands the problem domain until there's been an exploration of i…

"...until the rewrite"

Old school me understood we always create three versions: understand the problem, understand the solution, do it right.

I'm poorly adapted to today's world where projects don't mature past the first stage. Because of fashion, re-orgs, acquisitions, general purpose chaos.

Re: An Experiment on Code Structure

#44

Earlier quoted context omitted.

Multiple files also seems like a problem for IDEs to solve, not programmers.

That brings to mind an interesting idea for an IDE: having one big virtual file that you edit, which gets split into multiple physical files on disk (based on module/class/whatever). Although, thinking about it, there are some languages that would make such automatic restructuring rather difficult.

You've just described Leo - leoeditor.com - where you're effectively editing a gigantic single xml file hidden by a GUI. The structuring is only occasionally automatic - mostly manual. It has python available the way emacs has elisp.

Git conflict resolution of that single file is intractable, so I convert the representation into thousands of tiny files for git, which I reassemble into the xml for Leo.

Re: An Experiment on Code Structure

#45
post #40
post #6

Earlier quoted context omitted.

I’ve come to the conclusion that half or more of the rules we have about “clean” are about avoiding merge conflicts. Few things have been consistently disappointing to me as the inability of coworkers and myself to reason about merges correctly. There are three hard things in software and merges are #3. If anyone ever figures out how to make merges Just Work, then I expect a lot of pressure toward decomposition over…

An interesting point. I think it would be better to merge ASTs rather than text files that represent code. The annoying issues with merges are all about the text representation. When there's actually different logic changes in two different directions the merges cease to be annoying and start to require domain knowledge. Of course getting from this hand-wavey thought to working software is difficult. Perhaps we first…

I wish I kept better bookmarks. There was a project years ago where the diff tool had a tokenizer per language so that it could diff the code similarly to what you suggest. Obviously it did not take over the world.

But yes, that should help.

It always annoys me that I add a method and the diff tool says that I inserted code before the last curly bracket for the previous function, instead of balancing the brackets.

Re: An Experiment on Code Structure

#46
post #33

Earlier quoted context omitted.

It's actually the domain of build systems. Splitting code into as many independent files as possible gives the build system more data to work with, allowing it to compile more parts of the program in parallel only when necessary. If a file contains two functions and the developer changes one of them, both functions will be recompiled. If two files contain one function each, only the file with the changed function wil…

In C++, the experience is the opposite - a "unity build", where everything is #included into a single translation unit, tends to be faster: https://mesonbuild.com/Unity-builds.html http://onqtam.com/programming/2018-07-07-unity-builds/ https://buffered.io/posts/the-magic-of-unity-builds/

I have to clarify here a little bit and say that it is faster on one core. If you have multiple cores, having your translation unit count in the same order of magnitude as your core count will be faster. There is a lot more redundant work going on, but the parallelism can make up for it.

Re: An Experiment on Code Structure

#47
post #33

Earlier quoted context omitted.

It's actually the domain of build systems. Splitting code into as many independent files as possible gives the build system more data to work with, allowing it to compile more parts of the program in parallel only when necessary. If a file contains two functions and the developer changes one of them, both functions will be recompiled. If two files contain one function each, only the file with the changed function wil…

In C++, the experience is the opposite - a "unity build", where everything is #included into a single translation unit, tends to be faster: https://mesonbuild.com/Unity-builds.html http://onqtam.com/programming/2018-07-07-unity-builds/ https://buffered.io/posts/the-magic-of-unity-builds/

Unity builds are useful too but they have limitations. They are equivalent to full rebuilds and can't be done in parallel. The optimizations they enable can also be achieved via link time optimization. Language features that leverage file scope can interact badly with this type of build. They require a lot of memory since the compiler reads and processes the entire source code of the project and its dependencies.

Unity builds improve compilation times because the preprocessor and compiler is invoked only once. It is most useful in projects with lots of huge dependencies that require the inclusion of complex headers. The effect is less pronounced in simpler projects and they shouldn't be necessary at all in languages that have an actual module system instead of a preprocessor: Rust, Zig.

Re: An Experiment on Code Structure

#48
post #21

I wish for a future where we can have more than one concurrent view of the same code. Structure need not be derived from from mere files and newlines and a handful of semantic organizational elements (function, class, module). The current way of doing things forces us to make a compromise between prioritizing the forest over the trees, or vice versa. Programming languages are largely concerned with the trees' bark. B…

I love this. Currently working on a file storage system that gets away from folders, and that's hard because everyone has folders hard-wired into their brains because history. Functions shouldn't live in files, for a start. Files are an artefact of storing code in a file-based storage system, and have nothing to do with code architecture. Creating a code editor that stopped working with files and only worked with fun…

File systems aren't without their advantages. One huge advantage is that text files are extremely un-opinionated about how they're used. If my project exists as a tree of directories with text files inside, there are a ton of tools which can operate on them without any knowledge of my program or even programming language. I can open them in vim or my favorite IDE, dump them to the console with cat, manage versions with git and so on. Basically text files are one of the fundamental building blocks of *nix so having my project represented as files means I can leverage decades of tooling.

It's not to say that it couldn't work to have a program represented as some kind of a database or API, but that would imply much tighter binding between tools and their storage representation.

Re: An Experiment on Code Structure

#49
There is a huge amount of artisan streak to programming, vanity even.

Betting incredible amounts of effort and time, we tend to double-down as long as we can before considering alternatives.

There's also the tendency to choose our favourite hammer, it worked so well in the past!

Re: An Experiment on Code Structure

#50
post #20

These days, when I start a new project, I think of my code as a tree. I start at the trunk and write the branches. Each kind of state change needs to flow through the code in a consistent direction to avoid unexpected state mutations (like sap flows through a tree). Another developer should be able to understand all the main parts of my program just by looking at the main entry point/file (the trunk of the tree). Als…

> Also, no dependency injection should be used; all dependencies need to be listed explicitly and be trackable to its source file. Dependencies need to either be explicitly imported where they are used or passed down through the branches explicitly via method or constructor arguments. Isn't the latter precisely dependency injection? https://en.wikipedia.org/wiki/Dependency_injection#Construct...

Yep, I think GP meant DI frameworks.
Post reply on HN