Monday, March 12, 2012

6 Tips For Writing (Code)

I came across a list of 6 tips for writing by John Steinbeck: http://www.brainpickings.org/index.php/2012/03/12/john-steinbeck-six-tips-on-writing/ . This struck me as being somewhat applicable to programmers, so I tweeted such. And now, I want to expound on that idea.


Abandon the idea that you are ever going to finish. Lose track of the 400 pages and just write one page for each day. ...
This is all about having a maintainable pace. A maintainable pace is valuable to the writer and the programmer in part because it relieves burnout. But it is also valuable to the editor and Product Owner because it provides an unmatched ability to forecast delivery.

... Never correct or rewrite until the whole thing is down. Rewrite in process is usually found to be an excuse for not going on. ...
This is a partial quote, which indicates that the association between writing an programming is a bit loose. However, it does remind me of Kent Beck's "Make it work, make it right, make it fast." Don't refactor or redesign until you've got enough written to know what you're talking about. You may think you need a set of metric unit types, but unless you've got some code which tells you that you're getting ahead of yourself. Solve only the problems you can prove that you have.


Forget your generalized audience. In the first place, the nameless, faceless audience will scare you to death and in the second place, unlike the theater, it doesn’t exist. ...
I've seen plenty of in-house code which was designed to withstand the application of a malicious or incompetent programmer. It's a waste of everyone's time. You cannot design around a malicious coworker, and you cannot protect yourself against an incompetent programmer. Instead, determine what kind of programmer your organization hires (you, for example), and write code for that person. Your real audience is you two weeks or six months after you wrote the code.


If a scene or a section gets the better of you and you still think you want it—bypass it and go on. When you have finished the whole you can come back to it and then you may find that the reason it gave trouble is because it didn’t belong there.
If you can't think of a good class/method/function/field name, maybe you don't really understand what you're trying to accomplish with it. If you're having problems making your code generic, stop. Come back later when you understand the problem better.


Beware of a scene that becomes too dear to you, dearer than the rest.
This is applicable in nearly every corner of life. Code or architecture which you are attached to becomes difficult to change. Change is the lifeblood of a programmers process. The code changes as your understanding of the problem changes. The code changes as the customer's demands change. The code changes as you learn new techniques. Anchors will drown you in your seas of change.

If you are using dialogue—say it aloud as you write it. 
This relates to naming things, especially systems of things, and especially test methods. When you say the name of a method, it should be easy to turn into a sentence. The receiver is usually the object, the method is usually the verb and adverb. The parameters are usually the grammatical objects. When you follow this advice, you get a rich vocabulary for the domain. And you almost never succumb to Primitive Obsession.


So, there you have it: six tips for writing code. It's an imperfect but useful mapping from creative writing to programming. Programmers can learn much from authors, and maybe we can teach them a thing or two in return. But keep in mind that they've been at it for a few millennia. Us, not so much.

Monday, December 5, 2011

Reducing Extract Method on a Reduce Loop

Let's say you have code like this, wherein totalYs is being used for multiple purposes, including accumulate the Y values within the collection of Xs.


int totalYs = ...;
Collection<X> xs = ...;
... something that uses totalYs ...

for (X x : xs ) {
    totalYs += x.getY();

}
...
process(totalYs);


You can start isolating the Y accumulation (to extract to a method) by introducing a temporary variable.



int totalYs = ...; 

Collection<X> xs = ...;
...

int tmpTotalYs = 0;
for (X x : xs ) {
    totalYs += x.getY();

}
totalYs += tmpTotalYs;
...
process(totalYs);



Then, replace all instances of totalYs within the loop:




int totalYs = ...;
Collection<X> xs = ...;
...

int tmpTotalYs = 0;
for (X x : xs ) {
    tmpTotalYs += x.getY();
}

totalYs += tmpTotalYs;
...
process(totalYs);


Finally, you can extract your method easily, and inline the temporary variable:


int totalYs = ...; 

Collection<X> xs = ...;
...

totalYs += collectYs(xs);
...
process(totalYs);


Now, totalYs is much easier to manipulate. The lure of this transformation is that tests will pass at every step.

BTW, this will work for any associative operation with an identity value in place of addition.

Chris

Wednesday, August 10, 2011

Feedback Loops

Remember when you were in school, and your teacher was handing back your homework? You probably got a number or letter near the top of the paper indicating whether were going to have trouble passing the semester. That was feedback.

And as it happens, one of the worst sort of feedback.

Homework grades suffer from several serious problems: they are fed back to you far too late in the learning process, and they are discouraging when they should be informational.

However, homework grades are a perfect example of one good trait of feedback: they are highly visible.

Feedback is an integral part of a feedback loop, which is any iterative process wherein feedback from one part of the process to alter another part of the process. We use feedback loops to learn in school, such as with homework or test grades. We use feedback loops to learn to play games and music. We use feedback loops to improve at everything we do.

Well, almost everything. When was the last time you evaluated your job performance? That happens once or twice per year, right? And did your job performance improve as a result? Probably not measurably. Oddly, the place we spend most of our waking time is the place we use the fewest feedback loops.

I'm guessing that you or your boss or someone fairly high in your organization's hierarchy wants to increase the ratio of your output value to your output costs. And probably not just once. Improving performance consistently is only possible by learning from the past. And feedback loops are integral to learning.

Agile and lean methodologies evangelize short iterations of production interspersed with customer demos and team retrospection. Notice that this is a simple feedback loop. What's more, this process exhibits some of the best properties of feedback loops: there are natural consequences and the customer responses are simple (if not always pleasant) to consume.

Let's characterize feedback according to whether it is a (non-trivial) metric. A non-metric feedback might be a customer's comments after a demo, or the blinking lights telling everyone that you just broke the build. A metric-based feedback might be a graph of the count of broken builds each day in the last month or a diagram of your bottlenecks in your value stream. Some generalizations may be made about these two classes. A non-metric feedback is generally more useful the closer it is to the behavior it is meant to adjust. A metric-based feedback is often used to detect trends, and thus is more useful for longer-term behavior adjustments.

Other generalizations may be made about feedback in general. It should be relatively simple. It should be highly visible. Feedback is most potent when it takes the form of natural consequences. However, feedback which triggers negative emotions will almost always have several undesired effects. You can create (intentionally or accidentally) a virtuous cycle or a vicious cycle depending on the representation of your feedback. A broken build light will motivate a fix. A broken build stick will motivate not checking in, which is worse than a broken build.

Feedback loops are much easier to maintain whenthe feedback is collected or generated automatically. For metric-based feedback, this usually means having an automated process which regularly processes the relevant data. For non-metric feedback, this means that the process must explicitly capture the data. In the case of gathering customer comments, this may require setting the expectation early in the relationship that every iteration the customer must look at the product and tell you what they think.

The reason we use feedback loops is to measure performance of our systems over time. Metrics-based feedback are used primarily for this purpose. But, why do we care to measure the performance of our systems? To combat overconfidence. Unwarranted confidence damages the ability for people to make decisions, which in turn destroys their ability to deliver. And delivery is what Agile and Lean are all about.

Tuesday, December 28, 2010

Toy Robots and Linux

My lovely wife purchased a LEGO®* Mindstorms NXT 2.0 kit for Christmas for me!! Yay!!

I've got a Mac Mini driving my TV, so I _could_ plug my new toy into there... But, I don't like to stand uncomfortably for long periods of time, so I'd rather plug the brick into one of my Linux machines (laptop, desktop, or netbook). Ah, but the software that comes with the toy does not support Linux. Happily, there is an active community online which likes to play with these two systems together.

My first stop was Da' Goog, where I came across http://www.krizka.net/2009/12/27/starting-mindstorm-nxt-2-0-development-on-linux/. I started following the directions.

However, I was unable to get the udev rule to create the /dev/ device for me. After much gnashing of teeth, I found that the following worked:

SUBSYSTEM=="usb", SYSFS{idVendor}=="0694", SYSFS{idProduct}=="0002", ACTION=="add" SYMLINK+="legonxt-%k", RUN+="/etc/udev/legonxt.sh"
It differs from the original by the omission of 'group.' prepended to 'SUBSYSTEM', and by the used of 'usb' instead of 'usb_device' as the SUBSYSTEM value.

The only other problem that I ran into was that 'nbc' (the compiler/uploader for the NXC and NBC languages) had to be run as root due to permissions issues. I hope to get those figured out. For whatever reason, the script /etc/udev/legonxt.sh, which changes the permissions of the device file, still does not allow my user to access the brick. However, root can do it just fine. 'sudo' is your best friend and worst enemy.

When I get my system set up better, I will post my step-by-step guide. I've got some robot-making to do right now, though...

*LEGO® is a trademark of the LEGO Group of companies which does not sponsor, authorize or endorse this site. Please see: http://aboutus.lego.com/en-us/corporate/fairplay.aspx

Saturday, July 17, 2010

Go And Vim

I love Go in part because they ship with a unit-test system. On the command-line, call 'gotest', and it compiles your stuff and runs your tests. And it's FAST, much faster than any other compiled language I've ever used before.

I also love Vim, for too many reasons to mention here.

I was looking for a way to get continuous testing as part of my development process. And then I remembered :map.



Now, every time I write my file out, I get glorious testing!!

Monday, April 26, 2010

Agile Vs TDD and Pairing

In the past few days, I've seen several people express the idea that Agile => TDD/Pairing (or possibly TDD/Pairing => Agile). I'm guessing that XP (Extreme Programming) is the root of this misconception. I'm going attempt to clear it up here:

Agile is not a programming practice; it is a management attitude.
TDD and Pairing are (distinct) development practices.

But first, let me say that you should not take this as a lesson in any of these topics. Reading this will give you at most a flavor of these topics, and hopefully pique your interest in them.

Let's tackle the simple half first. TDD and Pairing are straight-forward and well served by their names

Pairing is simply two developers sitting at one computer working out a solution together.  I won't get into the cost/benefit analysis here, but I will state that pairing has been wonderful for my productivity and my knowledge.

TDD is slightly more complex. There are three steps: write a test, write some code, and clean up the code. This process is often called 'red, green, refactor', and you end up with a nice cadence of writing short tests, writing small amounts of code, and cleaning up. There are books written about TDD, so clearly there's more than meets the eye here. However, it's still a very simple process once you get the hang of it.

You will notice a distinct lack of any prerequisites in either of the above paragraphs. You don't need anything other than someone to pair with to do pairing, or an test framework to do TDD. Pairing helps you get more work at a higher quality done, but it doesn't fundamentally change how you manage the project. Similarly, TDD helps improve your code quality, and it increases visibility into your code quality. However, TDD doesn't change how you manage your project.

Let's tackle the harder half now: Agile. Agile is not a process, and it's barely a paradigm. Agile is an umbrella which covers (to a greater or lesser extent) several development methodologies (including Extreme Programming, Scrum, etc).

When someone asks if you are Agile, what they should be asking is, "Do you recognize that your clients' needs change, and can you respond to those changes with working software quickly?" This is (according to some of my PMP friends) pretty standard project management stuff, so you wonder why we need to give it a special name. Well, I wonder why we have to give it a special name... That is, in a nutshell, the primary concern of Agile. There are secondary concerns, of course.

The Agile mindset is based around your relationship with your client. But, that relationship informs nearly everything you do as a producer. It pressures you to have greater visibility into your processes, and to abide by shorter release cycles, and a number of other things, too. But, you can increase your visibility and shorten your release cycles and achieve a host of other goals without TDD and without Pairing.

That said, I really think that TDD and Pairing help a bunch.