Live data from Hacker News

The Design of Software is a Thing Apart

pathsensitive.com

81–90 of 124 posts

Re: The Design of Software is a Thing Apart

#81
post #5

Peter Naur's "Programming as Theory Building" also addresses this topic of a "theory" which is built in tandem with a piece of software, in the minds of the programmers building it, without actually being a part of the software itself. Definitely worth a read: http://pages.cs.wisc.edu/~remzi/Naur.pdf

> I shall use the word programming to denote the whole activity of design and implementation of programmed solutions.

Isn't this definition circular, using "programmed" in defining "programming"?

Re: The Design of Software is a Thing Apart

#82
post #61
post #8

> Those who speak of “self-documenting code” are missing something big: the purpose of documentation is not just to describe how the system works today, but also how it will work in the future and across many versions. And so it’s equally important what’s not documented. Documentation also (can) tell you why the code is a certain way. The code itself can only answer "what" and "how" questions. The simplest case to sh…

> If you don't explain in documentation (e.g. comments) why you went the more complicated route, someone might come along and "simplify" things to incorrectness, and the best case is they'll rediscover what you already knew in the first place, and fix their own mistake, wasting time in the process. I've done this to myself . It sucks. Revisiting years old code is often like reading something someone else entirely wro…

I have once or twice embarked on what I was sure was a well-thought-out, solid refactoring job, only to find that after a long process of cleaning, pulling out common code, and adding the special-case logic, I had refactored myself in a giant circle.

Every step of the process seemed like a local improvement, and yet I ended up where I started. It was like the programming equivalent of the Escher staircase: https://i.ytimg.com/vi/UCtTbdWdyOs/hqdefault.jpg.

Re: The Design of Software is a Thing Apart

#83

Earlier quoted context omitted.

Old and somewhat contrived example, but the first thing to pop into my head is the famous fast inverse square root function. float FastInvSqrt(float x) { float xhalf = 0.5f * x; int i = *(int*)&x; // evil floating point bit level hacking i = 0x5f3759df - (i >> 1); // what the fuck? x = *(float*)&i; x = x*(1.5f-(xhalf*x*x)); return x; } I can't think of a way to write a test that sufficiently explains "gets within a c…

Write a property based test, ie generate a bunch of random inputs, then assert that all of them are within some (loose) margin of error.

This doesn't satisfy the time constraint though.

    return 1.0f / sqrt(x)
Passes a property based test but now your game doesn't actually run because it's much too slow of an operation on hardware at that time.

You can also test execution time too, but that's finicky and doesn't help explain how to fix it if you break that test (if there's no accompanying documentation).

Re: The Design of Software is a Thing Apart

#84
post #39

Earlier quoted context omitted.

> Some might claim unit tests will solve this Yes. Tests will solve this. Your point is perfect for tests. If another experienced coder cannot comprehend from the tests why something is wrong, then improve the tests. Use any mix of literate programming, semantic names, domain driven design, test doubles, custom matchers, dependency injections, and the like. If you can point to a specific example of your statement, i.…

Old and somewhat contrived example, but the first thing to pop into my head is the famous fast inverse square root function. float FastInvSqrt(float x) { float xhalf = 0.5f * x; int i = *(int*)&x; // evil floating point bit level hacking i = 0x5f3759df - (i >> 1); // what the fuck? x = *(float*)&i; x = x*(1.5f-(xhalf*x*x)); return x; } I can't think of a way to write a test that sufficiently explains "gets within a c…

For example, here's one way to write a test that sufficiently explains "gets within a certain error margin of the correct answer yet is much much faster than the naive way".

Using Ruby and its built-in minitest gem:

1. Write a test that does minitest assert_in_epsilon(x,y,e)

2. Write a minitest benchmark test that compares the speed of the fast function with the speed of the naive function.

Notice the big advantage for long term projects: if the hack ever ceases to work then you'll know immediately. This actually happens in practice, such as math hacks that use 32-bit bit shifts that started failing when chip architecture got wider.

> no one on the Quake 3 team can remember who wrote it

Exactly. We have the code file, but not any documentation separate from the code, such as notes, plans, attempts, reasoning, etc.

Re: The Design of Software is a Thing Apart

#85
post #62
post #39

Earlier quoted context omitted.

> Some might claim unit tests will solve this Yes. Tests will solve this. Your point is perfect for tests. If another experienced coder cannot comprehend from the tests why something is wrong, then improve the tests. Use any mix of literate programming, semantic names, domain driven design, test doubles, custom matchers, dependency injections, and the like. If you can point to a specific example of your statement, i.…

Do you think this still holds true if you name all your tests in the format test1, test2 ... testN? If not, then you're in the realm of documentation, not tests, and the descriptive names (which is a form of metadata, just as comments are) of the tests are what is communicating these special cases, and not the test content itself. Combining the two is good, but let's not act like the tests themselves immediately solv…

My opinion is that test names, function names, variable names, constant names, high level languages, literate programming, and well written commit messages, all help code to be understandable; I'm fully in favor of all using all these in source code and also in commit messages.

My experience is that documentation is generally a shorthand word that means non-runnable files that do not automatically get compared to the application source code as it changes.

Of course there are some kinds of blurred lines among tests and documentation, such as Cucumber, Rational, UML, etc.; but that's not what the parent comment was talking about when they described the function with a naive/buggy implementation vs. an enhanced implementation that handles a subtle case.

> but let's not act like the tests themselves immediately solve the problem

I'm saying that yes, the tests do immediately solve the problem in the parent comment's question: a test for the "subtle" case in the parent comment immediately solves the problem of "how do we ensure that a future programmer doesn't write a simplified naive implementation that fails on this subtle case?"

Re: The Design of Software is a Thing Apart

#87

Earlier quoted context omitted.

In this strawman example, perhaps. However, code is usually surrounded by other code. So you could have the 'A' in multiple places. By using an explicit identifier you are protecting yourself against typos (depending on the language, it could be a compile-time error or at worst a very clear runtime error instead of a logic error). The other benefit of ASCII_A is that you are signalling that you are doing ASCII compar…

> The negative drawbacks of extracting constants is typically minimal > ASCII_A It comes down to naming and purpose. The example, ASCII_A, is terrible because it doesn't describe the purpose with its name. What will end up happening in any large codebase is ASCII_A will get reused in dozens of different places for dozens of different reasons. If it was named minValidLetterForAlgorithmX it would convey intent and its…

I'm partial to ALPHA_START or FIRST_LETTER. While it's true that 'A' is both, the naming helps communicate that the context is range-testing for alphabets inside a larger character set.

Re: The Design of Software is a Thing Apart

#89
1 point by charlysl 21 minutes ago | edit | delete [-]

Wouldn't it be better to use data abstraction instead of abusing primitive types?

For instance dates are often abstracted as a Date type instead of directly manipulating a bare int or long, which can be used internally to encode a date.

So, age, which isn't an int conceptually (should age^3 be a legal operation on an age?), could be modelled with an Age type. This, on top of preventing nonsense operations, also allows automatic invariant checking (age > 0), and to encapsulate representation (for instance changing it from an int representing the current age to a date of birth).

Re: The Design of Software is a Thing Apart

#90
post #5

Peter Naur's "Programming as Theory Building" also addresses this topic of a "theory" which is built in tandem with a piece of software, in the minds of the programmers building it, without actually being a part of the software itself. Definitely worth a read: http://pages.cs.wisc.edu/~remzi/Naur.pdf

> I shall use the word programming to denote the whole activity of design and implementation of programmed solutions. Isn't this definition circular, using "programmed" in defining "programming"?

I think for circularity you'd need a pair of definitions -- "programming: making a program" and "program: the result of programming". In this case, we already know what a program (or a "programmed solution") is -- that is, we can tell that something is a program without necessarily knowing how it was made. So the definition at least provides some new information on top of that -- the name for the activity of creating programs.[1] Also, by including the concept of "design", it lets you know when the author says "programming", he doesn't just mean the acts of writing source code, or typing it in.

[1] You could have probably guessed that the name was going to be "programming", but it might not have been.

Post reply on HN