Hacker News new | ask | show | jobs
by 6ren 4598 days ago
It clutters the code.

Tests are a form of documentation, but too much in the code, like too many comments, obscures. Higher level unit tests (acceptance tests) can be quite long, especially if there's a lot of setup - unlike their example code. Literate programming tried embedded documentation, but didn't catch on (even with Knuth's backing). Embedding tests makes them easier to keep in sync, but tests are already kept in sync by (hopefully) failing when not. However, their idea of automatically running tests is interesting, so there's no infrastructure to set-up, run etc (though you'd want to be able to disable them).

Nice for teaching.

9 comments

I don't think the story of literate programming can be of any help predicting how well this idea here can work out.

Literate programming is not "embedding documentation". The main idea was to separate the order in which the code is read from the order in which the compiler sees it, and it embeds the code in the documentation, not vice versa. It was a very idiosyncratic thing, hard to imagine a team of programmers in a typical current commercial setting, developing a nice LaTeX essay around the actual code of the next social network web-app. As the program grows larger it also gets harder and harder to maintain the "story" around it.

That's not the "main idea". Originally, it was a part of the suggested way to accomplish the goal ... but the main idea is this:

    > Let us change our traditional attitude to the construction of programs: 
    > Instead of imagining that our main task is to instruct a computer what 
    > to do, let us concentrate rather on explaining to human beings what we 
    > want a computer to do.
    >                          — Knuth
If your program can be read more as an enlightening explanation of the job-to-be-done, and is more oriented toward the human reader of the code than the machine that will execute it, then you've succeeded.

Hopefully, it's clear how a program written in such a way could potentially be beneficial to a large team, trying to understand, modify, and improve it.

Right, but it's important to emphasize what stiff was talking about, that the structure of the narrative needs to be oriented towards the human instead of the machine, because so many people don't bother to do this and decide that literate programming just means having LaTeX or docbook comments in your code. That total inversion (the code is in the documentation, not the documentation is in the code) is important. (That said, I admit that most modern languages are so much more flexible compared to C or Pascal with regards the ordering of code.)
It's like saying the main idea in C was to allow writing programs. At this level of generality it is indistinguishable from tens of projects with similar goals, including also earlier ones.
It's also much less necessary with packages, where you can trivially change the order of most of the code is read.
You don't have to put the tests right in the middle of code. The `where` form goes with the definition, but a `check` form can float freely. So if you prefer a <Lang>Unit style of testing, where your tests reside in a separate file, you can do that with `check` blocks just fine.

However, the `where` tests play into the type-inference story for the language!

I think that Python's doctests have shown this to be a greyer area than this. Not all tests can fit nicely next to function definitions, but a few well-chosen ones are both fantastic documentation and not too cluttery.
Doc tests are a poor solution precisely because they are difficult to edit. The solved a non-problem and made writing documentation AND tests more difficult.

Instead of writing tests in strings, the documentation tool should have been modified to render that code _in_ the documentation.

Doc tests are butt-ugly in several ways. Code shouldn't be written in strings, and they take twice as much vertical space as they need (which is a problem because monitors are typically used much wider than they are tall).
I agree with you in that managing real code in a place that gets less frequently executed is a bear, but I wanted to emphasize the value of having tests very near to the primary documentation for a function. That's a complete win, I feel.
Which it totally is! That is why all the functions I test are in pairs suitable for nose or py.test

    def test_foo():
        assert False, "test code for foo"

    def foo(farb):
        pass
Tests should absolutely be next to the code. The test should make it into the documentation. Code is documentation and should make it into the generated documentation, not the first thing you see but it should be there along with commit history, etc.
If that ended up nicely formatted beneath the definition of `foo` in the documentation I would recommend it wholeheartedly. In practice it doesn't happen, sadly.
Thank you! I never had any idea this kind of things exists in python... I can already see some code that would benefit from this (it would be insane to put it everywhere of course).
On the other hand, inline test does make it easier to write tests while writing the function. Besides many well-written programs already contains inline documentation (not comments) that can be a lot longer than the function they describes.

Code folding in a IDE goes a long way to make this bearable.

> Code folding in a IDE goes a long way to make this bearable.

Code folding in IDEs is an indication that we are doing it wrong -- that is, we human beings are programming computers "wrong."

I'm not saying that code folding is a symptom. I'm saying that code folding shows how primitive our means of managing code is. It's as if the mesopotamians somehow invented computers, and because of tradition, all code has to be written as cuneiform on wet clay tablets, then fired in ovens before being read. At least text files in directories are digital, but they are as static and behavior-less as clay tablets, and all of the important relationships therein are expressed as implicit correspondences which programmers have to keep track of in their heads.

Code Bubbles is a beacon in the direction we should go.

https://www.youtube.com/watch?v=PsPX0nElJ0k

Code Bubbles were invented one floor above me (by another team in computer science at Brown University). So, we're not at all unaware of it. And yes, it's great stuff.

But we also had to make a conscious decision about IDEs, and we decided to be IDE agnostic -- IDEs should enhance the language but not be the only means of working with it, because programmers are really attached to their editors, and a language predicated on tearing people away from their editors will stuggle. Also, having been part of DrRacket from version 0.0, I know how long it takes to make one that's any good.

Code Bubbles were invented one floor above me (by another team in computer science at Brown University).

I wrote a significant fraction of a Smalltalk class browser.

IDEs should enhance the language but not be the only means of working with it, because programmers are really attached to their editors, and a language predicated on tearing people away from their editors will struggle.

So, basically you made the pragmatic decision. What you say is true, but I suspect this tendency is ultimately holding us back.

I've had this argument for twenty years. I had my a-ha moment in grad school when, after I'd put a fair bit of work into a build system and showed it around, my advisor asked me, "What is a file?" And then I was enlightened. So I can play this song back with fairly good fidelity.

If I could get a reliable, efficient, cross-platform, extensible, quickly-ported-to-new-platforms environment that gave me rich editing, I'd grab it. I don't know of such a platform. So we made the "pragmatic" decision, yes. That's because this isn't the problem we're trying to solve.

We are actually trying to innovate in the programming environment space, and have been running with that experiment for the past semester internally at Brown. At some point, after it's been knocked around a bit more, we'll make it public. So we're not avoiding the environment space. But this is not a battle we're seeking to pick in that space.

I wish you luck with it, and hope we can build on the work of people like you.

While in some sense I agree with you, stuff like code bubbles is just a incremental step from folding. If you want better interfaces for your coding, you write bidirectional transformations between your representation and the text; the point being that the underlying representation does not particularly matter. Having underlying text, however, means you have a good fallback in case your tools do fail.

I would say the more potent point is that it should not matter at all if the tests are in the function or in a different directory: the IDE should be able to fold them in either way, and in some sense, IDEs already do have partial support for this.

> While in some sense I agree with you, stuff like code bubbles is just a incremental step from folding.

I said it was a "beacon in the direction we want to go," not a lighthouse at the destination!

> the point being that the underlying representation does not particularly matter. Having underlying text, however, means you have a good fallback in case your tools do fail.

Sure, do this, so long as the representation doesn't limit the objective capabilities of the environment and so long as it doesn't limit the ways tool makers think about code. Unfortunately, our current representations clearly do both.

Code bubbles looks cool, but I don't see the connection with your point about clay tablets. Any digital data is, by itself, flat and behavior-less, whether it's in the form of traditional files or some specially-designed backing store for something like Code Bubbles. I don't see any point in really trying to hide that base reality.

I am in favor of giving links between data a more prominent place in our storage systems. I envision a system where the data is mostly fine-grained trees, like sexprs, where hard-links between trees are first-class entities. But at the end of the day it's just an abstraction over a bunch of bytes.

> Any digital data is, by itself, flat and behavior-less, whether it's in the form of traditional files or some specially-designed backing store for something like Code Bubbles.

I know this is false. You can have a system where everything is an object and carries behavior around with it. We've had those for over 40 years.

> I am in favor of giving links between data a more prominent place in our storage systems.

A "more prominent place?" Isn't this a bit bass-ackwards? Aren't relationships in code where the primary value is?

The behavior carried around by those objects is ultimately in the form of flat digital data, interpreted by other, more general programs, executed on a CPU. Behavior, when it comes down to it, is a property of silicon, not data. This might seem like a useless distinction, but I don't think it is. I like to keep track of what things are underneath the abstractions.
I think you're completely backwards on this.

Code folding in an IDE is an example of a way in which text files aren't necessarily static and behavior-less. I see no reason to move away from an underlying representation as text.

I see no reason to move away from an underlying representation as text.

A big reason is that otherwise people won't move away from the paradigm of static text files. The best they'll do is text files with little gimmicks attached to them.

> Literate programming… didn't catch on

I would argue literate programming is experiencing a renaissance, thanks to docco:

https://github.com/jashkenas/docco

I think literate coffeescript might be a better example of popularizing literate programming:

http://ashkenas.com/literate-coffeescript/

There also seems to be some traction for literate Haskell:

http://www.haskell.org/haskellwiki/Literate_programming

I experimented a bit with literate programming on an introductory course in programming using java. It's an interesting experience -- it's very easy to produce a very readable language that is still pretty poor java code, as it becomes so easy to split out fragments and "procedures", rather than follow the more common java class-oriented object orientated way of doing things.

Not really, I never heard of docco and am yet to see a RFP for a node.js project from my employer's enterprise customers.
Chances are much higher that you've seen the output of Docco or one of the multitude of imitations for other languages.
You would think we'd have editors by now that could, say, hide all the tests to declutter the code while you're reading it.
I think you are both right. D even takes it to the next logical step: Present the unit tests as examples in the API documentation (like Doxygen,Javadoc). It means the API examples are kept in sync.

http://qznc.github.io/d-tut/testing.html

If the tests are pages long, that might be a sign that the function could be refactored. Also, the optional type annotations and refinements seem to decrease necessary testing quite a bit, compared to the typical scripting language. I would use this all the time.

And as other people mentioned, you can always use the check statement out of band, too.

> It clutters the code.

Modern IDEs/code editors can support code folding as well as projections fairly easily. I don't see a problem.