C. Keith Ray
Keith's Résumé (pdf)
Thursday, September 19, 2013
Writer Ferrets by Richard Bach
Tuesday, September 17, 2013
Fun in the Workplace
I read some years ago in the book A Great Place to Work that a good company allows people to not "be a part of the family" -- it's ok if the workplace is "just a job" -- though I hope it's a job done well.
I don't play pool or foosball at my office; I'm not in the company softball team; and while I wanted to get together with the radio-control-car guys, I was too busy and didn't want my rc-car to get muddy. My wife is still recovering from playing in a softball game for her office a week or more ago.
My preference for "fun" at the office would be people getting together to learn about software methods, design, and so on (topics I plan to write about in this blog). Getting a group of coworkers together to ride go-carts is not my idea of fun.
It appears that some people in Germany are blaming their dot-com collapse on "fun" in the workplace. Noted in Laurent Bossavit's blog pointing to article on Mair's End The Fun.
Mair's office rules seem to have gone too far in the other direction - uniforms required, no calendars or pictures on the walls, half-hour lunches. And this is in an advertising agency?!
I fail to see how uniforms get creative work done better or faster. Doesn't anyone blame to dot-com crash on bad business plans, profit-mongering brokers, and credulous investors?
A Great Place to Work says that the core truth of what makes a company successful, is mutual trust between employees and management. Quoting the preface:
[a great place to work] requires the direct involvement of senior management who must insist that fostering an exceptional work environment is an explicit goal of the organization - one that is on a par with other explicit goals like making a profit or providing high-quality products or services. Being a great place to work cannot be a fad of the month or it will rightfully appear to employees as another version of management by manipulation.
Thursday, August 1, 2013
C May Be Better Than C++ For Your Embedded Application
I have done some coaching of programmers writing C and C++ for embedded systems. The C programmers' target environment didn't have a heap, so C++ new/delete and associated smart pointers were out (and thus, most of C++'s standard libraries were out). But C was an improvement on assembly language for their productivity and unit testing.
The C++ programmers, though they called their target environments "embedded," really had lots of memory and full-fledged Linux or Linux-like operating systems. So they could use C++ instead of C for programming. But my experience helping them has showed me that very few programmers know how to write code that uses C++ safely (as in exception-safe code). Often their use of C++ was a hindrance to productivity, testability, and execution-efficiency.
If I could go back in time to advise those C++ embedded teams on the choice of their programming language, I'd recommend C instead of C++. It's seems like it is harder to write untestable, inefficient code in C, compared to the nightmares I've seen in C++. I've noticed that C programmers seem more pragmatic than many C++ programmers. The C++ programmers often have rules in their heads about the "right" way to code, that they have to unlearn if they want to write testable, efficient code.
If average-skilled C++ programmers could be trusted to use C++ as a "Better C" (which is how C++ used to be marketed), I would recommend that.
I'm currently programming in Objective-C with ARC. I could be blending Objective-C with C++ (just change the source file suffix to ".mm") , to take advantage of C++'s "Better C" advances in type-checking, but so far, I'm OK with the C part of Objective-C. Unit tests have found some of the issues with C's less-powerful type-checking the C++ compiler could have caught.
ARC takes Cocoa's semi-manual memory management and automates it, so I no longer have to write retain, release, or autorelease. If I didn't have ARC, I would seriously consider using C++ smart pointers to manage Objective-C memory usage. Some would view smart-pointers plus Objective-C as a worse solution than explicitly using retain and release, but manual or semi-manual memory management is very error-prone.
Thursday, June 13, 2013
Book Titles that may be More Interesting than the Books they Came From
A list of titles I found interesting, when looking at a mish-mosh of old books, some time ago.
- Labors of Love
- Proud Destiny
- Just In Case
- Natural Acts
- Education and Ecstasy
- The Cannibal Galaxy
- A Year in Upper Felicity
- The Land of Milk and Omelets
- Fly Boys
- Indian Killer
- The Formula
- Moon Deluxe
- Four Doctors
- The Outsider
- The Fourth Dimension is Death
- Dropping Your Guard
- Dark History
- The Crystal Towers of the Moon
and a title I could have used when writing about refactoring:
- From Jungle to Garden: cutting down long methods and large classes.
Wednesday, May 1, 2013
The Purpose of Unit Tests Is Not Recreating the Entire Running Environment
One of the "Aha!" experiences/epiphanies of a programmer I was working with, was the realization that a unit test only needs to test a "unit". He had been setting up real-life data, when a little "fake" data would verify the desired behavior.
Unit testing also makes the code more robust, because side-effects that might not be seen in a system test, can be found by unit tests exercising all the edge-cases for each function or behavior being tested—particularly testing situations that are hard to replicate in the real system.
Saturday, April 27, 2013
Command Pattern
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
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:
- Think about what we want to the program to do.
- Write a test that shows some aspect is done.
- 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).
- Write the smallest amount of code to make that test pass.
- Run the test, hopefully see if pass. (If it doesn't, fix the problem.)
- Refactor to clean up the code.
- Run the test again, to make sure refactoring didn't break anything.
- 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.
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
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:
- Behind Closed Doors: Secrets of Great Management by Rothman and Derby, and
- Agile Retrospectives: Making Good Teams Great by Derby and Larsen.
I would consult with Johanna Rothman for management and hiring. And her books:
- Hiring Geeks That Fit,
- Hiring The Best Knowledge Workers, Techies and Nerds, and
- Manage It!: Your Guide to Modern, Pragmatic Project Management.
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
Wednesday, January 9, 2013
Basic Unit Testing in Objective-C
When you create an iOS or MacOSX project in Xcode, you have the option of creating unit tests, which you can use to verify your code without manual intervention.
Here's an example...
STAssertTrue(TRUE, @"TRUE should be true");
STAssertTrue(FALSE, @"This assert should fail");
If we build and run the tests, Xcode will compile and run these tests.
Note 1: Declares a class that has SenTestCase as its parent class. Nothing else needs to go here.
Note 4: This test will fail, because FALSE is not true and the assertion STAssertTrue expects the first parameter to be evaluated to true.
The the tests are executed, Xcode will highlight the lines of code where the failing assertions are. We have just one failure; it looks like this:
The failure output tells us the expression FALSE is expected to be true (in this test), but is actually not true. The output also includes the string supplied as the second argument to STAssertTrue.
When I had Xcode generate the project and create the initial unit test code, it created two files: IntroductionToObjectiveCTests.m and IntroductionToObjectiveCTests.h. A header file (.m) to declare the interface of an objective-c test case, and a source file (.m) implementing the test case. I moved the class interface declaration to the .m file and deleted the .h file, because we don't need it. The .h would only be needed if I had written code in multiple .m files that needed to see the class interface declaration.
Why doesn't the test framework need to see the class interface? Magic. When the test code is executed, the test framework looks for classes and methods at runtime. The framework says something like "Give me a list of all your classes that have SentTestCase as their parent class, and give me the list of methods that start with 'test'. Let's execute those test methods."
SenTestingKit also outputs information to the Console. This is what it looks like for these tests:
Saturday, October 27, 2012
Agile Limerick 1
I got certified as a Scrum Master,
To make my projects go faster,
But the code was mess,
Never refactored, I guess,
So Agile, for us, was disaster.
Monday, June 11, 2012
Technical Reviews, More on Test Driven Design
Scott's essay on TDD is up here and Ron Jeffries's critique is [gone]. I'll have more to say about it after reading it a couple of times.
That recent issue of STQE Magazine also has a great short essay by Jerry Weinberg on technical reviews being a learning accelerator. One thing I want to point out is that junior programmers should be reviewing the work of master programmers, not necessarily to find errors, but to learn from the master - and of course, master programmers can make mistakes too, which are often visible to junior programmers as well as other master programmers. If the master programmer is humble, he/she can learn from a junior programmer, too.
I've been reading Weinberg and Freedman's book on the subject of technical reviews Handbook of Walkthroughs, Inspections and Technical Reviews (which was written in FAQ style - question/answer), and was a bit surprised by their recommendation that when people are being trained on how to technical (code) reviews, they should have some practice at conducting a review in the presence of hidden agendas.
Some examples of hidden agendas in code reviews: person A wants to impress person B. Person B wants to make person C look bad. Person C needs to go to the restroom, but doesn't want to say so. Person D is distracted by illness of his/her spouse.
Only Weinberg would write about hidden agendas in code reviews - too many writers and books on software development practices seem to assume that people act like machines.
On Weinberg's SHAPE forum, Charlie Adams wrote: "When people are getting tense about their software being reviewed, use Jerry's phrase, 'Yes, I trust your honesty, but I don't trust your infallibility. I don't trust anyone's infallibility.' (Quality Software Management: Anticipating Change: page 220) In my experience this has always calmed the atmosphere and allowed us to examine the code rather than the developer."
While I have done code reviews, both informal and formal, I prefer pair programming. It combines reviews with collaborative design, testing, and coding. Rather than go into all the reasons why pair programming is good, I'll point you to www.pairprogramming.com and Pair Programming Illuminated.
Thursday, February 16, 2012
Available and Seeking Employment
I am now extremely interested in getting back into product development and away from Agile Coaching. I am particularly interested in programming for the iPad and iPhone and Macintosh, and I would appreciate it if you, a reader of this blog, consider me for "mobile" or "Macintosh/cross-platform" Senior Software Developer positions.
As a technically-oriented Agile Coach for the last 5 years, I have helped teams reduce their bug counts and increase their rate of feature implementation. When I coach a team, I dive into the source code, quickly analyze and understand it, and help the team refactor it for testability and improved design. I help them write unit tests and teach them test-driven development; and provide instructions in other parts of an Agile software development process using Scrum and XP practices.
I have coached whole teams (managers, programmers, testers) at clients including Google using C++ and Python on Linux, IronKey using PHP, C, and C++ on Linux and Windows, Nokia-Siemans Networks in C++, and Schlumberger in C# and C++ on Windows, and Huawei in C++, and provided training to developers at these and other companies including HP.
Previous to working as an Agile Coach, I have worked on whole life-cycle projects at
- Apple, in C and C++,
- Intuit, using Objective-C, Cocoa, Carbon and C++,
- Electronics for Imaging, in C++ and Java on Mac and Windows,
- Hoffbauer Inc., my first use of Objective-C on NeXTStep (the ancestor of Cocoa and CocoaTouch),
- Ideal Learning, using Object Pascal, Object C, and C++, and
- Kodak Health Imaging Systems, in C++ on Mac and Unix.
- Pixera, a digital camera startup, in C++ on Mac and Windows.
While at Google, I contributed code to Google's open-source C++ test framework gtest and provided technical reviews of Google's open-source C++ mock-objects framework gmock.
