Archive for the 'general programming' Category

10
Jan
08

When (not) to document?

Documentation, it’s a boring job, but someone has to do it, right?  That’s what process advocates say, but maybe that view is overstated.  To think about that question, consider the reasons and flaws of documentation.  On the plus side, it’s hard to argue documentation is bad; it’s additional data.  In theory, documentation helps others understand something non-intuitive.  Managers hope documentation will allow replacement of one employee with another.  They say in case of accident (“hit by a bus”), but we know the reason is in case one employee quits or demands more money.  In another case, it educates users, and reduces the need for hands on training.

Documentation doesn’t always live up to those goals, but it at least partially accomplishes them.  But I see two primary problems with over-documentation.  The first, it is better not to need documentation, then to have it.  A goal of 100% documentation not only distracts from the quest to reduce it’s need, but as I’ll explain, it’s often an obstruction as well.  The second problem, is time.  Creating, maintaining, organizing and disseminating documentation is time consuming.

The second problem is obvious, and there is little to be said.  Each project must make it’s own decisions on when and how much documentation is appropriate.  Whatever that decision is, insure the entire lifecycle of documentation cost is considered.

The idea of fulfilling the goals of documentation through intuitive design is much more interesting.  It’s a commonly accepted practice in the development world that the design of classes, method names and other elements of code should strive to not need documentation. 

If you have the choices of creating a method void Execute(byte[] array, string input), and then providing documentation stating, “The Execute(ref byte[] array, string input) method reads the contents of a file with the input path input into a byte array, array.”, or simply creating a method byte[] ReadFromFile(string filePath) with no documentation, any rational developer would choose the second.

It’s not impossible to do both, especially in the case above, but it can be difficult.  I already pointed out it’s time consuming, but documenting what doesn’t require documenting is most tedious.  Repetition is the fuel of tedium, so don’t repeat yourself.

It’s not just code that benefits from the rule of eliminating the need for documentation.  The highest goal of any user interface designer should be an application that is intuitive, an application that trains the user through use.  RTFM is a nice phrase, but it’s been repeated so many times we should question it’s wisdom.

16
Nov
07

Browser Bias

Jeff Atwood writes about the higher expectations users have of internal software due exposure to Internet software.

It’s a good point, but there remains a stone unturned.  Why do users, who have no knowledge of the technical details, proclaim browser based software to be better.  One simple reason is, the internal software they were subjected to was not browser based, many times having been written before those tools were available.

Internal software sucks not because it’s not written in Javascript.  No, it sucks because no one cares enough to fix it.  Management can’t put a cost benefit study behind the fixes, users can’t switch to another platform, and developers aren’t half as motivated to create a piece of software for that overpaid salesperson (every company has at least one), as they are to create a piece of software that might bring them fame and fortune among the wider world.  And we haven’t even begun to consider the consequences of scale.

Thus internal software sucks, and when compared to a project someone loves, it looks horrible.  And that explains the irrational bias I’ve observed among pundits, executives and “hip” users toward browser based software.

22
Jun
07

Agile Architects and Agile Developers

I’ve been experimenting with agile development practices for the past year. Actually it’s longer than that, but I never called them agile practices before, and some I had never tried before. It’s been slow going because I get to do less and less development all the time.

I have however been happy with the results. Test Driven Development emerged somewhat naturally from a greater focus on unit tests, and more coding in unit test friendly languages, rather than the unit test agnostic C++.

Ironically, my only opportunity to conduct pair programming has not been the two-coders in a room together situation, but one with me in Chicago and the other half in California. It did however work extremely well despite the separation. My second monitor was invaluable, and the biggest regret was my California compatriot was stuck with only one monitor. A more hands free audio setup would have helped too.

The reason I’m losing my development time is because I have more and more responsibilities as an architect, and while I don’t intend to ever let go of coding entirely, I do have to approach it with a different purpose these days. I code to support the architecture; to educate, to demonstrate and to investigate. I unfortunately must leave delivery up to others. It’s not just a matter of insuring I don’t have a 48/7 job, but also a vexing realization that allowing delivery to depend upon me is not wise. I can’t readily abandon an architectural duty, but just as much cannot allow delivery to be held up by my other duties.

So I must settle for helping out when possible, hoping the developers will respect my talents enough that they won’t go to waste. That’s difficult because it’s not something that comes easy to most developers. When it works some of my experience is added to that of the developers but delivery remains non-dependent upon me. When it doesn’t it’s a waste, but that’s life eh?

My approach to architecture so far has been very common sense based. Some organizations seem to think they can improve upon this through a “framework” or process like FEAF or Zachman. Truthfully I find none of these appealing. They’re rigid in a way that doesn’t relate well to any successful architect I know. I think they are worthy of reading and understanding, but I don’t think they’re worthy of practicing. They attempt to take everything an architect might ever want to do, and sequence it. This means there’s plenty of good ideas. The bad idea is trying to do all of them all of the time, and in a specific order.

Maybe I’d like them better if they were called Enterprise Architecture Grab Bags.

I see the general advice from the agile architecture group as far more reasonable. An EA framework in my opinion is at best a reference tool, where the principles of agile architecture are better daily guides. Many match with my own common sense approach, and approaches of successful architects.

  1. Value People
  2. Communicate!
  3. Less is More
  4. Embrace Change: Plan It, Manage It!
  5. Choose the Right Solution for the Enterprise
  6. Deliver Quality
  7. Model and Document in an Agile Fashion

My daily conundrum is the balance of the first three principles. On one hand I’m constantly pressured to include everyone and to communicate to all of them. On the other hand I believe less is more applies to meetings, not just models. You want to give everyone the opportunity to contribute, but the process of evolving solutions happens more effectively when a core group can follow a specific path without interruption or diversion.

That is a tough balance, but possibly the most important one because if you can find it, and you have the right people, you’ll be able to plan for change better, choose the appropriate solutions and deliver quality.

The right people is a key point. It’s not just that they need to be smart either. They need the right attitude. Although there may be a love-hate relationship between agile architects and agile developers, I think the pair is ideal, at least better than EA architects and waterfall developers.

There is significantly higher conflict between agile architects and waterfall developers. The architect will be pushing for change, pushing for open communication, and pushing for participation. True waterfall developers won’t participate, they’ll wait. That is what they are accustomed to being forced to do, so why not? Developers a little less than true waterfall will participate some, but they’ll doggedly fight against change. They’re still thinking in the time boxed fashion of waterfall development, so the future value won’t align with their value system.

I’m unsure of the interaction of EA architects and agile developers. I think there are a few possibilities. In one case the EA architects employ a full governance process. I can’t even fathom how a developer who complies with such a process could still be considered agile. The only way I see it possible to practice agilism under such a regime is to rebel, which is likely to end in early termination.

In a slightly less restrictive version of EA I expect developers would push on with early development. At some point the architects would get involved and either kill the development, re-task it as a prototype, or let it slide. If they let it slide it won’t comply with any of the EA principles, goals or designs. It’s not a totally dysfunctional system, but either most of the work of the EA architects is wasted, or a great deal of developers work is wasted.

Systems with more open communication would have developers participate in the creation of the architecture, and architects contribute to the direction of development.

21
Jun
07

Getting into the "Zone"

For a long time all programmers preferred an isolated, sound insulated office.  It may not have been quiet but if it wasn’t it was full of music.  More recently some programmers prefer group work environments.

Different people have different preferences, but as different as these two practices appear on the surface, I think they’re a lot alike in ways that keep them totally separate from cubicle land.

Both environments offer predictability. 

  • Total quiet and solitude, or a consistent group of nearly always available companions.  In cube farms half the people are at meetings and there are so many coming and going.
  • In cube farms people sometimes invite people to their desks to talk about things you don’t care about or sometimes they’re on the phone.   In a group environment conversation is either social and inclusive, or relevant.  In a solo office it’s the same.  People only butt in when it’s relevant.

Predictability allows you to get to and stay in the zone.  A solo office is best for the straight to the keyboard thought for sure, but a group environment doesn’t do too bad.  Cubes are the worst because it’s one little thing after another, all unrelated.

Group environment excel at the bounce.  Work, think, talk, work, think, talk.  If you have a question answered, or need to answer one the process goes quick, there’s no thinking about a meeting, or stopping for a meeting, or wondering when your next meeting is.  Get the question done and back to work.  That’s a bit harder with solo offices, but at least there’s no conference rooms to worry about.  You can go by and (if they exist) peek through the window to see if someone’s busy.

In cubes, stopping by is higher cost to you, to the person you’re approaching, and to everyone in the surrounding area.  Worst of all, it’s unpredictable.  And thus comes the meeting to false rescue.  The lead life saver.  Meetings are supposed to be predictable, but their the exact opposite.  With a bunch of people, or even a few, coming from diverse locations their start times are bound to be vary by 5 minutes.  If you want them to start on time everyone needs to try to get there 5 minutes early.

Once there, you might be lucky enough to have functioning equipment, all the necessary materials, and someone who still remembers why you’re meeting in a clear enough form to start the discussion.  Worst of all, the only generally reliable thing, the end time, is no good.  It’s no good because it eliminates the predictability of leaving a conversation with answers.  But since someone has booked the conference room right after you …

P.S. This post was inspired by reading Geek Management @ killthemeeting

04
Feb
07

For the non-omniscient

In response to XML/JSON Futures and FormalitiesDouglas Crockford writes a rather humorous post,

I don’t think it makes sense to infect applications with a lot of complexity on the chance that we will discover intelligent life on Mars and that they would be into ecommerce and not so much into extermination. That’s why I like JSON. It lets me express data with appropriate structure, cleanly and efficiently. Anything else just seems alien to me.

While I find it a very amusing, I hope Douglas, and his readers didn’t miss the point that here on earth there are plenty of examples of either unknown, or difficult to research and standardize subjects.  Something so seemingly simple as an address or a phone number could take weeks to research all the international variations in order to create an application that has some hope of being usable internationally without significant modification.  We don’t need interplanetary travel, or even international travel to find subjects that have need for extensibility of this fashion.

01
Feb
07

XML/JSON Futures and Formalities

I’m somewhat lukewarm about the XML vs JSON debate. I’ll admit, from a straight reading perspective I usually find JSON more attractive. But in the end it all seems somewhat minor when compared to all of the work invested in XML.

At some point you need to reinvent the wheel, but I’m not sure JSON is to the point that justifies this yet. I’d personally hope that before the long road of redoing everything people have done in XML in JSON is undertaken that we could take a hard look at JSON itself and make sure it’s really really right.

Once you start down that road, you can’t fix JSON anymore than you can fix XML. Maybe it’s too late already.

On a less “in the clouds” note, reading Dave Meginson, Douglas Crockford and Don Box made me think. Megginson says there is only a syntactic difference (and community differences), but I think that’s wrong. In the section “Additional node attributes” the difference is clear. Things that are ad-hoc in one format are formalized in other formats.

While this may seem minor, it definitely surpasses syntax. Ad-hoc conventions do not convey the same level of information as formalized conventions do. Formalized conventions can be safely used as an additional meta-layer, where ad-hoc must be handled carefully.

Where are the formats different? JSON and LISP formalize the strongly typed list, where XML formalizes the loosely typed list. Douglas Crockford’s response illustrates this quite well as his solution highlights the JSON strength of a strongly typed list with “people: [...]“. Every item inside those brackets becomes a singular type because there is no formal mechanism to indicate any differentiation.

At the same time it highlights the weakness in the lack of formalization of the elements. Crockford’s refactoring of Megginson’s example works because in our society male names and female names are the same type. However, if instead you used an example of something like “Earth name”, and “Martian name”, the example makes more sense. We know what earth names are and could define the structure of those fairly well today. But we can’t write a structure for Martian names yet because we don’t know much about them. If we want to have any chance of supporting Martian names in the future, we need a typed list that lets us separate our earth names from the Martian names.

We can by informal or exterior convention specify a single name value pair, such as origin-planet to query upon, but if that’s not communicated clearly and universally we’ll always be afraid to add Martian names because someone may not have got the memo.

Just for giggles, I’ve taken a stab at a format modification that might accomplish both these goals, though I have not yet given it even one percent of the thought such a thing really deserves, but here’s the concept:

“people”= [
{"EarthName": lang="it", given="Anna Maria", surname="Mozart"}
{"MartianName": alphabet="#", ["Translations":
{dayOfWeek="Monday", earthTranslation={"EarthName": lang="en", given="who"}}
{dayofWeek="Tuesday", earthTranslation={"EarthName": lang="en", given="tfatf"}}
]}
]

["EarthNames":
{lang="it", given="Anna Maria", surname="Mozart"}
{lang="en", given="Fitzwilliam", surname="Darcy"}
{lang="fr", given="Maurice", surname="Chevalier"}
]

20
Jan
07

Types and Plugins

Summary: The value of types is documentation/guidance, not performance. Thus type systems can provide escape hatches without compromising their value. Also, covers uses of Plug-ins and advice on how to build a developer community.

My programming side has been quite quiet out here in blogland lately. One of the reasons is I’ve been working on something I’d like to share, but the company I work for doesn’t quite feel comfortable with that. It’s not world changing, since it’s still fairly domain specific, so I think the concern is a bit overstated, but it is interesting and as such has consumed a fair bit of my programming thought time, which leaves me with little to share.

Luckily for me, Yegge’s recent post, dances around a number of my favorite topics. Like type systems (way down at the end). I agree with some of what Yegge says here, but I think he’s missing an opportunity I mentioned in Suggested Type System. Steve says “that you need escape hatches”, and ML systems aren’t used because they “don’t have any holes”.

Despite being desperately close to the concept, he continues on to continue to advocate that static typing is inherently flawed and that the only thing holding back dynamic languages is a lack of execution or community mismanagement.

The problem is typing is not simply about turning software into hardware. That is one common use, and oddly he recommends it as the usefulness of Common Lisp type annotations. Personally I’m starting to hate that Common Lisp feature because it distracts so many people from the other purpose of types, the purpose that has far more value and reason.

The value of types that will always remain is they can be used as guides. This purpose has been perverted in varying degrees in many static languages when the performance promise is held out. Despite both qualities relying upon type data, they are not complimentary. In some cases type information is dropped from runtime/compiled code in the name of performance.

When runtime type checking is dropped you are faced with two horrible choices. Either you must find a way to remove all possibility of inaccuracy before runtime, or you must endure the possibility of catastrophic failure. The first system choice inevitably leads to systems ML like systems that attempt to describe every possibility and to remove all the holes. Like Steve points out, it’s a nice concept, but rather unworkable for real development. The second choice leads to C++ or worse.

Java, for all its flaws, did do something right by bringing the runtime type checking back and most of the type data. Unfortunately, the escape hatches were not planned well and in many cases intentionally neglected. There is some change happening here, but like the problems in the dynamic area, the community makes it difficult to effect change.

My choice for direction is a language that encourages types and provides all the guidance they allow for, but at the same time provides all the holes you need and all the holes you want. But you should have some clue when you’re passing through a hole. You shouldn’t simply be tossed into a piece of Swiss cheese. The goal should be to design a language where there is less reason to use holes, not a language that simply has fewer holes.

Plug-in systems

Yegge doesn’t specifically mention the connection between plug-in systems and type systems, but the implied connection is there. It’s about extensibility and flexibility, and the value of a plug-in system is hard to deny, there have been far too many great and important systems that relied heavily upon their plug-ins.

Operating Systems are essentially big plug-in systems, as each application is an extension of its own. But beyond that idea, operating systems always have numerous other finer grained plug-in systems. Drivers, Context Hooks, Services, etc.

But plug-in systems are difficult. Windows has been criticized and lauded for its extensibility, which for good or evil is extremely extensive. UNIX has always had a history of extensibility, which undoubtedly OS X has inherited, although it’s not very much part of the Apple philosophy.

Windows is somewhat of a special case, however, as its popularity has brought the evil side to the foreground as security exploits often took advantage of the extensibility, and the number of poorly written pieces of software that caused problems through improper use of extensibility caused non-vigilant users problems.

But most systems don’t face a similar quantity of misuse and as the runtime check becomes more prevalent it becomes easier to limit the possible negative impacts. It’s still quite easy to create a problem which a malevolent attacker or incompetent partner could misuse, but at least it doesn’t require a herculean effort.

All that aside, a plug-in system that is adopted by a community can singlehandedly insure the success of a product. FireFox’s strongest feature in my opinion is the add-on community. Internet Explorer has an add-on system as well, but it’s not as well adopted by the community.

Community Adoption

But how do you insure your plug-in system will be adopted by a community?

Well, you should make it easy to use, but what does this really mean? For plug-in systems you need to recognize that you have two groups of users, developers and users. Most companies have a good idea who their users are, but who are the developers? In mass market products or developer tools, like web-browsers or IDEs, the developers are a subset of the users, but for more specialized products this might not be the case. In more specialized products, developing a plug-in community requires going outside your user base to find developers.

But why would someone outside your user base develop a plug-in? When the developer is part of your user base then you can rely upon self use as motivation, but if they are outside you need to provide another motivation. The simplest substitute is money. For mass market products, money is also a good secondary motivation. So you need to provide a way for your developer community to monetize their effort.

Once you’ve identified who your potential developers are, you need to define easy to use in their terms. If your application is a development tool, you can expect your developers to be highly skilled developers, experienced with your tool. With a mathematics tool, you can expect your developers to be skilled in a field closely related to development, but they may not be programming every day. With a web-browser, your developers are probably more familiar with JavaScript than other languages.

Questions like these help define what easy to use is for the developer, but what about the user? More than anything, users want to have confidence in their plug-ins. Although some efforts in this area can be contrary to the goal of developer ease of use, you need to provide the user some security against malevolent or incompetent plug-in developers. Things should fail gracefully if a problem occurs. Diagnosis should enable identification of which plug-in is the source of problems when they occur. Depending upon how large your community is, and how mission critical your application is you may need to control the channel into your system and only allow approved plug-ins. Or, you may support certified and uncertified plug-ins.

An area where both developers and users can benefit from is by making it easy to find and install plug-ins. Developers benefit because it’s free publicity, and the benefit to users is obvious. Automatic updates are important as well, as it make maintenance easier.

At the same time, you need to think a little bit selfishly too. You’re still going to need to support your customers, so you need to insure that you have the necessary information about plug-ins and their effects available to your technical support people.

I could go on, but unfortunately I must go now.

12
Dec
06

On Simplicity

In many camps, especially anti-Microsoft camps, the clarion call of simplicity has become highly popular. It’s hard to argue with the natural value of simplicity when confronted with the enormous complexity developers encounter daily. However, I believe the movement has simply gone too far, and has lost sight of the true principles. Actually, I’m not sure they were ever well known in the first place.

The Simple Hedgehog

In the business world, there is a book “Good to Great”. The book outlines a number of practices, but one, the “Hedgehog Concept” applies well to the place of simplicity in software. A Hedgehog Concept, is a single simple and unifying concept that fulfills three qualities. The first two qualities, are that the concept must be based upon your key economic driver and be something your passionate about. While both of these are valuable principles for choosing a software concept, the third quality, that you must be able to be the best at this thing, applies more broadly.

The success of the Hedgehog Concept is heavily reliant upon being the best at the one simple thing that defines your Hedgehog Concept. With software, it’s much the same. Features are valuable, but without the best core in the world, your software will suffer. Your software will never be great, no matter how many features you add.

It is however possible to add features without neglecting your core once your product reaches a certain degree of maturity. In fact, simplicity will often run counter to your efforts to make the best core possible. Once your core is implemented in the best way possible, the only way to improve upon it is to add additional layers. Admittedly, few things ever reach the point of “best way possible”, but certainly many reach the point of “best so far”.

Simple products, like Google Docs can only excel by being better at the core functionality, not just by being simpler. In general, I don’t think these products succeed at this goal. Is there really anything in Google Docs that makes it better than Word? I don’t think so. At the very immediate core, a word processor is about helping you write. Google Docs captures keystrokes almost as good as Word, unless you have an internet connection problem. Google Docs provides a spell checker, which you have to manually operate (In fact it even prevents the FireFox 2.0 spellchecker from working properly). Is there a grammar checker? Nope.

With these failings, Google Docs would need to do something truly extraordinary, but it doesn’t. Simple just isn’t good enough. It has to be the best core. If that requires additional features that add complexity, then those features are absolutely more valuable than simplicity gained from their omission.

The Upper Limit

Why then, is simplicity so highly prized in software architecture and user interfaces? Finding the simplest design possible to accomplish a given task is certainly valuable, but I think extreme minimalist designs are overemphasized. I contend that the biggest benefit of the simplest possible design is that it gives you room to add additional features before you pass the “complexity” limit.

The human brain has an upper limit upon the amount of complexity that it can handle simultaneously. Once beyond this point, things start to slow down considerably. So without a very strong core UI concept you’ll eventually reach a limit where the value of additional features is mitigated by their difficulty or obscurity. A better UI concept can enable absorption and effective use of a much larger quantity of useful features, and allow each of those features to reach their true potential. This is the beauty of the changes to Office 2007. So many primary features have been made orders of magnitude simpler, that the value of the secondary features is multiplied greatly.

It hasn’t helped me a great deal in Word, but in PowerPoint the difference is quite striking in the depth of my usage patterns between the 2003 and 2007 versions.

In software architectures, the same principle applies, but in an even more absolute manner. A complex architecture isn’t a problem until it breaks or you attempt to change it. If the additional complexity exists to reduce breakages, as is often the case, then the only disadvantage left is future modification. An architecture with an unsuitably complex design will not be able to evolve effectively past a certain point until the core complexity is reduced.

In other words, it is only possible to support additional essential complexity after you have removed accidental complexity from your core. Adding additional features before addressing core design issues will have diminishing returns. It’s even possible to reach a point of negative returns. But in the end, at least in software design, the goal is not fewer features, but additional space for more features.

Mike Champion calls this process engineering.

The Long Fight

The amazing thing about all this is the realization that software design is attempting to simultaneously add and remove complexity at the same time. The result is a precipitous balance, which goes a long way to explaining the volatile nature of software schedules. A religious adherence to simplicity may produce some interesting ideas, but unfortunately it will produce relatively few great applications. The true path seeks to remove the unnecessary or accidental complexity, while simultaneously adding essential features and complexity.

How do you manage this process? Cutting 80% of your features isn’t how. Neglecting your architecture for the sake of feature releases doesn’t work either. You do it with a cool head, patience, and unwavering focus to not fall off the thin edge. Sound easy? Sure…

16
Oct
06

Suggested Type System

I think I am in general agreement with the viewpoint that typing should be optional not mandatory (see Is Static Typing a Form of Bad Coupling? and Plugabble Type Systems)

The one problem I have with this view is that most people who hold it seem to think typing should be a rarely used performance kludge. I’d also agree that typing should rarely be used as a performance kludge, but I don’t think that means typing should be rarely used. There are other reasons to use typing. Actually, there are quite a large number of them.

For me, the main justification has always been safety. Typing also has benefit as a form of documentation. Safety and documentation are things you want most of the time, not rarely, so why would you rarely want types?

I think one of the problems is that most people look at typing as a way that framework designers can restrict their users. But what if typing didn’t restrict users, but instead guided them? I think this would still meet the needs of framework designers. A framework change doesn’t need to have zero breaking changes. All it really needs to do is cover the reasonable points of view. If you provide a safety net, and your users tear it down, I don’t think any (reasonable) person would fault the framework designers for breaking those users.

A Metaphor

Consider programming like some kind of stunt in an Indiana Jones movie. In this stunt, you’re walking across a narrow beam, with a big pit of spikes down below. There’s also poison darts wizzing by from little holes in the side walls. Today’s type systems however fit into a few categories.

On type are harnesses that keep you from falling off, but they slow you down, and make you an easier target for the darts. These are your mandatory static type systems. Another type are safety nets, that let you fall, but at least keep you from hitting the spikes. These are the dynamically typed systems. You could go without a safety net at all, and save a bit of money and setup time. This would be assembler. Or you could go with a cheap and poorly designed harness. It would slow you down even more, and it might break and let you fall. This would be C or C++.

Although this metaphor isn’t perfect, I’d consider the darts to be complexity. You might be able to take one or two since the poison is somewhat weak, but there wizzing all over the place, and they add up. The spikes of course are the core dump that happens when runtime typing isn’t employed. Many static type systems employ both the harness and net, because the harness has a release latch. But this latch (reflection), is somewhat awkward and hard to use.

In the end we realize the best way through is a set of shields (unit tests) to protect us from the darts. But the only thing available to build these shields with is grass, and it takes a lot of grass to build a shield, since grass is kind of flimsy, our shields can only absorb so many darts. Plus we still have to worry about falling off and having to climb back up from our net.

I probably way over extended that metaphor, but it’s kind of catchy, and has a nice visual, so I’m keeping it.

Resolution

What I’d like to see is a type system that helps keep us from falling off, but doesn’t slow us down. I’m not sure how to represent this in my metaphor. Maybe as some kind of lightweight harness with a quick release/attach mechanism. When you have it on your sure you won’t fall, but if you need to do something that the cables are too restrictive for, you can detach. It’s important however that the choice to detach is not something that happens by accident. But it shouldn’t be hard to use either.

I think I’m asking for a lot here, but I do think it’s doable. If we could agree this was the way to go, we could start designing the syntax behind it. In a sense, we have all the basic ideas we need. The JVM and CLR provide just about all the necessary capabilities. The problem is that reflection is ugly and hard to use. We need a better designed latch. Even more important, we need one that’s designed for users who have a shield strapped to each forearm.

I’m afraid I may have blown the argument with that long drawn out metaphor, so I’ll probably write about this again, but it might be a fun to read anyhow, so I’ll publish.. really.. I’m doing it right .. now!

14
Oct
06

Testing Ruby

I spent a fair bit of time over the last two months with Ruby. I actually started studying it about six months before, but I hadn’t really got to the point of writing anything non-trivial with it. At that point, it was more “theoretical”, than real. So two months ago I started doing some more complex stuff. For example, I wrote this little distributed abstract syntax tree interpreter. It’s nothing to brag about, and it’s probably completely useless, so I won’t bother explaining it, but the point was to understand Ruby a bit better.

As I expected, there were a number of areas where Ruby was beautifully brilliant and easy to work with. There were some disappointments however. That’s not really surprising either, since Ruby hasn’t been in the limelight all that long, and as a result many of the more expensive peripheral things like tools and libraries haven’t matured yet. And of course, like any language/platform, there are going to be room for improvement. There will be tradeoffs, things the community is working on, etc.

To be fair, I should probably start by listing all the great things about Ruby, but plenty of people who know a lot more about Ruby than me have already done that, so I doubt I’d really add much through that. Let’s just accept that I do believe there are great things.

That said I’m going to start taking potshots. Well, potshots is a bit harsh, but since I’m sure someone will feel like that’s what they are, we’ll just label them as such, and avoid all confusion.

IDEs

The first disappointment was IDEs. I started with Ruby in Steel, an add-in for Visual Studio .NET. The beginning was rocky as the first installers had some issues, but eventually I got it installed (and the newer installers are smoother). But I was immediately disappointed because I thought there was some rudimentary Intellisense support. There wasn’t however. The SapphireSteel guys are still working on that feature for their developer edition, and it sounds like it will be better than what I expected could be done, but we’ll have to wait and see. Oh, and the debugger was being troublesome.

The next up was RDT for Eclipse. Despite also advertising code completion, I found no signs of it. And once again the debugger was very troublesome.

I was about to give up on the idea of a debugger at all, when I found ArachnoRuby. It didn’t have or advertise Intellisense, but it did have a working debugger. Actually, it wasn’t just working, but designed for dynamic languages. For example, it allows you to attach a IRB console to a running program (after a breakpoint has occurred), and make modifications just like you had run your whole program in IRB.

Beyond that, another great thing was the Ruby Class Browser, which was far more useful than the standard documentation, or RDoc for finding classes and methods. Still however, there was no Intellisense, which I think would have been better because I got annoyed at having to swap windows to look something up.

So, it’s not all doom and gloom, but clearly, Ruby IDEs have a lot of room for improvement. And some features, like refactoring and Intellisense are much more difficult than they would be in a non-dynamic language. That’s one of those little tradeoffs. The smart dedicated Ruby people will probably just shrug their shoulders at those issues and move on about their work, accepting it for what it is, a tradeoff. The really brilliant and really dedicated Ruby people will find a way around 90% or 95% of the problem, although that will take time.

The idealists will probably respond that those features aren’t necessary, or are actually, despite common wisdom, are evil. Something along the lines of “Code Completion makes you stupid”, or “My Dual Core 3Ghz processor is too slow to run anything more complex than a text editor.” Oops, didn’t mean to start ranting like that… Moving on.

Unit Testing

Unit testing in Ruby is actually very good, despite the lack of any IDE support for it. Being dynamic is the biggest contributor to this. The array and hash primitives are also great for setting up test cases. But mostly it’s the dynamic nature of Ruby. Tests get virtually no benefits from static types.

Except the problem is, I found myself writing tests that would have been covered by a static type system. It’s not that the test cases would have been any easier to write with a static language, but there were plenty of them I wouldn’t have had to write at all. And even then, there were even more tests I didn’t write that would have been provided by default through a static language. And beyond this, in order to implement some tests, I had to put the equivalent of static typing into my code. It just ended up being a lot more verbose then simply declaring the type would have been.

For example, take this initializer:

def initialize(*exprList)
@exprList = exprList
@exprList = *@exprList if @exprList.is_a?(Array)
raise "Values must be interpretable" unless @exprList.all? {|value|
value.respond_to?(:interpret)}
end

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

(I know I probably screwed up a dozen things, so it’s worthless to nitpick my code quality. I’m an admitted Ruby Nuby) That last line is really the crux of the issue here. I expect some will feel it’s simply not necessary, but the truth is, it helped solve more than one bug when I combined it with unit testing. But that line is really just a really verbose form of List<Interpretable>.

So what we have here, is just another tradeoff right? Dynamic languages make unit tests much easier to write, but require more of them. But what if we started to treat static type information as a compact, concise and expressive form of unit tests, rather than as a straitjacket. Maybe if we did this, by making static languages that support dynamic capabilities, we could make unit testing easy, and avoid rolling our own static typing. Just an idea.

Summary

There is more to all of this then simply potshots at Ruby. The real point, is that we all have a lot to learn from each other. Here I’ve shown how the Ruby tool developers are learning from the Java/.NET tool developers, though obviously they have their own unique challenges AND opportunities as well. But likely, all of the hard work put into Ruby Intellisense will have some real value to static language tool designers as well, especially those working with type inference.

I’ve also shown how static language unit test tool developers can learn from Ruby unit testing. I’m going to assume there is probably a way to make the Ruby side of things more palatable as well, though I don’t know what it is yet. When you get criticism, look at it as an opportunity to grow, not an attack, even if it actually is an attack (this wasn’t).




Pages

Top Clicks

  • None

a


Follow

Get every new post delivered to your Inbox.