Aegis supports TestFirstProgramming So does Bitkeeper; writing a trigger script which implements this feature isn't difficult.
Making BitKeeper support TestFirst to the level that Aegis does would be quite an undertaking -- although I will say that it would only have to be done once, so perhaps someone's already done it. It wasn't mentioned while I was on the BK list. I suspect it would be worth it.
arch: "unlike BitKeeper, that local repository is a full repository in its own right" So is Bitkeeper's. From your description, I don't see anything BK can't do.
Really? I don't remember that while I was working with BK. Maybe I missed something in the docs. If true, very cool.
What I recall was that the BK local repository was special: different from the global one. Hey, I've been wrong before.
I've always been impressed with BK (and I actually like its license a lot); the only reason I don't use it is that my company's firewall makes it impossible to even/experiment/ with BK.
If you're happy with CVS, stay with it at least until Subversion is finished -- svn is designed to be a replacement for CVS which fixes all the annoying oddities.
If you're not happy with CVS, or have been wondering why CVS doesn't do some specific things, check out some of the really different alternatives (but be prepared for some differences):
- "Aegis" supports TestFirstProgramming. In order to submit a change, you must provide a test which passes with the change, and fails to pass without the change. Furthermore, your change must not break any of the old tests. Extremely powerful for group programming, and useful for single-person programming.
- "BitKeeper" provides an attractive GUI and powerful tools, designed by a professional community. It provides very powerful support for branches, and allows you to use all the convenience of the full version-controlled repository without having to have all your checked-in changes messing up the main repository.
- "arch" may have a simpler interface right now, but it makes up for it with a very impressive model of distributed repositories. Like BitKeeper, you can make a local repository in order to make changes you want to see; unlike BitKeeper, that local repository is a full repository in its own right, and can be served independantly. It supports very sophisticated merging, so that you can merge your local repo with someone else who happened to start up their own local repo based on the same master repo; you can, of course, also merge with the master, and the master can choose to merge with your work.
I am impressed with the variety of version control systems which are now coming into their own. Very nice to see.
I'm surprised this one got modded up. The poster clearly knows nothing about the topic; it's just an ignorant flame.
In case anyone's wondering, arch supports and uses write permissions; however, it also allows you to start your OWN server, and people can hook up to it in parallel with the main server, and get all the branches which appear on either.
You can commit all the crashy code you want on your own server, but it won't affect anyone who isn't using your server.
The genius is that your server is hooked up to the original server, live, and you can track the changes they make, merging when and where you like. If the project manager for the original server feels like it (and if you let him), he can track the changes on your server as well. If someone else has started their own branch server, you can merge directly with them as well.
VERY clever.
Although I don't dig the Subversion trashing; Subversion is also very cool for its own purposes. I'm glad Tom took the time to underline the differences, but I'm unhappy that the result is so slanted. It didn't need to be: both arch and Subversion stand on their own as superb projects, and there's even another one coming out of IBM "sometime" which has its own merits.
Why should the benefits of research be first-generation only?
Because the benefits/do/ extend, even when the company hides the source. Only the source fails to extend -- but that's okay, because we have the part which was paid for by public money already.
Got that? We ALREADY have what we paid for. There's no reason to demand more. Or if you do demand more, you have every opportunity to get it -- simply take the open sourced research and create!
The problem with broadband (and the Internet in general) is that there's no economic feedback between supply and demand. The value of bandwidth, and of all the other services and 'goods' online, isn't clear, and it's hard to price it correctly.
I believe that there are good solutions. The one I'm watching closest right now is Mojonation; by providing a currency, they make it possible to track demand and allow "the market" to adapt supply to meet it. This will become really useful once some backbones sell and accept 'mojo' for their transport services (whatever method is used to account for the backbones will become a true currency).
I was in that boat for a while... Get your friend a copy of PC-Geos. It kicks Windows' butt, and does so without needing a 386. Back when the community college I used to go to had only 286es, it was the only way to get any real work done.
Unfortunately, Geoworks (the company that makes it) doesn't kick Microsoft's butt:-). And, of course, current versions of Windows FAR outdo Geos in every way. Although I still find myself using or wanting to use GeoWrite instead of the comparatively unfriendly Microsoft Word (GeoWrite is a frame-based word processor -- very impressive).
There's a demo version, named something like NewDeal Office.
Perhaps we are both mistaken about each other's position? Anyway, any misunderstanding aside, I think we probably still disagree on how to name functions.:-)
I think we're on the same page, actually. If you'd name a function resetThing then you're naming it according to its intent, not according to its contents.
However, you're also missing a point -- I'm not resetting the chip to indicate success; I'm simply setting the bit which usually means 'reset' and polling the device ready (which happens to coincide with the intended way of resetting the chip). The chip doesn't actually reset; it simply finishes unlocking its cryptographic functionality. So I don't call resetChip, because my purpose isn't to reset the chip, even though I think the procedure is the same. I would be wiser to call a function propagateUnlocking (or some such name). Therefore, when the workaround I mentioned is added to resetChip(), it breaks no code -- because everyone knows that a function named resetChip will be used only when a true full reset is needed.
My point is, as you discuss, that the programmer's intent in calling a function should be the main thing conveyed by the function's name. A function should never be called if its name fails to match your intent; if you examine the implementation, and it matches your needs exactly, you should at least change the function's name so that it fits into your intent as well as into the intent of its previous use. That way, when it comes time to modify the old function, the maintainer will know unmistakably that there's someone using the function in a way which was not originally anticipated.
Of course, if you choose to do that, you MUST also create some new unit tests for the renamed function which illustrate its new use. That way the maintainer will not only know _that_ there is a new use and intent for the function; he'll know also exactly what that new use it.
A function's name is not checked against what it does, any more than a comment is.
Well, yes; it is. A function's name appears in many places; if functions are supposed to have clear names, the lack of one will be very clear at a glance. A function which is being used for the wrong purpose should be obvious, and the best way to make it obvious is to make its name describe its purpose. Imagine seeing a function named 'SetFontAngle' in the middle of a vector rotation routine. You'd KNOW it was being used in a hackish way, and later font modifications could hammer it! How would you ever notice that if the function were instead named 'SetGraphicAngle' (i.e. it changed a cell named 'GraphicAngle' which happened to be shared by both vectors and fonts)?
Note that you're recommending naming functions for what they do; but the true story of what a function does is actually told by its implementation code. What a function does should be irrelevant to its use; for example, I may have a function which sets a specific bit in a specific I/O port, but that doesn't mean I name the function SetResetBitAndThenPollFor7854ChipReady. More likely, I name it for its intent: Reset7851Chip. Later on, when a reset bug is discovered, I implement the workaround without changing the name -- your function name would have to be changed to SetResetBitAndThenPollFor7854ChipReadyThenClearAll DMARegisters.
OTOH, suppose I'm writing some export unlocking code for the same chip, and step 5 of the unlocking procedure is to SetResetBitAndThenPollFor7854ChipReady. I would naturally notice your function name and would quite possibly use that function, because the name claims to tell what the function does -- but in your mind, that function is supposed to be a Reset7854Chip. What happens when the workaround has to be put in later? The only disciplined answer is that the person who originally wrote the function has to notice that it's being used elsewhere (hopefully), and rather than changing the old function, create a new function which calls the first and then zeroes the DMA registers. The new function would have the name we mentioned above, of course. Now what happens when a third programmer has to reset the chip? Which function does he choose? There's literally no way to know -- perhaps the comments in the calling functions will tell him, but that's a lot of source digging.
Code reuse: how can you reuse code if you don't know what it does? I think now you're arguing my side. I have been advocating naming a function for what it does. You're the one arguing that it should be named for why it does it, remember?:-)
I think we're getting confused here between 'what', 'how', and 'why'. I'm using 'what' to mean 'what is intended'; you're using it, I suspect, to mean 'what is being done'. I would not use 'what' for that purpose; 'how' is traditionally used. However, I should not use 'what' for my purpose, since 'why' is less ambiguous.
So I want to name functions based on their 'why'; you want to put the why in a comment, and name functions based on their 'how'.
I hope you don't actually think I'm advocating the use of bad names.
I apologise abjectly. That was a terrible connotation on my part.
However, you were clearly saying that function naming was a constraint which might get in the way of writing good functions. If you're going to abandon my constraint because it hinders divide-and-conquer, then you should equally consider abandoning all other naming constraints.
I'm just advocating naming functions by "what" rather than "why".
I hope you see why I believe 'what' is the wrong thing for a function name to say -- at least if the 'what' is 'what this function does'.
Do you have any evidence to support that, or is it just a little gratuitous XP evangelism?;-)
The second.;-)
I seriously do recognise some need for "get up to speed" documentation; it's just that it's almost impossible to write enough of it, and not write far too much. Of course, if you're doing pair programming regularly you won't need any (and you will have ALL team members knowledgable about the code in general), but if you can't do that (and politically it's almost impossible) you'll HAVE to write that getting-started documentation.
A pity that almost nobody will read it; the only exception will be the people so concientious that they hardly need it. Of course, you could be the exceptional project in which the people who know the code are also talented writers. But I doubt it.
And having him look at the requirements, and then work on the unit tests, and finally pair with a more experienced programmer, is better still -- and this way there's no extra paperwork to maintain.
I was referring to this code:
MakeNotAccidentallyClickable(widget);
That's what I meant by "example".
Yes, I wrote that -- but it's a direct translation of the comment someone else told me couldn't be replaced with a function name.
Ok, perhaps I made a straw man. The point I was trying to make is that there must be more details to the situation, whatever they are; and because your code didn't specify them, the problems you found in my commented version of the code may or may not exist in yours. One can't know without more information.
You're absolutely correct. However, this situation MUST be left to the wisdom of the programmer. There's simply nobody else to trust! If the programmer's wrong, he'll write wrong comments as well as wrong function names, and most likely wrong code as well. (See "peer review" and "pair programming" for some solutions to this.)
Perhaps I can sum up my thoughts this way. Programmers make mistakes.
Just a quick interruption: so do maintainers. The programmers shouldn't assume the maintainers are going to make all the mistakes in the book, and neither should the maintainers assume that about the programmers. A lot of common programming practice seems to assume that a horde of idiots are going to take over the code tomorrow, so anything I don't finish today will get destroyed and perverted. This results in late hours, aggressive comments (like "DON'T TOUCH THIS!"), a lack of tests (because you don't think the later programmers will have the wisdom to improve you code), and so on. Some cynicism is appropriate; after all, the later programmers will have at best a foggy memory of what you were thinking when you wrote it; however, at the same time, it's just as likely that the later programmers will understand the overall problem BETTER than you do.
It's hard to tell mistakes apart from deliberate decisions without some indication of the programmer's frame of mind.
This is true, and it's why I want code to be self-documenting. The code has to wisely and correctly make comments unneeded; you can't just delete the information contained in a comment. The advantage is huge: you go from *two* sources if information which may contradict each other (don't tell me that you've never seen out-of-sync comments;-) to one source which is automatically tested.
Thus, comments are only unnecessary in perfect code.
Not really true. There's no such thing as perfect code; comments are unneeded in code which tells the same story as the comments would. And such code (unlike perfect code) is not overly hard to construct.
If you choose to encode your comments using function names, rather than the features provided by the language specifically for the purpose, that's your choice;
Pardon, but function names are usually more of a language feature than comments; they're checked by the language, they're part of the syntax... Comments are just bolt-ons. And this IS the purpose of function names; but most people don't use them wisely.
but it's not yet clear to me that it is a beneficial one.
Well, I've given some reasons above. To me, the biggest two are as follows:
1. information can't get out of sync.
2. all information appears in two contexts: actual use (in the code), and prototypical use (in a unit test). Function names will look dramatically bad if they're chosen inappropriately. Comments can be ignored.
Comments can get out of sync with the code, in which case all of their "benefits" go to waste; and they can appear in only one place, and aren't checked there.
Have you ever come across (or written) any material that discuss the pros and cons of your approach?
It's a critical component of Extreme Programming, which is being discussed pro and con in a lot of places. I can also link to a few semi-balanced discussions (good paper, but biased toward the rather management-heavier SEI CMM model, which is needed for some projects). BTW, I was going to provide a con link, but the one I found is BAD -- hasty generalizations are just FLYING. Every single "danger" he cites is completely unjustified by experience and study, and many of the quotes he makes are out of context. It looks more like a Usenet post than a web article.
Anyhow, to implement what I'm describing you'll need at least Refactoring and Unit Testing from XP's arsenal. There's no reason you should have to adopt more, although once you have those in the others usually can be added at will. You also have to practice egoless programming -- don't be offended if someone changes the name of one of your functions; instead, make sure that the name is still appropriate to the use (if it's not, we have a bug being formed, since the person misunderstood the purpose of the function; you should show him a unit test in which the old name makes sense but the new one doesn't).
To me, function decomposition already serves three purposes: information hiding, code reuse, and divide-and-conquer problem solving. Adding a fourth criterion--of allowing comments to be encoded as function names--seems to raise the possibility that the criteria may conflict, and one may have to be sacrificed for another. Looking at the list, I know which is first on my chopping block.
Information hiding: true, but part of the purpose of IH is exposing only the correct information. That's part of the job of the function's name. So really, these two work together.
Code reuse: how can you reuse code if you don't know what it does? By choosing a good name, you are able to tell when things are being reused, and how appropriate they are to the situation. Note that the first time you extract a function, it'll have a very specific name (because you probably took it from a comment). The first time you reuse that function, you'll probably want to think of a little better name, and you'll probably also make some code changes -- the code worked in the one special case before, but now it has to work in two cases. As you keep reusing, your code keeps becoming easier to reuse; the name and the code keep becoming more general. So those two work together as well.
Divide-and-conquer: indeed, this is important -- but it's hard to argue that bad naming will help your strategy here.
When you scream "must," you seem to claim that "there are no exceptions." What if this new function needs to use a lot of a function's local variables without passing them as parameters (expensive for stack memory bandwidth, especially in the inner loop)?
Optimization/is/ a special case, I admit. For optimised code, expect readability to go out the window, in general. You have to give up something. Thus, you use comments rather than proper coding. However, keep in mind that micro-optimizations like that are dwarfed by better algorithms -- and sometimes (rarely) they're even trumped by a decent compiler. So keep those comments ready, but TRY not to use them.
However, in the general case, there's an alternative you aren't considering. Rather than fiddling with the stack or with messy hand-optimization, put the variables and the two methods into a class of their own. It's a standard, documented refactoring.
There is some info that can't be conveyed by code; it's called "requirements". That info can't be conveyed by comments, though, either.
However, you can refer to and briefly quote the use cases in the comments, to give future maintainers a bit of context.
Most requirements can't be expressed that way; any that can be, should be expressed as function names, as with all the examples which have been given.
I didn't give that example -- look at the history. That was given by someone who thought that the comment was needed (they provided a comment, too). I made a function which contained the code being commented, gave it a name which was essentially identical to the comment, and called it where the comment was. I also claimed that in any real work, I would have first built unit tests which confirmed that the function did what its name claimed.
so you tell me why you would call the "MakeNotAccidentallyClickable" function. I can't tell from your code, and that's the exact problem.
You use it when you want to make something not accidentally clickable. I haven't defined what "something" is, and I haven't defined in what context it's useful. The first job is for the type system, and the second job is for the object system.
It seems to me that my comments have helped you to diagnose problems in the code that were not obvious without those comments.
No! There were no problems in my code; there couldn't be, since I wrote no code. What I did was respond to someone else's problem sketch with a solution sketch. You responded not by pointing out omissions in my solution, but by inventing new problem details and situations. The fact that my example solution didn't cover them hardly matters; it was a solution to a/different/ problem.
What is the advantage of your scheme over comments?
A superb question.
Obviously, it can do everything comments can do except contain language syntax; so it's clear that for most purposes a good function name equals a comment. So why should we choose a function name _over_ a comment?
The first answer is that when more than one line is covered by a comment, those lines form a functional group and MUST be a function of their own. Once you have that, it's silly to not choose the new name to be as descriptive as the comment.
But there's more. If only a single line is covered by the comment, it's still beneficial to extract a function and delete the comment: by encapsulating the "how", you provide opportunity for later changes to the "what".
But the final BIG statement is this: comments can't be tested. Functions can, and a unit test will make it obvious when a function's name doesn't match its function.
However, explaining the "why" when it is not obvious from the "what" is exactly what comments are good at.
Please tell me SOME information in a comment which could not be conveyed in a function name. Fact is, you can't do it. Function names are exactly as expressive as comments.
There is some info that can't be conveyed by code; it's called "requirements". That info can't be conveyed by comments, though, either. It should be contained in use cases and acceptance tests, one acceptance test per use case. Acceptance tests should be automated, but that's a different story, and up to the customer, not the programmer.
Well said. It really, really helps, in my experience, to develop the habit of coding to the tests.
That is, you first write the tests; do the design while you're writing the tests (and have the tests express the design). Then write the code, trying constantly to run it against the tests. AS SOON as all your tests pass, commit the code; you're done. Don't refine anything until you have written a test which fails under the current code.
You see what happens? Pretty soon, instead of tests being your enemies which break your code, they're your friends which tell you when your job is done. You'll quickly find that they're reliable friends -- and long-lasting ones, too.
The only function whose name makes the comment unneeded is "exit()".
That's a stupid universal; I've already shown one example, which therefore disproves it. (exit() sometimes still needs a clear name, anyhow -- you may need to make it clear why you're exiting.)
But is there a form of your statement which has value? I say NO. Comments are only needed when clear code is impossible. Clear code is ALWAYS better. Sometimes it's unattainable, in which case comments are the only thing that can be done.
Design documentation is highly overrated (after all, it's a duplication of the code itself, which is the most detailed possible design document). Requirement documentation is essential. I suspect that this is what you're asking for, anyhow, since you're talking about showing it to the person who asked for it.
I think that requirement documentation is the only universal documentation requirement. Everything else can be ignored in some (special) situations.
I coded for the example I was given, at the level of detail I was given. You've added some more detailed scenarios; and I can code for those too.
The first comment should be a function name, not a comment. There's a LOT more you have to do to prevent document deletion! The comment, as it stands, is misleading, and later modification will possibly have to add more functionality. Just make it a function, so the functionality can be kept together.
The second comment says, "I, the programmer of this system, don't like the UI design." BAD SMELL. Use comments if you must, but a FAR FAR better solution is to fix the UI. Don't you agree?
Now, I'm sure you can invent other details under which those specific solutions are inapplicable -- but for every scenario you invent, I'll invent a way to code it so the comments aren't needed. The only exception is when time or lack of knowledge prevents removing the comments -- and the result is tragic.
Well said, on all points. Microsoft's problem is that they have too many processes, and IMO most of them are too heavy (and therefore they aren't really being well-applied). So they don't have A current process; they have many of them.
I personally have a bias against strong processes. I do admit that they can work, and work well; but they also cost a LOT, in every way; it's very hard to tell whether you're applying enough of the process to make it work. I'm definitely an XP fan; there, your process is light (although it IS hard), and feedback is immediate and automatic.
Comments used that way are like perfume -- they cover the smell of stinky code. Perfume isn't bad when your code stinks, but better is to make your code not stink.
A better solution would be to extract the thing you're commenting into a function, and name the function so that the comment is unneeded. Don't forget to write a test which checks the purpose of the function. Then (and only then) delete the comment.
MakeNotAccidentallyClickable(widget);
See what I mean? Now it's impossible for your comments to become out of sync with your code -- your code IS your comments.
Microsoft doesn't have quality code, but it DOES have reams of documentation. They have, and follow sporadically, a really strong process -- in fact, a huge number of really strong processes.
In many of their products, the design decisions are documented, and documented well.
As with all documentation at that level of detail, good luck finding the right page...
Don't play with code trees. Use only one "tree": the current, live one. Don't let one code base rot unmaintained while the other one is hacked to bits, untested.
Do take one mouthful at a time. Add unit tests, make sure they work. Now add a unit test for something you WANT to work, but which doesn't. Make that unit test work by implementing the feature. Release the result. Repeat.
Depend on tests, not documents. Documents lie. Tests don't.
Use as little documentation as possible, BUT NO LESS. (In other words, for heaven's sake don't ever try to get away without any documentation.) Documentation should state fundamental premises -- things like "The customer wants X." and "This code checks that I'm fulfilling the customer's requirement of X." Documentation should not state intrinsic properties -- the statement "this code does X" should be made as a test, not a document.
You're wrong. The comments you recommend will only/add/ to the mass of code to be grokked. Don't forbid commenting; but don't consider them a solution.
Instead, refactor and unit test. Unlike comments inserted into the middle of the code, unit tests will fail and point you to the reason for the failure. In the above example, when we upgrade to Qux1.5, the unit test which asserts that the Foo is untoggled will fail, and will point right to the function which made the assumption. Bingo -- a quick fix.
Aegis supports TestFirstProgramming
/experiment/ with BK.
So does Bitkeeper; writing a trigger script which implements this feature isn't difficult.
Making BitKeeper support TestFirst to the level that Aegis does would be quite an undertaking -- although I will say that it would only have to be done once, so perhaps someone's already done it. It wasn't mentioned while I was on the BK list. I suspect it would be worth it.
arch: "unlike BitKeeper, that local repository is a full repository in its own right"
So is Bitkeeper's. From your description, I don't see anything BK can't do.
Really? I don't remember that while I was working with BK. Maybe I missed something in the docs. If true, very cool.
What I recall was that the BK local repository was special: different from the global one. Hey, I've been wrong before.
I've always been impressed with BK (and I actually like its license a lot); the only reason I don't use it is that my company's firewall makes it impossible to even
-Billy
If you're happy with CVS, stay with it at least until Subversion is finished -- svn is designed to be a replacement for CVS which fixes all the annoying oddities.
If you're not happy with CVS, or have been wondering why CVS doesn't do some specific things, check out some of the really different alternatives (but be prepared for some differences):
- "Aegis" supports TestFirstProgramming. In order to submit a change, you must provide a test which passes with the change, and fails to pass without the change. Furthermore, your change must not break any of the old tests. Extremely powerful for group programming, and useful for single-person programming.
- "BitKeeper" provides an attractive GUI and powerful tools, designed by a professional community. It provides very powerful support for branches, and allows you to use all the convenience of the full version-controlled repository without having to have all your checked-in changes messing up the main repository.
- "arch" may have a simpler interface right now, but it makes up for it with a very impressive model of distributed repositories. Like BitKeeper, you can make a local repository in order to make changes you want to see; unlike BitKeeper, that local repository is a full repository in its own right, and can be served independantly. It supports very sophisticated merging, so that you can merge your local repo with someone else who happened to start up their own local repo based on the same master repo; you can, of course, also merge with the master, and the master can choose to merge with your work.
I am impressed with the variety of version control systems which are now coming into their own. Very nice to see.
-Billy
arch isn't designed for someone who wants a clean CVS replacement. It's a completely different system, with all its own powers and drawbacks.
Subversion is a CVS replacement.
-Billy
I'm surprised this one got modded up. The poster clearly knows nothing about the topic; it's just an ignorant flame.
In case anyone's wondering, arch supports and uses write permissions; however, it also allows you to start your OWN server, and people can hook up to it in parallel with the main server, and get all the branches which appear on either.
You can commit all the crashy code you want on your own server, but it won't affect anyone who isn't using your server.
The genius is that your server is hooked up to the original server, live, and you can track the changes they make, merging when and where you like. If the project manager for the original server feels like it (and if you let him), he can track the changes on your server as well. If someone else has started their own branch server, you can merge directly with them as well.
VERY clever.
Although I don't dig the Subversion trashing; Subversion is also very cool for its own purposes. I'm glad Tom took the time to underline the differences, but I'm unhappy that the result is so slanted. It didn't need to be: both arch and Subversion stand on their own as superb projects, and there's even another one coming out of IBM "sometime" which has its own merits.
-Billy
Why should the benefits of research be first-generation only?
/do/ extend, even when the company hides the source. Only the source fails to extend -- but that's okay, because we have the part which was paid for by public money already.
Because the benefits
Got that? We ALREADY have what we paid for. There's no reason to demand more. Or if you do demand more, you have every opportunity to get it -- simply take the open sourced research and create!
-Billy
The problem with broadband (and the Internet in general) is that there's no economic feedback between supply and demand. The value of bandwidth, and of all the other services and 'goods' online, isn't clear, and it's hard to price it correctly.
I believe that there are good solutions. The one I'm watching closest right now is Mojonation; by providing a currency, they make it possible to track demand and allow "the market" to adapt supply to meet it. This will become really useful once some backbones sell and accept 'mojo' for their transport services (whatever method is used to account for the backbones will become a true currency).
-Billy
I was in that boat for a while... Get your friend a copy of PC-Geos. It kicks Windows' butt, and does so without needing a 386. Back when the community college I used to go to had only 286es, it was the only way to get any real work done.
:-). And, of course, current versions of Windows FAR outdo Geos in every way. Although I still find myself using or wanting to use GeoWrite instead of the comparatively unfriendly Microsoft Word (GeoWrite is a frame-based word processor -- very impressive).
Unfortunately, Geoworks (the company that makes it) doesn't kick Microsoft's butt
There's a demo version, named something like NewDeal Office.
-Billy
I wonder... The press release quotes a PhD from Hifn and a marketing droid from RSA, and says that RSA and Hifn developed this together.
I know RSA's the big name here, but I wonder whether they merely contributed the name, not the research.
-Billy
Perhaps we are both mistaken about each other's position? Anyway, any misunderstanding aside, I think we probably still disagree on how to name functions. :-)
I think we're on the same page, actually. If you'd name a function resetThing then you're naming it according to its intent, not according to its contents.
However, you're also missing a point -- I'm not resetting the chip to indicate success; I'm simply setting the bit which usually means 'reset' and polling the device ready (which happens to coincide with the intended way of resetting the chip). The chip doesn't actually reset; it simply finishes unlocking its cryptographic functionality. So I don't call resetChip, because my purpose isn't to reset the chip, even though I think the procedure is the same. I would be wiser to call a function propagateUnlocking (or some such name). Therefore, when the workaround I mentioned is added to resetChip(), it breaks no code -- because everyone knows that a function named resetChip will be used only when a true full reset is needed.
My point is, as you discuss, that the programmer's intent in calling a function should be the main thing conveyed by the function's name. A function should never be called if its name fails to match your intent; if you examine the implementation, and it matches your needs exactly, you should at least change the function's name so that it fits into your intent as well as into the intent of its previous use. That way, when it comes time to modify the old function, the maintainer will know unmistakably that there's someone using the function in a way which was not originally anticipated.
Of course, if you choose to do that, you MUST also create some new unit tests for the renamed function which illustrate its new use. That way the maintainer will not only know _that_ there is a new use and intent for the function; he'll know also exactly what that new use it.
-Billy
Good points, again.
l DMARegisters.
:-)
A function's name is not checked against what it does, any more than a comment is.
Well, yes; it is. A function's name appears in many places; if functions are supposed to have clear names, the lack of one will be very clear at a glance. A function which is being used for the wrong purpose should be obvious, and the best way to make it obvious is to make its name describe its purpose. Imagine seeing a function named 'SetFontAngle' in the middle of a vector rotation routine. You'd KNOW it was being used in a hackish way, and later font modifications could hammer it! How would you ever notice that if the function were instead named 'SetGraphicAngle' (i.e. it changed a cell named 'GraphicAngle' which happened to be shared by both vectors and fonts)?
Note that you're recommending naming functions for what they do; but the true story of what a function does is actually told by its implementation code. What a function does should be irrelevant to its use; for example, I may have a function which sets a specific bit in a specific I/O port, but that doesn't mean I name the function SetResetBitAndThenPollFor7854ChipReady. More likely, I name it for its intent: Reset7851Chip. Later on, when a reset bug is discovered, I implement the workaround without changing the name -- your function name would have to be changed to SetResetBitAndThenPollFor7854ChipReadyThenClearAl
OTOH, suppose I'm writing some export unlocking code for the same chip, and step 5 of the unlocking procedure is to SetResetBitAndThenPollFor7854ChipReady. I would naturally notice your function name and would quite possibly use that function, because the name claims to tell what the function does -- but in your mind, that function is supposed to be a Reset7854Chip. What happens when the workaround has to be put in later? The only disciplined answer is that the person who originally wrote the function has to notice that it's being used elsewhere (hopefully), and rather than changing the old function, create a new function which calls the first and then zeroes the DMA registers. The new function would have the name we mentioned above, of course. Now what happens when a third programmer has to reset the chip? Which function does he choose? There's literally no way to know -- perhaps the comments in the calling functions will tell him, but that's a lot of source digging.
Code reuse: how can you reuse code if you don't know what it does?
I think now you're arguing my side. I have been advocating naming a function for what it does. You're the one arguing that it should be named for why it does it, remember?
I think we're getting confused here between 'what', 'how', and 'why'. I'm using 'what' to mean 'what is intended'; you're using it, I suspect, to mean 'what is being done'. I would not use 'what' for that purpose; 'how' is traditionally used. However, I should not use 'what' for my purpose, since 'why' is less ambiguous.
So I want to name functions based on their 'why'; you want to put the why in a comment, and name functions based on their 'how'.
I hope you don't actually think I'm advocating the use of bad names.
I apologise abjectly. That was a terrible connotation on my part.
However, you were clearly saying that function naming was a constraint which might get in the way of writing good functions. If you're going to abandon my constraint because it hinders divide-and-conquer, then you should equally consider abandoning all other naming constraints.
I'm just advocating naming functions by "what" rather than "why".
I hope you see why I believe 'what' is the wrong thing for a function name to say -- at least if the 'what' is 'what this function does'.
-Billy
Do you have any evidence to support that, or is it just a little gratuitous XP evangelism? ;-)
;-)
The second.
I seriously do recognise some need for "get up to speed" documentation; it's just that it's almost impossible to write enough of it, and not write far too much. Of course, if you're doing pair programming regularly you won't need any (and you will have ALL team members knowledgable about the code in general), but if you can't do that (and politically it's almost impossible) you'll HAVE to write that getting-started documentation.
A pity that almost nobody will read it; the only exception will be the people so concientious that they hardly need it. Of course, you could be the exceptional project in which the people who know the code are also talented writers. But I doubt it.
-Billy
And having him look at the requirements, and then work on the unit tests, and finally pair with a more experienced programmer, is better still -- and this way there's no extra paperwork to maintain.
-Billy
I was referring to this code:
;-) to one source which is automatically tested.
MakeNotAccidentallyClickable(widget);
That's what I meant by "example".
Yes, I wrote that -- but it's a direct translation of the comment someone else told me couldn't be replaced with a function name.
Ok, perhaps I made a straw man. The point I was trying to make is that there must be more details to the situation, whatever they are; and because your code didn't specify them, the problems you found in my commented version of the code may or may not exist in yours. One can't know without more information.
You're absolutely correct. However, this situation MUST be left to the wisdom of the programmer. There's simply nobody else to trust! If the programmer's wrong, he'll write wrong comments as well as wrong function names, and most likely wrong code as well. (See "peer review" and "pair programming" for some solutions to this.)
Perhaps I can sum up my thoughts this way. Programmers make mistakes.
Just a quick interruption: so do maintainers. The programmers shouldn't assume the maintainers are going to make all the mistakes in the book, and neither should the maintainers assume that about the programmers. A lot of common programming practice seems to assume that a horde of idiots are going to take over the code tomorrow, so anything I don't finish today will get destroyed and perverted. This results in late hours, aggressive comments (like "DON'T TOUCH THIS!"), a lack of tests (because you don't think the later programmers will have the wisdom to improve you code), and so on. Some cynicism is appropriate; after all, the later programmers will have at best a foggy memory of what you were thinking when you wrote it; however, at the same time, it's just as likely that the later programmers will understand the overall problem BETTER than you do.
It's hard to tell mistakes apart from deliberate decisions without some indication of the programmer's frame of mind.
This is true, and it's why I want code to be self-documenting. The code has to wisely and correctly make comments unneeded; you can't just delete the information contained in a comment. The advantage is huge: you go from *two* sources if information which may contradict each other (don't tell me that you've never seen out-of-sync comments
Thus, comments are only unnecessary in perfect code.
Not really true. There's no such thing as perfect code; comments are unneeded in code which tells the same story as the comments would. And such code (unlike perfect code) is not overly hard to construct.
If you choose to encode your comments using function names, rather than the features provided by the language specifically for the purpose, that's your choice;
Pardon, but function names are usually more of a language feature than comments; they're checked by the language, they're part of the syntax... Comments are just bolt-ons. And this IS the purpose of function names; but most people don't use them wisely.
but it's not yet clear to me that it is a beneficial one.
Well, I've given some reasons above. To me, the biggest two are as follows:
1. information can't get out of sync.
2. all information appears in two contexts: actual use (in the code), and prototypical use (in a unit test). Function names will look dramatically bad if they're chosen inappropriately. Comments can be ignored.
Comments can get out of sync with the code, in which case all of their "benefits" go to waste; and they can appear in only one place, and aren't checked there.
Have you ever come across (or written) any material that discuss the pros and cons of your approach?
It's a critical component of Extreme Programming, which is being discussed pro and con in a lot of places. I can also link to a few semi-balanced discussions (good paper, but biased toward the rather management-heavier SEI CMM model, which is needed for some projects). BTW, I was going to provide a con link, but the one I found is BAD -- hasty generalizations are just FLYING. Every single "danger" he cites is completely unjustified by experience and study, and many of the quotes he makes are out of context. It looks more like a Usenet post than a web article.
Oh, here's dmoz's directory page.
Anyhow, to implement what I'm describing you'll need at least Refactoring and Unit Testing from XP's arsenal. There's no reason you should have to adopt more, although once you have those in the others usually can be added at will. You also have to practice egoless programming -- don't be offended if someone changes the name of one of your functions; instead, make sure that the name is still appropriate to the use (if it's not, we have a bug being formed, since the person misunderstood the purpose of the function; you should show him a unit test in which the old name makes sense but the new one doesn't).
To me, function decomposition already serves three purposes: information hiding, code reuse, and divide-and-conquer problem solving. Adding a fourth criterion--of allowing comments to be encoded as function names--seems to raise the possibility that the criteria may conflict, and one may have to be sacrificed for another. Looking at the list, I know which is first on my chopping block.
Information hiding: true, but part of the purpose of IH is exposing only the correct information. That's part of the job of the function's name. So really, these two work together.
Code reuse: how can you reuse code if you don't know what it does? By choosing a good name, you are able to tell when things are being reused, and how appropriate they are to the situation. Note that the first time you extract a function, it'll have a very specific name (because you probably took it from a comment). The first time you reuse that function, you'll probably want to think of a little better name, and you'll probably also make some code changes -- the code worked in the one special case before, but now it has to work in two cases. As you keep reusing, your code keeps becoming easier to reuse; the name and the code keep becoming more general. So those two work together as well.
Divide-and-conquer: indeed, this is important -- but it's hard to argue that bad naming will help your strategy here.
-Billy
When you scream "must," you seem to claim that "there are no exceptions." What if this new function needs to use a lot of a function's local variables without passing them as parameters (expensive for stack memory bandwidth, especially in the inner loop)?
/is/ a special case, I admit. For optimised code, expect readability to go out the window, in general. You have to give up something. Thus, you use comments rather than proper coding. However, keep in mind that micro-optimizations like that are dwarfed by better algorithms -- and sometimes (rarely) they're even trumped by a decent compiler. So keep those comments ready, but TRY not to use them.
Optimization
However, in the general case, there's an alternative you aren't considering. Rather than fiddling with the stack or with messy hand-optimization, put the variables and the two methods into a class of their own. It's a standard, documented refactoring.
There is some info that can't be conveyed by code; it's called "requirements". That info can't be conveyed by comments, though, either.
However, you can refer to and briefly quote the use cases in the comments, to give future maintainers a bit of context.
Most requirements can't be expressed that way; any that can be, should be expressed as function names, as with all the examples which have been given.
-Billy
Hey, you're the one who gave the example,
/different/ problem.
I didn't give that example -- look at the history. That was given by someone who thought that the comment was needed (they provided a comment, too). I made a function which contained the code being commented, gave it a name which was essentially identical to the comment, and called it where the comment was. I also claimed that in any real work, I would have first built unit tests which confirmed that the function did what its name claimed.
so you tell me why you would call the "MakeNotAccidentallyClickable" function. I can't tell from your code, and that's the exact problem.
You use it when you want to make something not accidentally clickable. I haven't defined what "something" is, and I haven't defined in what context it's useful. The first job is for the type system, and the second job is for the object system.
It seems to me that my comments have helped you to diagnose problems in the code that were not obvious without those comments.
No! There were no problems in my code; there couldn't be, since I wrote no code. What I did was respond to someone else's problem sketch with a solution sketch. You responded not by pointing out omissions in my solution, but by inventing new problem details and situations. The fact that my example solution didn't cover them hardly matters; it was a solution to a
What is the advantage of your scheme over comments?
A superb question.
Obviously, it can do everything comments can do except contain language syntax; so it's clear that for most purposes a good function name equals a comment. So why should we choose a function name _over_ a comment?
The first answer is that when more than one line is covered by a comment, those lines form a functional group and MUST be a function of their own. Once you have that, it's silly to not choose the new name to be as descriptive as the comment.
But there's more. If only a single line is covered by the comment, it's still beneficial to extract a function and delete the comment: by encapsulating the "how", you provide opportunity for later changes to the "what".
But the final BIG statement is this: comments can't be tested. Functions can, and a unit test will make it obvious when a function's name doesn't match its function.
However, explaining the "why" when it is not obvious from the "what" is exactly what comments are good at.
Please tell me SOME information in a comment which could not be conveyed in a function name. Fact is, you can't do it. Function names are exactly as expressive as comments.
There is some info that can't be conveyed by code; it's called "requirements". That info can't be conveyed by comments, though, either. It should be contained in use cases and acceptance tests, one acceptance test per use case. Acceptance tests should be automated, but that's a different story, and up to the customer, not the programmer.
-Billy
Well said. It really, really helps, in my experience, to develop the habit of coding to the tests.
That is, you first write the tests; do the design while you're writing the tests (and have the tests express the design). Then write the code, trying constantly to run it against the tests. AS SOON as all your tests pass, commit the code; you're done. Don't refine anything until you have written a test which fails under the current code.
You see what happens? Pretty soon, instead of tests being your enemies which break your code, they're your friends which tell you when your job is done. You'll quickly find that they're reliable friends -- and long-lasting ones, too.
-Billy
The only function whose name makes the comment unneeded is "exit()".
That's a stupid universal; I've already shown one example, which therefore disproves it. (exit() sometimes still needs a clear name, anyhow -- you may need to make it clear why you're exiting.)
But is there a form of your statement which has value? I say NO. Comments are only needed when clear code is impossible. Clear code is ALWAYS better. Sometimes it's unattainable, in which case comments are the only thing that can be done.
-Billy
Design documentation is highly overrated (after all, it's a duplication of the code itself, which is the most detailed possible design document). Requirement documentation is essential. I suspect that this is what you're asking for, anyhow, since you're talking about showing it to the person who asked for it.
I think that requirement documentation is the only universal documentation requirement. Everything else can be ignored in some (special) situations.
-Billy
I coded for the example I was given, at the level of detail I was given. You've added some more detailed scenarios; and I can code for those too.
The first comment should be a function name, not a comment. There's a LOT more you have to do to prevent document deletion! The comment, as it stands, is misleading, and later modification will possibly have to add more functionality. Just make it a function, so the functionality can be kept together.
The second comment says, "I, the programmer of this system, don't like the UI design." BAD SMELL. Use comments if you must, but a FAR FAR better solution is to fix the UI. Don't you agree?
Now, I'm sure you can invent other details under which those specific solutions are inapplicable -- but for every scenario you invent, I'll invent a way to code it so the comments aren't needed. The only exception is when time or lack of knowledge prevents removing the comments -- and the result is tragic.
-Billy
Well said, on all points. Microsoft's problem is that they have too many processes, and IMO most of them are too heavy (and therefore they aren't really being well-applied). So they don't have A current process; they have many of them.
I personally have a bias against strong processes. I do admit that they can work, and work well; but they also cost a LOT, in every way; it's very hard to tell whether you're applying enough of the process to make it work. I'm definitely an XP fan; there, your process is light (although it IS hard), and feedback is immediate and automatic.
-Billy
Comments used that way are like perfume -- they cover the smell of stinky code. Perfume isn't bad when your code stinks, but better is to make your code not stink.
A better solution would be to extract the thing you're commenting into a function, and name the function so that the comment is unneeded. Don't forget to write a test which checks the purpose of the function. Then (and only then) delete the comment.
MakeNotAccidentallyClickable(widget);
See what I mean? Now it's impossible for your comments to become out of sync with your code -- your code IS your comments.
-Billy
Microsoft doesn't have quality code, but it DOES have reams of documentation. They have, and follow sporadically, a really strong process -- in fact, a huge number of really strong processes.
In many of their products, the design decisions are documented, and documented well.
As with all documentation at that level of detail, good luck finding the right page...
Other than that, you're right.
-Billy
Wise, but may I suggest the obvious extension?
Don't play with code trees. Use only one "tree": the current, live one. Don't let one code base rot unmaintained while the other one is hacked to bits, untested.
Do take one mouthful at a time. Add unit tests, make sure they work. Now add a unit test for something you WANT to work, but which doesn't. Make that unit test work by implementing the feature. Release the result. Repeat.
-Billy
Depend on tests, not documents. Documents lie. Tests don't.
Use as little documentation as possible, BUT NO LESS. (In other words, for heaven's sake don't ever try to get away without any documentation.) Documentation should state fundamental premises -- things like "The customer wants X." and "This code checks that I'm fulfilling the customer's requirement of X." Documentation should not state intrinsic properties -- the statement "this code does X" should be made as a test, not a document.
-Billy
You're wrong. The comments you recommend will only /add/ to the mass of code to be grokked. Don't forbid commenting; but don't consider them a solution.
Instead, refactor and unit test. Unlike comments inserted into the middle of the code, unit tests will fail and point you to the reason for the failure. In the above example, when we upgrade to Qux1.5, the unit test which asserts that the Foo is untoggled will fail, and will point right to the function which made the assumption. Bingo -- a quick fix.
-Billy