|
| suzzer99 wrote:
| I must be weird because I love YAML. I love the brevity of no
| closing brackets and the finality of the indentation being the
| code, rather than just window dressing that can get out of whack.
| prohobo wrote:
| Competent*
| googlryas wrote:
| I've often thought of this as "developer empathy" when I was
| working at Amazon. Generally regarding people who create APIs for
| other developers to use. The idea being that you can make your
| API simple or complex, and most developers tend to make their API
| complex, because they think their system is really powerful and
| cool and want to expose all the power to end users. But, you need
| to remember that your users aren't just using your API. They are
| using maybe 100 other ones as well. And there is no way for a
| person to learn the ins and outs of all 101 complex APIs. Add to
| this the fact that the more complexity you expose, the more
| unintentionally coupled your API becomes to your implementation
| (generally). So, make your APIs simple, and provide backdoors if
| you really want to expose complexity.
|
| I will say, this did not get me promoted at Amazon.
| jackblemming wrote:
| That just sounds like the designer didn't layer the API
| properly. A good API has a sensible top level that does all the
| common use cases, but also allows access to the lower level
| stuff for power users.
| krawczstef wrote:
| Yes! As one of the creators of
| https://github.com/stitchfix/hamilton this was one of the aims.
| Simplifying the cognitive burden for those developing and
| managing data transforms over the course of years, and in
| particular for ones they didn't write!
|
| For example in Hamilton -- we force people to write "declarative
| functions" which then are stitched together to create a dataflow.
|
| E.g. example function -- my guess is that you can read and
| understand/guess what it does very easily. # in
| client_features.py
|
| @tag(owner='Data-Science', pii='False')
|
| @check_output(data_type=np.float64, range=(-5.0, 5.0),
| allow_nans=False)
|
| def height_zero_mean_unit_variance(height_zero_mean: pd.Series,
| height_std_dev: pd.Series) -> pd.Series: """Zero mean
| unit variance value of height""" return
| height_zero_mean / height_std_dev
|
| To use `height_zero_mean_unit_variance` somewhere else, you'd
| then find it as a parameter to some other function, and that's
| the basic gist of how you'd develop a dataflow. To then execute
| the dataflow, you'd then in a separate file, decoupled from your
| transform logic, write some code to (1) create the DAG, and then
| (2) request what you want executed from it.
|
| In terms of reducing cognitive burden for maintainers, by forcing
| things into a function there's all these nice properties to be
| had for maintenance:
|
| - unit testing is always possible
|
| - integration testing is super easy, since you can add code, and
| then _only_ test that path without having to run your entire
| transform workflow.
|
| - documentation has a natural place & and we can build a DAG
| visualizing the dataflow that you're looking at
|
| - debugging is methodical since it's straightforward to map an
| output to a function, check the logic there, and then
| methodically traverse its dependencies because they are declared.
|
| - you can wrap functions/inject things at run time easily
| baby wrote:
| People write code for computers, but they should also write code
| for humans. Humans have different parsers and the evolution of
| the code is dictated by how quickly and efficiently can these
| human parse the code.
| karmakaze wrote:
| I write code for humans, first of all me. Ensuring correctness,
| getting the syntax right, and following style conventions, etc
| is what follows. It's much easier for a human to verify the
| logic if it's easy to read and comprehend. Good notes in a
| pull-request is also handy and easy to find with a git-blame
| and commit hash lookup on GitHub.
| luciusdomitius wrote:
| Programming code is for humans. Machine code is for machines.
| The compiler translates from human to machine.
| troelsSteegin wrote:
| Would GOMS [0] be a useful framework for thinking about cognitive
| load in programming? GOMS is a framework for analyzing user
| workload in system interaction. Bad or gnarly code creates a much
| more complex interface for the programmer. A quick look did not
| surface a reference here, but I'd look further at work by David
| Kieras [1].
|
| [0] https://en.wikipedia.org/wiki/GOMS [1]
| https://www.researchgate.net/profile/David-Kieras
| AceJohnny2 wrote:
| Offtopic:
|
| I'm saddened to see YAML get a bad rap for effectively being
| shoehorned to fit a task that it's just bad at.
|
| In my experience, YAML is a great format for legibly declaring a
| dict/array structure, with added benefits over JSON like
| anchors/references (effectively pointers, which thus allow it to
| describe a graph), comments, and overloads (great for defaults!).
|
| But YAML has no facilities for conditionals, loops, or any logic.
| So these get tacked-on, ad-hoc, by systems that need them, and
| that pulls YAML towards Greenspun's Tenth Rule ( _" Any
| sufficiently complicated [system] contains an ad hoc, informally-
| specified, bug-ridden, slow implementation of half of Common
| Lisp"_)
|
| I'm glad better languages like Dhall exist for the problem-space
| that YAML is just not designed for.
| giantg2 wrote:
| Multiple levels of abstraction kills me, at least without
| adequate documentation. Conceptually, it's veey easy to grasp,
| but in code it becomes a mess making jumps through multiple
| unfamiliar files in a large code base. Essentially, you end up
| having to hold all the pertinent information on that code in your
| head, which largely defeats some of the purposes of breaking them
| into multiple files.
| baby wrote:
| You'd probably say the same if no abstractions were there. It's
| a trade off. Don't necessarily abstract something, but do it if
| it makes everything else better and more maintainable and more
| secure. Probably a good philosophy is to never start with
| abstraction and leave that to refactors.
| giantg2 wrote:
| Yeah, we seem to have gotten better at this by using noSQL
| databases with one big JSON object for each item instead of
| relational based on OOP objects.
| rileymat2 wrote:
| I find that this type of code is much easier to debug in a
| debugger, while harder to debug looking at source code.
|
| When in a debugger, I can throw a breakpoint in, inspect inputs
| and outputs, if they are what I expect, there is (generally[1])
| no reason to dive into those other files.
|
| When reading the code from source outside of a debugger, as a
| new person to the code base, I agree with you and the exact
| problem you are describing.
|
| [1] Reasonably written code without a bunch of hidden global
| state.
| keyle wrote:
| One of the goals of any code base of significant size should be
| to reduce the cognitive load (not lines of code per function).
|
| Assume the developer working here just had a 45 mins sync, has a
| meaningless repeat meeting about vapourware in 10 mins and a 2
| hours town hall meeting after lunch... and still have to deliver
| that mess of a requirement you made him promise to deliver before
| any of these interruptions were even on his calendar!
|
| - Always aim for declarative programming (abstract out the how it
| does it),
|
| - limit the depth of the function calls (rabbit hole
| developers...),
|
| - separate business logic from framework internals and
|
| - choose composition over inheritance.
|
| - Also avoid traits and mixins (run from the dark magic)
|
| - don't over document the language or framework, only the eyebrow
| raising lines, the performance sensitive stuff and the context
| surrounding the file if it isn't obvious.
|
| - name stuff to be easily grepable
|
| Easy rules to go by, (there are probably more), they can make or
| break your ability to work, so that you can get interrupted 12
| times an hour and still commit work.
|
| I don't find these in books, just decades of sweating and pulling
| my hair "why does it have to be so hard!?" I have met plenty of
| senior devs who naturally do the same thing now.
|
| The code size fallacy is a prime example of the wrong way to look
| at it. Plenty of extremely large code base in C++ are far more
| manageable than small JavaScript apps.
|
| Mixing boilerplate framework junk with your intellectual property
| algorithms "what makes your software yours" is a sure way to
| hinder productivity in the long term.
|
| You write code 3-4 times. You read it 365 times a year.
|
| One last thing I recommend if you deal with a lot of
| interruptions and maybe multiple products, various code bases...
| keep a // @next reintegrate with X
|
| The @next comment 'marker' is a great way to mark exactly which
| line of which file you were at before you left this project, for
| a meeting, for lunch, for the day, etc. And it allows you jump
| back into context by searching for @next and go. Also since it's
| visual and located, your brain has a much better time remembering
| the context, since we're good with places and visual landmarks.
|
| It's far more efficient than roughly remembering what I was
| doing, looking at the last commit, scrolling endlessly through
| open files. Don't commit @next though :)
| [deleted]
| magicalhippo wrote:
| Nice list. I would add, near the top, "don't be clever unless
| it makes the code significantly easier to read for others".
|
| For example, if your code involves a lot of linear algebra,
| then operator overloading the sensible operators is probably a
| good thing. But don't use operator overloading just to save
| some keystrokes.
|
| Over-abstraction is another such case. Try to avoid adding
| abstraction layers until you need them.
|
| I'd also add "make the code as self-documenting as possible".
| That means being verbose at the right times, such as writing
| meaningful identifier names.
|
| And of course "avoid global variables". I've seen people use
| singletons with a read/write member, which is as much a global
| variable as any other.
| ABS wrote:
| it's going to take quite some time to read it all since it's long
| and deserves the time but since it's soliciting early feedback
| here it is: research and quote all the works done over the last
| 10 or so years by others in this space!!
|
| The topic of cognitive load in software development is far from
| rarely considered and in fact it's been somewhat "popular" for
| several years depending on what communities and circles you
| participate it on- and off-line.
|
| I'm surprised not to find any mentions to things like:
|
| - the Team Topologies book by Skelton and Pais, published in 2019
| where they cover the topic. Particularly of note here is the fact
| that Skelton has a Computer Science BSc and a Neuroscience MSc
|
| - the many, many, many articles, posts, discussions and
| conference sessions on congnitive load from the same authors and
| connected people in subsequent years (I'd say 2021 was a
| particularly rich year for the topic)
|
| - Dan North sessions, articles and posts from around 2013/2014 in
| which he talks about code that fits in your head but no more,
| referencing James Lewis original... insight. E.g. his GOTO 2014
| session "Kicking the Complexity Habit"
| https://www.youtube.com/watch?v=XqgwHXsQA1g&t=510s a quick search
| returns references to it even in articles from 2020
| https://martinfowler.com/articles/class-too-large.html
|
| - Rich Hickey's famous 2011 Simple Made Easy talk
| https://www.infoq.com/presentations/Simple-Made-Easy/
| Lwepz wrote:
| >research and quote all the works done over the last 10 years
| or so by researchers in this space!!
|
| I totally understand your point and appreciate you linking
| those resources, however I think it's important to remember
| that the author's post is from a personal blog, not from a
| scientific journal or arxiv.
|
| Perhaps OP would've never posted this if he felt that his
| "contribution" wasn't novel enough. Additionally, there's a
| chance that the wording and tone the author used might speak to
| people who found the articles you mentioned opaque(and vice
| versa, obviously).
|
| If the author, feeling the urge to write something up, had
| looked very hard for "prior work" instead of following the flow
| of their insights gained through experience, perhaps they
| would've felt compelled to use the same vocabulary as the
| source, which has its pros(forwarding instead of reinventing
| knowledge) and cons(propagating opaque terms, self censoring
| because of a feeling of incompetence in the face of the
| almighty researchers).
|
| That's one of the great things about blog posts: to be able to
| write freely without being blamed for incompleteness or prior
| art omission.
|
| On a different note, I think this may also highlight the fact
| that the prior work you mentioned isn't easy enough to find.
| Perhaps knowledge isn't circulating well enough outside of
| particular circles.
| UweSchmidt wrote:
| One measure for code quality should be the effort to make a minor
| change to code, or to fix a simple, common bug.
|
| Can a developer who is familiar with the code, effortless make a
| change in an area where change was expected at the beginning?
|
| Assuming a typical, minor bug that turns out to originate from
| the usual suspect places in the code (database query, logical
| error, incomplete implementation of a requirement, off-by-
| one/calculation error). Is it usually easy to narrow things down,
| and to spot the error?
|
| That means the lead architect should regularly try implementing
| minor features or fix minor bugs and/or pair up with colleagues
| who do, and draw conclusions about the code accordingly.
| hu3 wrote:
| That's a good one.
|
| Another measure I use for code quality is: how afraid am I of
| breaking something when I make changes? This is where typing
| and tests shine.
| wtetzner wrote:
| Typing and tests definitely help, but nothing works better
| than having well-factored, decoupled code, so a change in one
| place doesn't impact the rest of the code base in unexpected
| ways. Unfortunately I don't know of a good way to do that
| outside of experience + vigilance.
| baby wrote:
| Good abstractions + asserts + minimal assumptions
| everywhere in the code (also called refactoring-resistant
| code)
| bcrosby95 wrote:
| Unexpected is an interesting word. This probably means
| consistency is important, because expected in one codebase
| could be unexpected in another.
| [deleted]
| mikewarot wrote:
| I tend to think of this as an _impedance matching_ [1] (in the EE
| sense) problem. The best frameworks match the way we think about
| problems once we've gotten used to them. There has to be some
| give on the part of the programmer, because of Godel's
| incompleteness theorems.[2]
|
| I whole heartedly agree that we have to minimize extra steps when
| reviewing code, but you can only push so much of that burden back
| through space-time to the green field programmer.
|
| For instance, in Pascal, you have to declare everything first.
| I'm used to that, so it matches my expectations. However, it also
| sucks because if you're looking in the middle of code the
| declarations aren't proximal to the first time they're used.
| There's an expectation that all the code will be read, which was
| fine in the academic world which gave birth to Pascal, but not in
| the world of million line systems.
|
| There are tradeoffs that will take decades to get right, simply
| because we need to have time to gain enough perspective to adjust
| things collectively, as a profession.
|
| [Edit -- Tweak link format per suggestions below]
|
| [1] - https://en.wikipedia.org/wiki/Impedance_matching
|
| [2] -
| https://en.wikipedia.org/wiki/G%C3%B6del%27s_incompleteness_...
|
| [3] - https://en.wikipedia.org/wiki/Off-by-one_error
| Jtsummers wrote:
| Is there a reason you deliberately make it hard for people to
| follow the links you put in your comments?
| mikewarot wrote:
| I number them, and space them out to make it easy to select
| and copy... there's no way to inline hyperlinks here that I'm
| aware of.
|
| Option #1 -- formatted as a code block [1] -
| https://en.wikipedia.org/wiki/Impedance_matching [2] -
| https://en.wikipedia.org/wiki/G%C3%B6del%27s_incompleteness_t
| heorems [3] - https://en.wikipedia.org/wiki/Off-by-
| one_error
|
| Option 2 -- jumble of links
|
| [1] - https://en.wikipedia.org/wiki/Impedance_matching [2] -
| https://en.wikipedia.org/wiki/G%C3%B6del%27s_incompleteness_.
| .. [3] - https://en.wikipedia.org/wiki/Off-by-one_error
|
| -
|
| Option 3 -- Extra line breaks everywhere
|
| [1] - https://en.wikipedia.org/wiki/Impedance_matching
|
| [2] - https://en.wikipedia.org/wiki/G%C3%B6del%27s_incomplete
| ness_...
|
| [3] - https://en.wikipedia.org/wiki/Off-by-one_error
|
| -
|
| None of those really seems right
|
| [Edit] Sorry, I didn't know about the issues on mobile. it
| definitely wasn't trying to make it worse on purpose. I added
| the off by one link to make the examples long enough
|
| The 2 biggest problems in computing... Naming things, Cache
| Invalidation, and off by 1 errors.
| layer8 wrote:
| I'd also suggest to leave out the hyphens, they are just
| visual noise.
| Jtsummers wrote:
| No, but if you didn't put the white space at the front of
| the line they'd be, you know, _links_. So people don 't
| have to copy/paste them. Which is sort of the point of
| hypertext.
|
| EDIT: Most of the parent comment wasn't there when I wrote
| my initial reply.
|
| Of the three options, the third is the best of a bad
| situation since we don't get to cleanly inline links like
| on Reddit and other places. The first is just
| inconsiderate, especially to mobile users. The second is,
| as you noted, a mess especially when there are multiple
| links. The third lets you keep your original intent
| (clearly listing each link) while letting them still
| function as links. Which is better than the first option
| because it's not disrespectful of other people even if it
| does add some vertical whitespace.
| wtetzner wrote:
| If you don't put them in a code block, the URLs are
| automatically linkified by HN.
| OneLessThing wrote:
| If we improve our programming languages and practices to make
| code bases more easily understood we will simply increase the
| scope of what the projects attempt to solve, not reduce their
| complexity. While this is a good for software it still means
| we're going to be moaning about working on complex software.
|
| It's like how the increased economic productivity due to
| technology has not made the work week shorter.
| luciusdomitius wrote:
| This is insanely good! I always thought I am the only person in
| the world taking that into account when designing/coding
| something.
| z9znz wrote:
| > We ask "How long will it take?"
|
| That is the first problem. We should be asking several questions,
| and the value of their answers would be weighted against business
| goals.
|
| How long will it take?
|
| How will it affect future development (pace).
|
| How will it affect the forced total rewrite date (a broader view
| of the previous question).
|
| And my favorite, how difficult will it affect provability of
| system behavior? This point is greatly affected by frameworks
| which impose their own conventions (which change over time).
| Lwepz wrote:
| Splendid article.
|
| I was thinking that perhaps walking the readers of our code
| through our architectural decisions(and not just through what our
| code does) is a good way to lessen their cognitive load. This
| helps identify decisions that have been taken to look smart or
| because the foie-gras the author ate on that day went down really
| well with the Chardonnay and made them feel extra stylish.
|
| This also helps us understand how well we know the tools we're
| using versus how much we do simply through pattern repetition.
| CraigJPerry wrote:
| This is an enjoyable read. The topic of abstraction needs to be
| explored more here. I wonder if the author would agree that In
| practice almost all abstractions can be made to leak. Given that,
| then even experienced developers who understand how to avoid
| mixing different layers of abstraction will seldom succeed in
| creating abstractions without leaks. If an abstraction leaks,
| it's not germane, it's incidental complexity.
|
| This applies to blueprints as equally as it does to
| implementations. The author notes the caveat in soundness of
| blueprints - not something a common developer can do much about -
| but if the developer designs blueprints with unintended
| behaviours - for example the author's recursive let example -
| then they're being very generous with the helpfulness of
| blueprints since they are no silver bullet to avoid shooting
| yourself in the foot.
|
| The common case in software development is not a PLT enthusiast.
| Blueprints are just another way you can shoot yourself in the
| foot if you hold the tool wrongly. And the common case is not to
| understand the tool much more than at a fairly superficial level,
| so mishandling is all but assured.
|
| This means pragmatically, there's no substitute for an acceptable
| level of testing in a project.
| he0001 wrote:
| My pet peeve with this, is that people write code that doesn't
| reflect the problem. A messy problem should have a messy solution
| as that would reflect the problem. As soon you start to write
| code that's either for the sake of something else, clean code
| etc, you deviate from what you are trying to solve. That creates
| a solution which hard to follow, as the problem is abstract and
| others may be able to interpret that. But then if you look at
| some code that does something entirely different, due to language
| constructs, framework or some diligent programmer trying to write
| good looking code but has nothing to do with the problem. That
| creates cognitive load as you need to not just only understand
| and solve original problem and changes, you need to understand
| the actual code too.
| michaelwww wrote:
| > A messy problem should have a messy solution as that would
| reflect the problem
|
| I've never heard this expressed before and it goes against my
| experience. My entire goal is to find a simple solution to a
| messy problem. I can think of a lot of simple solutions to
| messy problems. If programming required me to come up with
| messy solutions to messy problems I wouldn't want to do it.
| Most programmers like that "a-ha" moment of a discovering a
| simple and elegant solution to a messy problem.
| Aperocky wrote:
| Exactly, solution to a messy problem is 3 simple solutions
| working together, not one messy solution.
| michaelwww wrote:
| I'm a bit old so when I was growing up in the 60's a
| cartoonist named Rube Goldberg made his living by amusing
| people with overly-complicated solutions to simple
| problems. I don't hear him mentioned anymore so I'll
| mention him now
|
| https://en.wikipedia.org/wiki/Rube_Goldberg_machine
| atoav wrote:
| I once wrote an extremely general and elegant piece of code for
| an extremely messy problem (some obscure CSV from a source
| system I cannot influence with a ton of inconsistencies and
| mistakes that I have to straighten out automatically).
|
| I started out with straightforward and somewhat messy code, but
| after adjusting that 3 times, I ended up writing something that
| is more or less a toolset to deal with the problems that data
| had. The code of the tools is convoluted, but when I have to
| adjust some things every now and then I just use the tools I
| built anyways so who cares.
|
| Abstraction in programming should be seen like certain devices,
| helpers etc. someone would make use of in woodworking. Of
| course it costs you some time to built them, but it can make
| your life a lot easier, because ot makes results more
| consistent and testable.
| layer8 wrote:
| Yes, I would formulate this as the distance between the mental
| model of the functionality being implemented and the structure
| of the code. The interesting question is how to design
| programming languages, libraries and tooling so that gap
| remains small.
| wikitopian wrote:
| Alan Kay is a very nice and bright guy and I don't want to hurt
| his feelings.
|
| But this is a perfectly soluble problem and it is entirely and
| exclusively Alan's fault that everybody stampeded in the wrong
| direction to our current situation.
___________________________________________________________________
(page generated 2022-08-31 23:00 UTC) |