30 June, 2008

Beer troubleshooting 101

SYMPTOM: Feet cold and wet.
FAULT: Glass being held at incorrect angle.
ACTION: Rotate glass so that open end points toward ceiling.


SYMPTOM: Feet warm and wet.
FAULT: Improper bladder control.
ACTION: Stand next to nearest dog, complain about house training.

SYMPTOM: Beer unusually pale and tasteless.
FAULT: Glass empty.
ACTION: Get someone to buy you another beer.

SYMPTOM: Opposite wall covered with fluorescent lights.
FAULT: You have fallen over backward.
ACTION: Have yourself leashed to bar.

SYMPTOM: Mouth contains cigarette butts.
FAULT: You have fallen forward.
ACTION: See above.

SYMPTOM: Beer tasteless, front of your shirt is wet.
FAULT: Mouth not open, or glass applied to wrong part of face.
ACTION: Retire to restroom, practice in mirror.

SYMPTOM: Floor blurred.
FAULT: You are looking through bottom of empty glass.
ACTION: Get someone to buy you another beer.

SYMPTOM: Floor moving.
FAULT: You are being carried out.
ACTION: Find out if you are being taken to another bar.

SYMPTOM: Room seems unusually dark.
FAULT: Bar has closed.
ACTION: Confirm home address with bartender.

SYMPTOM: Taxi suddenly takes on colorful aspect and textures.
FAULT: Beer consumption has exceeded personal limitations.
ACTION: Cover mouth.

SYMPTOM: Everyone looks up to you and smiles.
FAULT: You are dancing on the table.
ACTION: Fall on somebody cushy-looking.

SYMPTOM: Beer is crystal-clear.
FAULT: It's water. Somebody is trying to sober you up.
ACTION: Punch him.

SYMPTOM: Hands hurts, nose hurts, mind unusually clear.
FAULT: You have been in a fight.
ACTION: Apologize to everyone you see, just in case it was them.

SYMPTOM: Don't recognize anyone, don't recognize the room you're in.
FAULT: You've wandered into the wrong party.
ACTION: See if they have free beer.

SYMPTOM: Your singing sounds distorted.
FAULT: The beer is too weak.
ACTION: Have more beer until your voice improves.

SYMPTOM: Don't remember the words to the song.
FAULT: Beer is just right.
ACTION: Play air guitar.

Stumble Upon Toolbar

29 June, 2008

Five best desktop media players


You've collected hundreds of thousands of megabytes (and maybe even gigabytes) of digital music and video in the past 10 years, and as your media library has grown, so has the necessity for finding the perfect desktop media player. Not only must the perfect player be capable of playing back your media, but it also needs to be able to help you search through and find any song or movie you're looking for at a moment's notice. On Tuesday we asked to hear about your favorite desktop media player, and over 600 comments later we're back with the most popular answers. Hit the jump for a glimpse at the five best desktop media players, then help us choose the best of the best.

foobar2000 (Windows)

foobar2k.png foobar2000 is the most customizable digital audio player on the block. It's also one of the most lightweight players we're featuring. Out of the box foobar2000 is a little bland, but if you're willing to roll up your sleeves, you can make it into almost anything you want. Check out our primer for customizing foobar2000, and if you want a little inspiration, take a look at some reader-submitted custom foobar2ks. foobar2000 has plug-ins for iPod support, album art, lyrics, and it's even portable.


Winamp (Windows)


winamp.png
If you were a fan of digital music in the '90s, the only thing you were into as much as Napster was Winamp. Despite the fact that Winamp isn't as much at the forefront as it once was, it's still in active development and still maintains a thriving community of users contributing skins and plug-ins. It's also got iPod and other MP3 player support (naturally), remote streaming through your browser and game consoles, and an auto-tagging feature that automatically updates your music's metadata. It's also added video support for managing your ever-growing video library.


iTunes (Windows/Mac)


itunes.png
iTunes has gained massive popularity as the official media player of the iPod, but iTunes is also a powerful media management tool in its own right. Despite its detractors, iTunes has secured much of its popularity with a dead-simple yet powerful interface. It also bundles up the most successful digital music store on the planet, having sold over 5 billion songs—though it also comes with all that sticky, iPod-only DRM. Perhaps the biggest downside to iTunes: It can have a massive memory footprint.


Amarok (Linux/Unix)


amarok-screen.png
Amarok is the go-to digital music player for Linux users looking for a feature-rich, attractive player. With automatic album art imports, lyrics support, and Wikipedia integration (the coolest feature any media player could have), Amarok doesn't disappoint. With no iTunes available for Linux, Amarok doesn't just sync iPods and other MP3 players—it can even sync music to your iPhone or iPod touch wirelessly.


VLC (All Platforms)

vlc.pngVLC is the cross-platform Swiss Army knife of media players. It's lightweight, open source, and can play virtually any file—audio or video—that you throw at it. If you're really into VLC, you can even use it rip DVDs, fix out-of-sync audio and video, and play your ripped DVDs. VLC has no media library tools, but you can create and save playlists. Either way, the slim, no-nonsense player has found a home on countless Windows, Mac, and Linux installs.

Now that you've seen the five reader favorites, it's time to vote for the one you like best:


This weeks honorable mentions go to Media Monkey (Windows freeware and shareware) and Windows Media Player. Whether or not your media player of choice made the Hive Five, let's hear more about the player you love and why in the comments.

Adam Pash is a senior editor for Lifehacker who has a polyamorous love for media players. His Hive Five feature appears every Thursday on Lifehacker. Subscribe to the Hive Five RSS feed to get new installments in your newsreader.


Original Post

Stumble Upon Toolbar

20 June, 2008

Amazing simple home remedies

  • If you are chocking on an ice cube, simply pour a cup of boiling water down your throat. Presto! The blockage will instantly remove itself.
  • Avoid cutting yourself when slicing vegetables by getting someone else to hold the vegetables while you chop.
  • Avoid arguments about the toilet seat - Use the sink.
  • For high blood-pressure sufferers, simply cut yourself and bleed for a few minutes, thus reducing the pressure on your veins. Remember to use a timer.
  • A mouse trap on top of your alarm clock will prevent you from rolling over and going back to sleep after you hit the snooze button.
  • If you have a bad cough, take a large dose of Laxatives. Then you'll be afraid to cough.
  • You only need 2 tools in life - WD-40 and Duct tape. If it doesn't move and it should, use the WD-40. If it shouldn't move and it does, use the duct tape.
  • Remember: Everyone seems normal until you get to know them.
  • If you can't fix it with a hammer, you've go an electrical problem.

Daily thought: Some people are like Slinkies - Not really good for anything, but they bring smile to your face when pushed down the stairs.

Stumble Upon Toolbar

17 June, 2008

Flock catches up with Firefox 3 in sophomore release

Sequels aren't always as good as what comes before them (see Indiana Jones 2) but when it comes to technology and software, newer usually means better.

Flock, the self-proclaimed social browser, is catching up with the times this week with a new version for brave Windows and Mac beta testers that employs technology from the upcoming Firefox 3. Dubbed version 2.0, the new Flock is largely a behind-the-scenes operation, including such FF3 niceties as the controversial "awesome bar", improved render speeds, and the new bookmarking system, along with in-browser security notifications--which should keep the phishing sites at bay.

Flock's new people bar saves space by scaling up the services into scrollable feeds.

(Credit: CNET Networks)

That's not to say Flock 2 is without its new polishes. For one, the media bar that sits atop your browser window and lets you browse and snag any media that's on the page has been given a slight visual update. It's still a film roll of sorts with a slew of clickable thumbnails. What's new is that you can now save and bookmark media streams like you would Web pages. These items are saved alongside your bookmarks and can be called up, whether you're on that site or not.

Flock devs have also redesigned the people toolbar to scale for more services. One of my initial criticisms with it, and on other similar services like Yoono, is that it worked fine with five or six sites, but moving up into something like FriendFeed, which pulls in more than 40 services, people would just run out of room. Flock's solution is to compartmentalize each feed into three different sections, which--once you get the hang of it--works like a multi-pane e-mail client.

Another noticeable improvement is the built-in feed reader. If you're using that instead of something like Google Reader or a mail program, you previously had to re-start the browser to get the latest feeds. The new version includes a refresh button and adds time stamps so you can see how old each story is. I hope that in future iterations feeds will automatically refresh like they do on other readers, but the change is a huge step up from the old version.

We'll be updating the Newbie's guide when Flock 2.0 overtakes the current version (1.2), which should happen in the coming weeks.


Original Post

Stumble Upon Toolbar

08 June, 2008

Tips for maintainable Java code

There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies. -- C.A.R. Hoare

Here's a random collection of personal observations (some well established to the point of cliché, some deliberately controversial and tongue in cheek) on things to watch out for while designing and implementing large scale object oriented applications. While much is applicable to other languages such as C++, these days I'm only interested in Java, so that's what the examples refer to.

General

  • Programmers need to be precise. If you're sloppy and inconsistent with spaces, indentation, names, or access modifiers, what confidence will people have that your logic is any more accurate?
  • A good framework can sometimes help developers by avoiding you having to reinvent the wheel each time, but a bad framework is infinitely worse than no framework at all. Designing good frameworks is very, very hard. Consider this point carefully and draw your own conclusions...
  • Test your code, and keep testing it. Automated unit tests can be very useful, particularly for modules that can be driven programmatically or from a command line. Trying to automate GUI tests, on the other hand, is a noble goal but usually doomed to failure. It takes a vast amount of effort with very little payback. The tests produced are very 'brittle' (they permanently fail, but nearly always because of new development or changes in the test data, rather than bugs in the code actually under test).
  • Keep your code simple and comprehensible. Source code that nobody understands is about as useful as a bug-ridden third party library with no documentation, no source code, and no support, i.e. not very!
  • Think about your reward structures. If the system rewards analysts for the length of their documents, programmers for the number of lines of code they write, consultants for the number of days they can invoice, and managers for the size of the teams they hire, then collectively this will do little to reduce the size or cost of your development!
  • Don't optimise too soon. Unless you're doing I/O or performing the same operation a million times or more, forget about optimising it until you've run the program under a profiler. (On the other hand, if you develop an exponential-time algorithm with test cases of half a dozen elements, don't be too surprised if performance is less than satisfactory on a real world data set of 10,000 rows!)
  • Using common design patterns can be useful, but only when appropriate: "It must be good design, look, I'm using the Visitor pattern!" "Why, exactly?" "Err, well, I've just got to page 79 in the book and haven't tried that one yet..."
  • Never test for an error condition you don't know how to handle! If you don't know how to handle exceptions properly then let them propagate up to someone who does, as undeclared runtime exceptions if necessary. (Don't make the mistake of catching an exception that contains precise details of an error, simply because it's declared and you "have to" catch it, and then silently return, neither reporting an error nor completing the operation the method was called to perform!)
  • Here's one for managers: learn to identify those developers with negative productivity (and, boy, do they exist!) and don't be afraid to sack them, or at least move them to a role such as testing or documentation where they won't cause as much damage. (That isn't meant to imply that testing isn't a valuable role - which it is - so much as the worst most people are likely to achieve at it is zero productivity.)

Documentation

  • Document your design after you code it (or while you code it), not before. That way your documents stand at least some chance of corresponding with reality and still being useful when someone has to come along later and maintain your code. (Ok, some up front design is clearly a good idea, but you should still leave a large chunk of your documentation effort until after you've started coding).
  • It should go without saying that you must comment your code, and keep those comments up to date! Code that isn't worth commenting probably isn't worth executing either.
  • Any maintenance programmer who has had to work on code hacked about over the years by a myriad of other people will tell you that the only documentation they trust (or in all likelihood even look at) is the code itself. If a crucial piece of information is documented elsewhere, or if two or more files need to be maintained in sync, then say so in the code (in both places...).
  • Remember that it's much more important to document why a method exists than what it does.
  • If you find you need to use a debugger to understand the programming logic in your own code, something, somewhere, has gone badly wrong!
  • It sounds like a paradox but too much documentation is actually worse than too little documentation. Nobody will read it, it will be permanently out of date, and it lulls you into a false sense of security.
  • Avoid vacuous statements, e.g. commenting a method setList(List list) to say "This methods sets the list.". They're insulting and a waste of everybody's time. I might have guessed that it sets a list, but what list? Why? When? What does the object do with the list? Can it be null? etc.
  • Make sure you use a version control system that maintains an edit history, and try to enter a meaningful description of each change. (Again, it's more important to record why you made a change than what the change is.)

Java language

  • When you implement equals() or hashCode() always override both or neither (you're liable to encounter some very nasty and subtle bugs otherwise, once your objects start finding their way into hashtables, which they often do).
  • Consider overriding toString() to produce a useful description of the object (eg. the type of the object and the value of any unique id it contains). To avoid confusion, toString() on two objects should normally be equal if and only if equals() is true.
  • The result of calling equals() on an object of the wrong type is 'false', not a ClassCastException. (Knowing that the "instanceof" operator doesn't throw a NullPointerException on a null argument but returns 'false' often helps, by the way.)
  • If your class is cloneable always call super.clone() rather than using "new" to create the new object. This is implemented natively and will create an object of the correct type even if your class is later extended.
  • Keys and other basic types should be immutable, ie. have no setters, only take on values at time of construction, implement equals() and hashCode(). For good measure, they could also have a string constructor that works if you pass in the value returned by toString().
  • Immutable objects are the "first class citizens" of the object world. Semantically they behave exactly the same way as basic types. You can share instances without having to worry about anyone else modifying the value (or having the overhead of creating copies). Declare them to be final too and you have a self-contained, bullet-proof class, which should be every developer's highest aspiration.
  • Avoid duplicate representations of the same data that need to be maintained in sync. Instead, have a single master copy and use an adapter.
  • Think symmetrically. Every object that's created, every link that's made, every listener that's added, all need to be removed again, unless you consciously intend them to last the entire life of the VM or can be certain they will be garbage collected. Consider adding a dispose() method to your objects to forcibly break any references they hold and make the garbage collector's job easier.
  • Don't overuse threads. Unless you're sure you know what you're doing and sure you need some extra threads then you probably don't.
  • Java is not C++. It's generally good practice not to check for error conditions all over the place unless you expect the condition to occur and plan to do something specific with that knowledge. Let the VM take care of array bounds and null pointer checking while you concentrate on your design (programming logic that is correct and code that's clean and understandable).
  • This is an important point so to reiterate: too much error checking is a bad thing, especially if it's applied haphazardly. If I come across an existing class and see that in some methods a particular member variable is compared against null before it's used and in others it's dereferenced without a check, what am I to assume regarding the status of that variable?

Modularity

  • A good modular, componentized design means minimizing the knowledge and dependency one part of the system has to have about another.
  • Dogma has no place in practical programming, especially when it's driven by the latest trends in fashion, as often seems to be the case. Who remembers the introduction of macro assemblers, high level languages, procedural languages, structured programming, object oriented programming, 4GLs, CASE tools, UML, client-server, COM, JavaBeans, components, CORBA, frameworks, XML, J2EE, etc.? Each in their way promised to be the panacea of programming, delivering standard reusable components, and reducing the time to deliver applications to almost nothing. But looking back, who can truthfully claim that it's cheaper to develop software now than it was 10 or 15 years ago?!
  • The common theme of most of these methodologies is modularity. To make sense of a large complex system it is necessary to break it down into smaller parts somehow, with the minimum of interdependencies between those parts. The difficulty of course is knowing which parts. A good methodology may help you come up with a good design (in other words: a good breakdown into independent components), but by no means guarantees it. Nor does a good design necessarily depend on using any particular methodology.
  • If you view each component (method, class, file, package, application, or whatever) as a box, the important thing is having a clear mental picture that tells you which box a particular piece of functionality ought to go in (and even more importantly, which boxes it shouldn't). Achieving that clear mental picture requires both skill and experience; there aren't any shortcuts!
  • If you encounter an ugly or difficult to use API, wrap it up in your own abstraction layer so that all the ugly code is in one place. You can then convert it easily to use a different back end while keeping the interface the same. Even if the API is clean and well established, for example JDBC, there may still be valid reasons to abstract from it. Does this mean you're likely to write your own database drivers? No. However, you might want to log all database accesses, or perhaps start persisting your objects via XML and HTTP rather than to a relational database, and it's obviously easier to do this if all the related code is in one place.
  • Avoid designs with complex interdependencies, such as having to write three new classes and change six others each time you add a new field to an existing table.
  • Having all your code in one big file may not be the epitome of good OO design but it makes it a darn sight easier to find something if you don't know where to look for it, and easier to modify too if the alternative is a morass of interdependent files. Perhaps that's extreme, but never underestimate the power of grep as a software development tool - the best identifiers are the ones you can easily search for!
  • Make sure you fully understand the concept of a dependency. Decide which packages are allowed to refer to which other ones and which aren't and strictly adhere to those rules (for example, you might have GUI code that can refer to and invoke methods on your business objects, but not vice versa).
  • Complexity in the implementation is fine, but keep the API simple!

Just in time development and over-complexity

  • All code has a cost. Justify every class you write. Developers should be rewarded for functionality rather than code; if anything they should be penalised rather than rewarded for every new class or line of code they require to deliver that functionality.
  • Programmers love to be creative and demonstrate how clever they are at coming up with elegant and generalised designs. Don't let them - the objective is to write maintainable code, not an elaborate monument to one's own ego.
  • Virtually everybody loves to generalise, yet virtually nobody is any good at it. Until you've done something the hard way more than once it's very difficult to spot the general pattern.
  • Although the exact opposite has traditionally been ingrained in us, often it's actually better if we do not worry about the big picture or future requirements until we have to. When the future arrives you're going to have to change it anyway, and it's a lot easier to change a simple design, that admits it didn't try to anticipate all possible future requirements, than a complex one that tried but got it wrong, as they invariably do.
  • Take your pick as to which methodology name you pick to make the process sound respectable: "Just in time" development, iterative development cycles, RAD, timeboxed development, re-factoring, etc. The message is the same. Design and build only what you and your users understand now, and be prepared to review and change it once you have more complete knowledge. Throwing away and rewriting code is a good thing. Get it right next time.
  • Be very suspicious of generalised designs that are supposed to make things easier in future, unless you have a pretty good understanding of those requirements and what the payback will be now.
  • If you're determined to ignore this advice (as I'm sure you will), at least make some effort to quantify what long-term benefits you think your design will bring. All too often a developer will spend a week developing, then two weeks debugging a general solution where the specific solution will take a day to develop, a day to debug, and then a further 10 minutes two months later to adapt it to a new scenario. The developer will quite happily justify his two weeks of debugging effort, to himself and his manager, because it avoids the need for that one 10 minute change - and don't think I made those numbers up!
  • If a design is too complex and difficult to code correctly, the correct solution is a simpler design, not automatic code generators. If code is worth writing more than once, it's worth writing by hand each time!
  • Don't expose more methods in a class than you need (eg. gratuitous 'convenience' methods). Once published, they form part of the contract of your class, and make it much more difficult to change in future.
  • Building software is the opposite of building bridges. Ten developers deliver twice as much code, four times as many bugs, and half as much functionality as five developers. I didn't make those numbers up either. (Of course, if managers are rewarded for the number of people they hire and size of budget they control then it's only natural that they'll build up as big a team is possible, regardless of whether that's good for the project or not.)
  • If it were possible to know all the requirements of a program in advance why are we still writing software today - wouldn't it all already have been written 20 years or more ago? (Arguably of course, nearly all the software that anybody really needs was written 20 years ago, and everything developed since is fluff in the name of buzzword compliance, either just 'eye candy' or driven by marketing imperatives. Progress has its own inevitable inertia, and you need to be seen to be using the latest technology, regardless of whether it actually adds much tangible benefit to users!)
  • Let's face it, you and I and everyone else are going to write crap code anyway, so it may as well be cheap and simple crap code that you understand and can afford to throw away rather than complicated and expensive crap code. (The fact that 90% of the code written by 90% of developers is crap is a corollary of Sturgeon's law that 90% of everything is crap.)
  • Don't get me wrong, I'm not saying generalised designs or frameworks are wrong in principle, far from it. The important thing is a good design, though, framework or no, and a good design almost invariably means a simple design.

Objects and classes

  • Think about what an object is, not what the class does. With relatively few exceptions (eg. some factories, or if you specifically need to encapsulate an algorithm or process) classes whose name is a verb (eg. something-"Manager") are not good OO design!
  • An object or instance, as opposed to a class, is defined by its state. Think about what its state is, and what the lifecycle of that object is. Who creates it and when, who owns it, when or how does it get saved, when or how does it get refreshed, when is it destroyed? etc.
  • Remember, what we do is called object-oriented programming, not class-oriented programming! (One reason, incidentally, why I'm not a huge fan of Rose models. I'm more interested in how many of something there are and how they're used than what they extend.)
  • Think instances: if two related objects always exist in a one-to-one relationship with each other, it's quite likely they're actually the same thing and should be a single class.
  • Complex switch statements, especially if they occur more than once in a class, are usually a sign of poor OO design and call for use of inheritance. Conversely, sometimes it is ok just to parametrize a class and write a simple 'if' statement. As with everything, apply common sense and "value your intelligence above the standard".
  • Don't use random classes or interfaces you stumble upon for other than their intended purpose, just because they happen to resemble the structure of what you want. (An AWT Dimension measures pixels on a screen, so don't use it to store the size of a football pitch in feet. A Swing ListModel defines the specific requirements of a JList component, not a general purpose collection interface.)
  • If a utility method doesn't access any instance variables in a class then you should probably declare the method static.
  • Don't use inheritance when aggregation is called for (think about whether the relationship is an "is-a" or "has-a" relationship).

Style

  • Be consistent with indendation style. Personally, I loathe and detest K&R style indentation. The only logic behind it seems to be to avoid unecessary white space, which may have been useful once but when is the last time you edited code on a line printer or dumb VT100 terminal? Far more useful, surely, to clearly show how blocks line up - and far easier to spot when a rogue brace is missing. On the other hand, this is just my personal preference, and it's always more important to be consistent. If you need to add code to someone else's class make sure you respect the indentation style that's already in force (or use a pretty print utility afterwards, such as jpp).
  • There are some pretty strong conventions in Java that class names start with UpperCase, that packages are all lower case, that method and variable names start with lower case, that identifiers other than constants are in mixedCase and that constants are ALL_CAPS. It's also pretty much mandatory not just that the name of a source file matches the class name it contains but also that the directory structure matches the package name.
  • Avoid Hungarian notation (prefixing identifiers with things like 'm' and 'lpsz'), it's ugly and unnecessary. Trying to cram all the type and scope information into the variable name is a hangover from the days of C, when everything was stored in global variables. It suggests you either don't understand or don't trust the language and compiler. (Programmers need to keep track of the meaning of identifiers, so if you had a naming scheme that told you who owns an object, or whether it's the master or a temporary copy of some information, then that might actually be useful, not one that tells you what's already known.)
  • Many people put the private instance variables of a class at the bottom of the file, reasoning that users of the class shouldn't be concerned with the implementation. That's true, but missing the point slightly. Having a picture of what state a class embodies is essential to understanding the class as a whole and therefore one of the first things you look at, irrespective of whether you plan to access that state directly.
  • Be consistent with your names. If variables in two different scopes have the same meaning, or if methods in two classes do the same thing, give them the same name. If you abbreviate a name, do so consistently.

Pulling it all together

Or not:

  • For a particularly bad example of how not to generalise a class, take a look at the abomination that is GregorianCalendar. Vastly overcomplicated and difficult to use, and full of concepts in the wrong place, inappropriate abstractions and inconsistent names. Why does a Calendar contain an instance in time rather than just embodying the rules for doing date arithmetic? Why does a Date have set methods (a more classic example of an object that ought to be immutable than a date or timestamp is difficult to imagine)? Why deprecate methods that create or display a Date as UTC/GMT (by definition a universal representation that can be depended on without any further locale information) and yet leave in a toString() method that defaults to Pacific Daylight Time?! Why expose a complicated API that reveals internal implementation details and yet hide a safe and useful method like getTimeInMillis(), another unambiguous and universal representation? The designers thought they were so clever and forward-looking in not assuming a year starts on January 1, yet still have constants like MONDAY or PM. Above all, why is it so big and slow? (The 1.1 date classes are wrong at so many levels you're left wondering if the whole thing was just a sick joke, which might even have been quite funny if they weren't part of the core language and we were now stuck with the thing!)

By far the biggest cost in any project is fixing and maintaining the code, not developing it in the first place. So:

  • Think about users of your class.
  • Design for understandability and maintainability.
  • Remember that complexity is the number one enemy of maintainability.
  • Less is more!

Stumble Upon Toolbar