Saturday, February 18, 2006

Thinking Outside the Box

Sometimes you gotta stretch the definition of things...

If you have a new application that needs interprocess communications, but you don't want to build the whole infrastructure, consider using something like email or instant messaging for IPC. Many modern languages have libraries that support email, so it's not a difficult thing to add, and allows you to take advantage of the entire internet connectivity. You also can use it for communications back to developers, when significant errors occur.

Instant messaging can be used as well, but there are fewer libraries built-in to langauges. It's faster and more connection-oriented, but less well-supported across the networks. You will have a variety of IM protocols to choose from, and a plethora of servers to run, should you choose to run a private server.


Another useful hack for developers is to use Gmail as a poor-man's FTP utility. Since you have over 2.5GB of space on an account, it will be large enough for most any transfer. You probably will want to encrypt your files, however, to preserve security. This will pose a slight problem, as Google blocks encrypted archives. Never fear, because you can use something like uuencode to convert an encrypted file into pure ASCII. After downloading the file, uudecode will convert it back into its original binary form.


Andrew Tannenbaum has been quoted as saying "Never underestimate the bandwidth of a station wagon full of tapes shurtling down the highway". As network speeds have increased, so has portable storage density, so the saying is probably as true now as it was then, with only the vehicle and media changing (I'd probably reference a minivan full of USB thumb drives, personally). Sometimes the brute force approach is the best combination of simplicity and utility. If you need to be able to do a rapid upgrade with the ability to just as rapidly return to the initial setup, look into the cost of simply making a complete copy of the machine in the new configuration, and perform the switch by swapping the network connections.



Technorati Tags --
, , ,

Friday, February 17, 2006

How Not To Be Seen

It's relatively rare these days to be part of a team that is just forming. Most of us start a new job with a bunch of existing developers already working on the product. So there is a period of adjustment as you learn the new team's process and culture.

One of the worst things to do during this time is to start commenting on the team's practices in a critcal manner, even if they are suboptimal. This will not endear you to your new colleagues.
  1. Don't assume that they are not reading current journals. If they are not taking advantage of the latest technology, it may not be because they haven't heard of it.
  2. Don't act surprised if they don't have all of the Best Practices implemented. Company politics, inertia, and scheduling may prevent them from implementing them
  3. Don't try to impose your favorite practice. You will appear arrogant. No matter how good an idea it is, you will piss people off.
  4. If you really wish to change, build support from within. No group welcomes an outsider trying to change things by fiat.
  5. Don't go running to the manager to get things done without first. It looks to coworkers like you can't support your idea, and want to short-circuit the team's evaluation of the idea.
  6. Never talk about how great the process was at your last job. The team has had to work under this company's system, and they are probably making the best of it here.
The executive summary: Don't assume that the team is full of idiots, and don't act superior.



Technorati Tags --
, , ,

Monday, February 13, 2006

Hints for new programmers - someone else's view

I was poking about today and happend across this article about what advice to give a new programmer. Overall, I agree with it, except for the parts about a coding standard, Singletons, and comments.

Singletons are more than just global variables. Even if you code them to just be wrappers around global variables, you've gained some encapsulation, and that will help you when you need to track changes to something global - you put a trace statement into the set function for the value, and you'll see where it's getting changed.

A single coding standard is important - the article shows a small function with 2 different styles and states that it's easy to work out the code flow and intent. Well, sure it is, when you've got only 5 lines of code. Where a coding standard shines is in functions that are longer, with more complex interactions. I had the misfortune to be looking at some code recently that as far as I can tell had been developed by at least 3 different people, each with a different indentation setting and brace style. I found differences in one function (about 30 lines) in intertwined sections of the code. Following the logic was difficult because I had to keep going back to the start of each clause to see if I was exiting a layer. If you can't get your development team to agree on a standard, enforce one with an automated tool - you will be thankful later.

And finally, comments. The article does recommend using comments for the WHY and not the WHAT, and rightly ridicules commenting each change in the top of the file, but if you don't comment on the why of each non-obvoius path in the code, the developers that come after will miss it.



Technorati Tags --
, , ,

Sunday, February 12, 2006

Developer Tip: Yet Another API point

Just a quickie -
When you write the functions for an interprocess API, don't put the work part of the API in the catching functions. If you put the guts of the work into the catching function, changes to the API directly affect the work part. Instead, if you have a small dispatching function as the catcher, and delegate the work to another function, you can reuse that function for later version fo the API functions, without needing to completely rewrite the work function.

You will need to make the work function fit the newer version of the API, and the older version catcher function will need to be modified to send the new parameters to the work function, but that is relatively minor work compared to a total clone, or complete rewrite.



Technorati Tags --
, , ,

Wednesday, February 08, 2006

Developer Tip - One Code Stream To Rule Them All

Here's something that I recommend that might fly in the face of conventional wisdom regarding the use of your CVS to manage multiple branches of code in the corporate world - if at all possible, DON'T!

It's not because the tools can't handle them - most modern CVS tools are adequate for managing separate code streams. It's the overhead in managing the streams that will kill you. Every bug found will need to be tracked once for each stream, fixed once for each stream, and tested once for each stream. If you have different code in modules along the branches, the fixes are more complex, since you can't just plug in the same lines of code.

If you have a fluid feature set for a given release, as is unfortunately common, you'll find that features jump between releases depending on:
  • Progress - if the work can't be done in time, the feature moves to the next release.
  • Contractual obligations - someone signed papers promising it earlier than previously scheduled.
  • Hail Mary business deals - the future of the company depends on closing this deal, and this feature is the only way to do that.
  • Customer release cycles - a common problem. The customer wants the feature by time N, and the schedules are drawn up, and suddenly the customer decides they need 6 weeks of certification testing to accept the new code you give them, meaning that you have to pull the important features back into the current release to get it to the customer before the certification deadline.
  • Customer A doesn't want Feature X, but Customer B does. Several releases later, Customer A wants Feature X, after a lot of divergence in the code streams.
So how to solve this?

For every feature in the product, have an activation flag. You may need more than one flavor of this, to account for the differences between optional features that everyone gets to choose to activate or not, and bespoke features that only some customers will be allowed to activate, or even know about. In any case, build a library that will have a set of simple functions that will determine if a given feature is in use at runtime. Don't forget multi-valued options, like a staged conversion between file formats - you'll have a value for pre-conversion, mid-conversion [when both old and new formats are valid], and post-conversion.

Once a feature has been defined, write all the code to handle that feature in all of its incarnations, so that there is no need to branch your code stream. You may need to branch for customer-specific configurations to present the options in a desired manner, but that code should be very small, and managing it on a per-customer basis will not be taxing.

Another important facet of this is to concentrate the decision-making for a feature in as few places as possible, and have the rest of the code handle all possibilities without checking for feature activation. An example of this would be a system that talks to some specific type of equipment only if licensed. The communication code should be written to handle messages from all types of equipment, and the next layer up would be the code that decides to send messages to that type only if licensed, and to respond to any message from that type only if licensed. The fact that messages from an unlicensed type of equipment are passed up to the higher layer instead of being rejected at the lower layer is not a problem - the logic of licensing has no business in the communications layer of a system.

This will develop your system as both flexible and simple, and spare you the headaches of trying to port features into radically different code streams. Your CVS tool will present simple trees instead of briar patches of inheritance. If you use a database, the schema will easier to upgrade, since there will be no releases that have different parts of a later schema - they will all be the same, or newer ones will be supersets of older ones (barring removal of tables, in which case they will be subsets, but functionally complete subsets).



Technorati Tags --
, , ,

Tuesday, February 07, 2006

In on the ground floor

Let's talk for a minute about the ideal software developer situation - when you are there before the product exists. Getting in on the ground floor is exhilarating; there is no cruft in the code, there is no backwards compatibility to maintain, there is no build-up of sludge in the process. But it's also a challenge - there is no structure to work from, no library of existing code that you know fit your problem space. So what do you do?

If you've got a team already, then you probably have a work style that the team is comfortable with. Take a few days to meet and analyze this, to see if there are issues that need to be handled, and if there is anything the team really wants to change. Get consensus, but you don't need unanimity - as long as the dissenters are recognized and taken seriously, things can proceed.

From that point, you have a number of things to decide:
  • pick your code management system. Make sure it fits your development process, and your company's release style. If you don't plan to have more than one code stream, things like RCS and SCCS may be perfectly suitable. Otherwise, something like CVS, or Subversion may be more suitable. For large companies, something like Telelogic's Synergy or IBM/Rational's ClearCase might be mandatory. In any case, settle the question and set up the project in the system.
  • System startup and shutdown. Decide how the system will start and stop. If the product is a single program, this may be a no-brainer - a command line or desktop shortcut may be all that is needed. If the product is a full suite of programs that need to be running all the time, you may need to interact with the operating system in some way - inittab for UNIX-style OS's, for example. Don't forget to examine the need to stop the system for upgrades!
  • Configuration. Determine how your applications will get their configuration. The two obvious choices are a database or a configuration file. If the application does not have a DB, then file(s) are your only choice. If you have a DB, then you can choose. The factors influencing you will be the type of data you need for configuration, and the amount of data needed. Be sure to make your programs capable of re-reading configuration on demand, to make runtime changes possible and easy.
  • Logging. Your programs will need to log abnormal conditions, errors, and other information. Decide how you will need to report this data. On UNIX-like systems, syslog is a good choice. if you want to piggyback on the OS facilities. One thing to consider with your logging system is rollover - you do not want to fill up the disk with one large file. Design the logging system to allow the log file to be moved out and replaced, and manage the saved files so you don't fill the disk. Another consideration is whether or not you have multiple copies of a single program running - your file naming scheme should make allowances for this, as well as the rest of your logging scheme - if you have a single logging process that connects to the work processes by name, or some such.
  • Interprocess communication. You've got a lot of options - RPC, CORBA, plain sockets, shared memory. Don't overlook some newer options, given the versatile libraries of modern languages, of email and instant messaging; also don't discount such old-school options like using the database, or files on the disk as communications channels. Build your libraries using the minimum number of options, but keep the interfaces clear (see my previous entries on this )
  • Coding Standards. I'll address this more some other time, but work out a coding standard for your project with the developers, and if possible, make that format automatic - use hooks in the CMS to convert files into that standard upon check-in. This will prevent disagreements from stubborn developers - they can code their own way if they insist, and the code gets dropped into the common area in the standard form.

That's at least a few of the things that I feel important about a starting project.



Technorati Tags --
, , ,

Thursday, February 02, 2006

Developer Tip: Defining an API

Ok, enough blather about theory, company politics, and other crap. How about something useful to an everyday developer?

When defining an API, make it as simple and as obvious as possible what data is actually being passed across the API.
  1. This will make the API much easier to document - the names of the fields in the structures/objects/messages will be mnemonic, and you can document them as comments in the IDL file.
  2. You can use an IDL translator to convert from one IDL to another, like RPC to CORBA, or from one language to another, like C to Python
  3. You can automate the argument marshalling code if you want to write one or both sides of the API in another language.
An example I have seen that violates this was an API that wrapped all the arguments inside functor objects that were templates typed by the number of arguments they took. It's a great utility mechanism, because all your calls across the API are compact, taking one argument, and no return value because the functor inside will handle all that when the callback is made.

HOWEVER, this API was aboslutely miserable to develop with, because you had to go deep into the code on both client and server sides to discover what the arguments being passed really were. We wanted to build a test framework to exercise a server, but we had to manually build the structures populate the arguments, instead of being able to build them automatically from the IDL files.

A counterexample is a typical RPC interface to C programs. It will have a number of structures defined in the .x file, and it's a small matter of programming to build, buy, or Google a program to parse the .x file and produce the other files to build a test scaffold from in the language of your choice.



Technorati Tags --
, , ,