A
Andrew McDonagh
Chris said:Hopefully, no one uses UML to document all the kinds of things that are
documented automatically by type systems. That would be a pain. Even
if they did, UML diagrams can generally get out of date, especially if
the code doesn't contain enough information to keep them up to date with
tools that do that sort of thing. JavaDoc (or any equivalent, as you
say Ruby has) can definitely get out of date. Documentation expressed
by the type system within the syntax of the language doesn't get out of
date.
I did say, 'depends upon what type you want' I didn't mean that to come
across as using them to document Types relations that are done by type
systems.
Unit tests as documentation is another thing. They are kept up to date
with code. The weakness, of course, lies in being so separated from
code; often residing in a different directory from the code that is
being documented by that test.
This is never a problem - the unit tests are considered as high a value
(or more) as the production code and therefore always compiled and run
as part of the build.
If they don't compile (because they haven't been kept up to date) then
the build fails.
If they don't ALL pass (because they haven't been kept upto date) then
the build fails.
Basically they either are up to date or the build fails.
The other weakness is that the tests are
in a language that as fundamentally just as opaque to reasoning about
behavior as the original programming language (in fact, it generally is
the same language). While one might hope that the code would be kept at
least a little simpler -- or perhaps that you'd write unit tests or
acceptance tests for the unit tests or acceptance tests -- the result
will still not match a form of expression designed for describing facts
about code that are the basis for simple reasoning about behavior.
Unit tests are best written in the same language as the code, as they
are only to describe what the code IS and how to USE it.
Their target audience is developers.
Acceptance Tests on the other hand should indeed be in a domain specfic
langauage. As this allows the stakeholders, testers and developers to
understand what the system is supposed to do.
Units tests are for Building the Code Right.
Acceptance Tests are for Building the Right Code
Interestingly, if I start to imagine languages in which simple unit
tests can be written inline to put the documentation closer to the code,
and possibly in a simpler language that is more prone to reasoning about
behavior, then I end up thinking about a proper design-by-contract
language. Hmm...
Having the unit tests in a parallel directory structure is only one of a
few standard ways of organising them. Lots of teams have the test code
in the same directory as the production code.
Sure, or other tools. Doesn't really matter if they are integrated or
not.
Yes. However, a good portion of the refactorings you list are
computationally intractable in Smalltalk in the general case. I am not
a Smalltalk programmer, and I don't know how the refactoring tools
handled that... perhaps they would give up, or perhaps they would guess
according to some heuristic to guess at the meaning of the code, and
rely on your unit tests to catch any errors that are introduced. Either
could be reasonable, depending on how good the heuristic can be made,
but either one is also a significant barrier to having usable tools.
And yet it doesn't in practice this does not seem to be the case....
So clearly, tools can be written for dynamic languages. The question is
whether they can be as good as tools for typed languages can be. (I'm
arguing the less popular side here; I would, however, probably agree if
you point out that an interactive tool that works 99.99% of the time is
just as good as one that works 100% of the time. I don't know if
Smalltalk's refactorings really do work 99.99% of the time or not.)
I haven't yet found a tool for statically typed languages that work
99.99% of the time (Eclipse, IntellJ, etc).
I don't personally find that the language type system has any impact on
usability or reliability.
Like, for example, implementation of polymorphic method dispatch in
practically the same time cost as a standard procedure call by using
vtables. Also, as an example, some of the work being done toward
optimizing away heap allocations by moving data onto the stack in Java
depends on static type analysis.
Chris Uppal has already answered this one better than I can.