I just received my May issue of MacTech Magazine, and I have two articles in this issue. Part II of my RubyCocoa article and an overview of the iPhone SDK (at least, what I can talk about without violating my NDA).
Hopefully I'll be able to talk a lot more about the iPhone SDK soon. However, I can safely say, good things are coming.
-Rich-
Tuesday, May 13, 2008
Saturday, May 3, 2008
The problem with JUnit
I'm a big unit test fan. However, I often feel that the goals of testing run counter to the goals of good Object Oriented design. At least in static languages like Java.
Object oriented design is based on the idea of encapsulating behavior. Testing is an attempt to reveal and examine behavior. You can't have both.
I often run into this problem when implementing algorithms inside an object. From an OO perspective, I often want to declare all the methods that perform the scary math as private. They should never be called from the outside. However, I really need to test them somewhere.
Problems also crop up when calling methods that change an object's state. The state is not always directly exposed, and sometimes it's nearly impossible to indirectly detect the change.
I don't feel the same tension when testing in dynamic languages like Ruby. Usually, these languages have a stronger reflexion or metaprogramming functionality. They let me safely encapsulate the things that should remain hidden, but still allow me to pry my objects open and root around in the guts.
I can write tests using reflection in Java, but the syntax is painful. I can get around that with a library of helper methods--but for some reason, reflection makes many Java developers uncomfortable, even when only used in testing. And, truth be told, it never feels as natural as the dynamic language tests.
Similarly, I can use a mixture of interfaces and mock objects (for example, using EasyMock) to let me examine the inner workings of a class. Often this simplifies writing the tests, but the results can be incredibly brittle. Building useful mock objects generally requires a detailed understanding of our classes inner workings. If I change the implementation, I will break my mock objects, and then break my tests--even if the new version is functionally identical to the old.
Of course, even the reflection-based testing is somewhat brittle. Reflection, by definition, looks at the implementation, not the interface. But, our interactions with the implementation tend to be more surgical and specific. So, while these tests are somewhat brittle, they tend to be more resilient than the mock-object versions.
I can try to get around all these problems by redesigning my objects. Move my algorithms to a utility class, where they are publicly exposed and easy to test, or add accessors to the internal state, even if the accessors should never be used for non-test code. While this works, it can lead to unnecessarily awkward designs, or exposing more of the implementation than is really necessary.
I think, ultimately, a mixed approach is best. Like many software engineering tasks, we must examine our design and decide which sections are likely to change, and which are likely to remain the same. Static sections can often be effectively tested using reflection or mock objects. Sections that are likely to change should be encapsulated and tested as separate objects.
The trick is then to successfully separate one from the other.
Object oriented design is based on the idea of encapsulating behavior. Testing is an attempt to reveal and examine behavior. You can't have both.
I often run into this problem when implementing algorithms inside an object. From an OO perspective, I often want to declare all the methods that perform the scary math as private. They should never be called from the outside. However, I really need to test them somewhere.
Problems also crop up when calling methods that change an object's state. The state is not always directly exposed, and sometimes it's nearly impossible to indirectly detect the change.
I don't feel the same tension when testing in dynamic languages like Ruby. Usually, these languages have a stronger reflexion or metaprogramming functionality. They let me safely encapsulate the things that should remain hidden, but still allow me to pry my objects open and root around in the guts.
I can write tests using reflection in Java, but the syntax is painful. I can get around that with a library of helper methods--but for some reason, reflection makes many Java developers uncomfortable, even when only used in testing. And, truth be told, it never feels as natural as the dynamic language tests.
Similarly, I can use a mixture of interfaces and mock objects (for example, using EasyMock) to let me examine the inner workings of a class. Often this simplifies writing the tests, but the results can be incredibly brittle. Building useful mock objects generally requires a detailed understanding of our classes inner workings. If I change the implementation, I will break my mock objects, and then break my tests--even if the new version is functionally identical to the old.
Of course, even the reflection-based testing is somewhat brittle. Reflection, by definition, looks at the implementation, not the interface. But, our interactions with the implementation tend to be more surgical and specific. So, while these tests are somewhat brittle, they tend to be more resilient than the mock-object versions.
I can try to get around all these problems by redesigning my objects. Move my algorithms to a utility class, where they are publicly exposed and easy to test, or add accessors to the internal state, even if the accessors should never be used for non-test code. While this works, it can lead to unnecessarily awkward designs, or exposing more of the implementation than is really necessary.
I think, ultimately, a mixed approach is best. Like many software engineering tasks, we must examine our design and decide which sections are likely to change, and which are likely to remain the same. Static sections can often be effectively tested using reflection or mock objects. Sections that are likely to change should be encapsulated and tested as separate objects.
The trick is then to successfully separate one from the other.
Wednesday, April 9, 2008
Interested in Nu
If you haven't already, check out Nu. A LISP variant, implemented in Objective-C with heavy Ruby sensibilities. It's like all of my favorite things, rolled into one.
Well...It would be nice if it had XCode support. And it's seems a long ways away from a 1.0 release. Still, it looks quite interesting.
-Rich-
Well...It would be nice if it had XCode support. And it's seems a long ways away from a 1.0 release. Still, it looks quite interesting.
-Rich-
Monday, March 24, 2008
Time Machine Update Update
Nope, my wife's computer has been refusing to do backups since shortly after the 10.5.2 update. Apparently, she got tired of seeing it complain, and just shut it off. Anyway, it's not just me.
Wednesday, March 19, 2008
Time Machine Update
Here are a few things I've learned about Time Machine since writing the article.
1) I had to send my MacBook in for repairs. Apple replaced the logic board. Therefor, I had a new ethernet MAC address. Therefor I could no longer access my backups. I found some hackish instructions online that helped me fix it. But, I told them that I had backups when I sent it in. If they had wiped my hard drive, I would have panicked.
2) When booting from a Leopard DVD, I did not have the option to restore from backup. The problem seems to be, I need to setup the wireless to connect to the network, and I need to log into the host machine before getting access to the backup bundle. The software on the Leopard DVD simply doesn't give me the option to do that.
In the end, I erased and reinstalled OS X on the machine. Set up a dummy account. Used that account to access the network and log into the host machine. Then I connected to the time machine backup and restored all my data.
I think there may be a better option here. I think I spotted something that suggested connecting the drive directly (even though you typically cannot connect the hard drive directly if you've been doing remote backups). I don't know. It sounds sketchy to me. But it might be worth a try the next time a machine goes down.
3) 10.5.2 seems to hate Time Machine. Since upgrading, my backup has become more and more unreliable, and has taken longer and longer. Finally, it stopped working entirely. I couldn't even mount the bundle anymore. I let Disk Warrior work on it for three days. It reported over 50,000 errors, but wasn't able to do anything useful. In the end, I had to delete the bundle and start from scratch.
Actually, it may have been the hacks I mentioned in step 1 that eventually killed it--but I don't think so. Other people seem to be having the same problem. I thought 10.5.2 was supposed to improve Time Machine stability.
4) While I cannot mount my backup sparse bundle directly on the host machine, I can mount any backup bundle from any remotely logged in machine. No password needed. That's kind of scary.
That's it. If you have any other tidbits, list them in the comments.
-Rich-
1) I had to send my MacBook in for repairs. Apple replaced the logic board. Therefor, I had a new ethernet MAC address. Therefor I could no longer access my backups. I found some hackish instructions online that helped me fix it. But, I told them that I had backups when I sent it in. If they had wiped my hard drive, I would have panicked.
2) When booting from a Leopard DVD, I did not have the option to restore from backup. The problem seems to be, I need to setup the wireless to connect to the network, and I need to log into the host machine before getting access to the backup bundle. The software on the Leopard DVD simply doesn't give me the option to do that.
In the end, I erased and reinstalled OS X on the machine. Set up a dummy account. Used that account to access the network and log into the host machine. Then I connected to the time machine backup and restored all my data.
I think there may be a better option here. I think I spotted something that suggested connecting the drive directly (even though you typically cannot connect the hard drive directly if you've been doing remote backups). I don't know. It sounds sketchy to me. But it might be worth a try the next time a machine goes down.
3) 10.5.2 seems to hate Time Machine. Since upgrading, my backup has become more and more unreliable, and has taken longer and longer. Finally, it stopped working entirely. I couldn't even mount the bundle anymore. I let Disk Warrior work on it for three days. It reported over 50,000 errors, but wasn't able to do anything useful. In the end, I had to delete the bundle and start from scratch.
Actually, it may have been the hacks I mentioned in step 1 that eventually killed it--but I don't think so. Other people seem to be having the same problem. I thought 10.5.2 was supposed to improve Time Machine stability.
4) While I cannot mount my backup sparse bundle directly on the host machine, I can mount any backup bundle from any remotely logged in machine. No password needed. That's kind of scary.
That's it. If you have any other tidbits, list them in the comments.
-Rich-
Tuesday, March 4, 2008
Sometimes I think Apple's out to get me!
So, I write an article about installing Ruby for Rails on Tiger. Then Apple announces that RoR will be included in Leopard.
Then I write an article about using TimeMachine over a wireless connection. Just days after the magazine hits the stand, Steve Jobs announces Time Capsule.
Now, I've just finished a pair of articles on RubyCocoa. They haven't even been published yet, but Apple's already at it again.
Today, I just learned about a new, open source project backed by Apple, called MacRuby.
MacRuby is a Ruby 1.9 port that runs on top of Objective-C. It's not ready for prime time yet, but it looks promising. First off, it is Ruby 1.9--which I think is a great thing. Among other things, this means it will be much, much faster than RubyCocoa, which uses Ruby 1.8.
From there, things get really interesting--and just a bit odd. All MacRuby objects are subclasses of NSObject. Because of this, they inherit all the base object methods from both Objective-C and Ruby. They've also added an expanded syntax for keyed attributes in method calls.
So,
becomes
or
You can even write your own classes in Ruby that use keyed attributes:
Of course, you can do all the cool RubyCocoa tricks. Make calls back and forth between the Objective-C and Ruby portions of your code. Import Cocoa frameworks. Etc. But, in MacRuby, it all looks just a little bit tighter.
For example, MacRuby's String, Array and Hash classes are simply subclasses of Objective-C's NSString, NSArray and NSDictionary. This lets you transparently pass objects between Ruby and Objective-C.
I look forward to playing around with this project as it develops.
-Rich-
Then I write an article about using TimeMachine over a wireless connection. Just days after the magazine hits the stand, Steve Jobs announces Time Capsule.
Now, I've just finished a pair of articles on RubyCocoa. They haven't even been published yet, but Apple's already at it again.
Today, I just learned about a new, open source project backed by Apple, called MacRuby.
MacRuby is a Ruby 1.9 port that runs on top of Objective-C. It's not ready for prime time yet, but it looks promising. First off, it is Ruby 1.9--which I think is a great thing. Among other things, this means it will be much, much faster than RubyCocoa, which uses Ruby 1.8.
From there, things get really interesting--and just a bit odd. All MacRuby objects are subclasses of NSObject. Because of this, they inherit all the base object methods from both Objective-C and Ruby. They've also added an expanded syntax for keyed attributes in method calls.
So,
[person setFirstName:first lastName:last];
becomes
person.setFirstName(first, lastName:last)
or
person.setFirstName first, :lastName => last
You can even write your own classes in Ruby that use keyed attributes:
def setFirstName(first, lastName:last)
@name = "#{first} #{last}"
end
Of course, you can do all the cool RubyCocoa tricks. Make calls back and forth between the Objective-C and Ruby portions of your code. Import Cocoa frameworks. Etc. But, in MacRuby, it all looks just a little bit tighter.
For example, MacRuby's String, Array and Hash classes are simply subclasses of Objective-C's NSString, NSArray and NSDictionary. This lets you transparently pass objects between Ruby and Objective-C.
I look forward to playing around with this project as it develops.
-Rich-
Sunday, March 2, 2008
Review of The Unofficial Lego Mindstorms NXT Inventor's Guide
I love the Lego Mindstorm kits, and I've always enjoyed No Starch Press's books. So I was excited to hear about their Unofficial Lego Mindstorms NXT Inventor's Guide (ULMNIG). These are two great tastes that taste great together.
Unfortunately, I was led a bit astray by the title. "Inventor's Guide", to me, summons mental images of crazy legos hacks, but that's not the goal of this book.
In the introduction, the ULMNIG describes its true intentions--taking you beyond the user guide and instructions that came with the Mindstorm kit. It does not assume any previous experience with Lego or Mindstorms, but helps you explore a broader range or projects and possibilities.
As an entry level book, I think the ULMNIG overwhelmingly succeeds.
The book starts with a description of the lego pieces, then provides basic guidelines for building sturdy structures and functional gear trains. For me, this was the weakest part of the book. Don't get me wrong. It has solid information, and should be useful for beginning builders. But it felt too short and too superficial for my tastes.
The ULMNIG then spends two chapters exploring the NXT-G programming language in detail. If you are going to use NXT-G, then you need to read these chapters. They provide a lot of information that will help you get the most out of your Mindstorm brick. They are also much clearer and more informative than the user manual. Reading these chapters will save you from hours of frustrating trial and error.
Finally the last half of the book covers six new robot designs. Four of these designs are radically different from each other. One is a differential drive with a ball castor. One is a four-wheeled steering vehicle. One is a six-legged walking motion sensor, and one is a stationary bot. There are also two variations on the differential-drive bot.
This gives you a nice combination of projects. The designs increase in complexity, allowing you to improve your skills as you progress through them. Building them will teach you a wide range of design techniques, while the variations show you how you can modify existing designs for other purposes.
The projects are definitely the highlight of the book. Working through the projects will teach you more about building robots than the rest of the book combined. And, once your finished, you should be ready to jump into your own projects.
Unfortunately, advanced builders/programmers might find themselves somewhat disappointed with this book. The ULMNIG hints at several advanced topics: building dynamic structures and third party programming languages. Unfortunately, these only get the briefest introduction. A few paragraphs each, tops. And the ULMNIG doesn't even mention other advanced topics, like third-party sensors and hardware, or attaching your own circuits to the NXT brick.
So, I would not recommend this book for everyone. But, if you've finished all the projects in the Mindstorm Users Guide, but your still struggling to build your own robots, then this is definitely the book for you.
-Rich-
Unfortunately, I was led a bit astray by the title. "Inventor's Guide", to me, summons mental images of crazy legos hacks, but that's not the goal of this book.
In the introduction, the ULMNIG describes its true intentions--taking you beyond the user guide and instructions that came with the Mindstorm kit. It does not assume any previous experience with Lego or Mindstorms, but helps you explore a broader range or projects and possibilities.
As an entry level book, I think the ULMNIG overwhelmingly succeeds.
The book starts with a description of the lego pieces, then provides basic guidelines for building sturdy structures and functional gear trains. For me, this was the weakest part of the book. Don't get me wrong. It has solid information, and should be useful for beginning builders. But it felt too short and too superficial for my tastes.
The ULMNIG then spends two chapters exploring the NXT-G programming language in detail. If you are going to use NXT-G, then you need to read these chapters. They provide a lot of information that will help you get the most out of your Mindstorm brick. They are also much clearer and more informative than the user manual. Reading these chapters will save you from hours of frustrating trial and error.
Finally the last half of the book covers six new robot designs. Four of these designs are radically different from each other. One is a differential drive with a ball castor. One is a four-wheeled steering vehicle. One is a six-legged walking motion sensor, and one is a stationary bot. There are also two variations on the differential-drive bot.
This gives you a nice combination of projects. The designs increase in complexity, allowing you to improve your skills as you progress through them. Building them will teach you a wide range of design techniques, while the variations show you how you can modify existing designs for other purposes.
The projects are definitely the highlight of the book. Working through the projects will teach you more about building robots than the rest of the book combined. And, once your finished, you should be ready to jump into your own projects.
Unfortunately, advanced builders/programmers might find themselves somewhat disappointed with this book. The ULMNIG hints at several advanced topics: building dynamic structures and third party programming languages. Unfortunately, these only get the briefest introduction. A few paragraphs each, tops. And the ULMNIG doesn't even mention other advanced topics, like third-party sensors and hardware, or attaching your own circuits to the NXT brick.
So, I would not recommend this book for everyone. But, if you've finished all the projects in the Mindstorm Users Guide, but your still struggling to build your own robots, then this is definitely the book for you.
-Rich-
Subscribe to:
Posts (Atom)