C. Keith Ray

C. Keith Ray writes about and develops software in multiple platforms and languages, including iOS® and Macintosh®.
Keith's Résumé (pdf)

Saturday, April 27, 2013

Command Pattern

(Reblogged from 11/23/2003)

Martin Fowler writes of the CommandOrientedInterface and command objects and executors:
Command oriented interfaces have a number of benefits. One of the primary ones is the ability to easily add common behavior to commands by decorating the command executor. This is very handy for handling transactions, logging, and the like. Commands can be queued for later execution and [...] be passed across a network. Command results can be cached [...]
And, of course, it is relatively easy to add "Undo/Redo" support to command objects and store stacks of command objects to be undone/redone.

In a dynamic language that supports reflection, one could create generic command objects by creating a class that retains a reference to an arbitrary object [call it a 'target'], a reference to an arbitrary method of that object [call that an 'action'], and a list of arguments to pass into that method [or perhaps only one argument, the 'sender'].

Instances of this class could be created by reading a configuration file or deserializing instances that had been created in an Interface Builder. I'm not saying that Apple's Interface Builder does exactly like this, but it is doing something kind of like this. See this page for more.

Cocoa and Interface builder allow creating powerful programs without writing (or generating) a lot of code. It's been one of the most advanced development environments for at least a decade (it used to be part of NextStep), and it still is one of the most advanced development environments.

Smalltalk, Objective-C, and no doubt Python and Ruby could generic command-object classes like this very succinctly. Java would be more difficult, but it can be done in Java, as well.

Perhaps if methods and method-calls (and classes) were more easily thought of as first-class objects [which is very far from the case in C++], tools forAspect-Oriented programming would be easier or unnecessary.

Thursday, April 25, 2013

Test-Driven Design/Development

(Repeat from my old blog 2003/11/25.)

I'm about two-thirds done reading Unit Testing In Java: How tests drive the code by Johannes Link. It's a very good book. Go buy it now, even if you're not programming in Java, and then finish reading my blog. :-)

The summary form of test-driven development is:
  1. Think about what we want to the program to do.
  2. Write a test that shows some aspect is done.
  3. Run the test, see it fail because we haven't written the code to get the thing done yet (this tests our test, giving us some confidence that our test is written correctly).
  4. Write the smallest amount of code to make that test pass.
  5. Run the test, hopefully see if pass. (If it doesn't, fix the problem.)
  6. Refactor to clean up the code.
  7. Run the test again, to make sure refactoring didn't break anything.
  8. Repeat [sometimes skipping 6 and 7] until you can't think of any new tests, or until the code stops changing as a result of adding tests.
So what if we don't know what we want the program to do?

Writing a test can help us figure that out. Since the code hasn't been done yet, the test is "black-box" and does not necessarily commit us to any particular way of implementing the solution. We can write "Exploratory Tests" to investigate existing code - does calling "X" do "Y"? Write a test and find out.

I don't have time to write lots of tests.

Well, you only have to test code that you want to work. If you don't test it before you write, you'll be testing it in some fashion after you write it. Or someone else will test it, file a bug report because you didn't test it, and then you have to not only interrupt whatever you're doing and fix it, but also test it to confirm that you fixed it. And the time-delays between your writing the code, the tester finding the bug, and your trying to fix the bug means that you will be less familiar with the code, and thus fixing it will be that much harder and slower.

There is, of course LOTS of code out there that was not written this way (some of it is mine). Just browse some of the code on the internet or in your company's source-code-control system - probably most of it isn't written using test-driven techniques.

You'll probably find these things in non-test-driven code (particularly in projects that don't do code-reviews or pair-programming and refactoring):
  • Dead code -- code that is never invoked.
  • Duplicate code.
  • Unreferenced parameters and variables.
  • Variables that never vary: 'constant' variables.
  • Toughly-coupled code. You can't use a class in isolation because it depends on lots of other concrete classes.
  • Non-cohesive classes and methods. (Classes and methods that do "too much")
  • BUGS
There is in fact a whole list of "code smells" (possible design problems) at http://c2.com/cgi/wiki?CodeSmell. TDD helps prevent some of them, and refactoring with the safety net of tests can allow you to to fix the others. With TDD and Refactoring, you don't have to live with smelly code.
I find that once my tests are passing, I almost never have to go back and fix any bugs later. This saves me a lot of time. At the worse, it takes about the same time as coding + debugging, but it's less stressful. If a bug arises during TDD, it is most likely in code that I wrote less than five minutes ago -- easily found and fixed.

For those people who say they don't have time to write tests, I ask: why do you have time to write dead code, duplicated code, and where does the time to fix bugs come from?

In traditional development and testing, you create a lot of defect-ridden code, and then test the defects out. The underlying assumption is that this is the only way it can be done. Test-Driven-Design works with a different assumption: You can put the quality in first, and not have to spend time getting defects out.

Traditional (maintenance) development, because it usually isn't supported by suites of tests, eventually grinds to a halt: the code becomes so fragile that it can't be modified without breaking something. I don't know if the IRS has depreciation tables for source-code assets, but the reality is that code eventually loses value unless you take steps to keep it from losing value. Sometimes, code becomes unmaintainable while the company is still trying to make money off of it - the result is the company loses money or doesn't get the opportunity to modify the code to make more money.

Test-Driven-Design provides a suite of tests that allows you to refactor - keeping the code maintainable so it is easy to enhance, re-use, etc., so you can make money.

If I Were Advising Someone Forming a Start-up

If I were advising someone forming a start-up, or forming a start-up myself, I'd want to learn a few things first, and then be able to consult certain experts as I continued.

I would learn from this list of books here, in a page created by Steve Blank. Note Kent Beck's Extreme Programming Explained is listed near the top of this list of books, along with The Lean Startup by Eric Ries, and The Startup Owners Manual by Steve Blank. The list of books is quite long, so I'd get summaries of these books and skim through the few I'd buy, digging deeper as needed. Reading them all would take a long time.

I would consult with Esther Derby for team-work and process improvement. And her books:

I would consult with Johanna Rothman for management and hiring. And her books:

There are a variety of legal issues when starting a business. Nolo Press has a lot of advice. I'd get something like The Small Business Start-Up Kit: A Step-by-Step Legal Guide.