Friday, May 23, 2008

The 7 Habits of Highly Effective Developers

If you want to achieve your highest aspirations and overcome your greatest challenges, identify and apply the principle or natural law that governs the results you seek.  How we apply a principle will vary greatly and will be determined by our unique strengths, talents, and creativity, but, ultimately, success in any endeavor is always derived from acting in harmony with principles to which the success is tied.  This advice comes from Steven Covey in his best-selling book, The 7 Habits of Highly Effective People.  If you haven't read this book yet, you must.  It's about effecting change from the inside out for success in both your personal and professional life by aligning your values with principles through practicing seven habits.  Before reading this book, I felt like a passenger on a career freight-train. like something put in motion that I was powerless to control.  What I was practicing in my career, my habits, was misaligned with my values, and my values were misaligned with unmovable principles.  Although I was powerless over the career train, I came to realize I had the power to choose which train I was on.  So here I am at a company that allows me to follow my passion: developing software.

The 7 Habits book is broadly focused, and it made me think about habits specific to my profession.  What do those software developers that I consider effective (if not brilliant) have in common?  What values drive their decisions and what habits do they practice that make them successful?  Here are the seven habits that I think effective developers practice:

Passionate

The most brilliant people I've worked with are passionate about what they do.  They aren't driven by money and fame and, I say this with tongue in cheek, if they didn't have families to feed, would develop software without compensation.  If I had two candidates for a development position, I'd rather hire a less-experienced person with passion than a more experienced person without.  If you aren't passionate about software development, find what you are passionate about and follow that path.

Able to Learn, Unlearn and Re-learn

I believe that learning is an extension of passion, and effective developers operate in a continuum of improvement and innovation.  They learn from their and others' mistakes and don't apply old solutions to new problems just because they worked before.  Effective developers follow technology, but are careful to not let new approaches become solutions looking for a problem.

Balance Principle and Practice

Principle and practice are the Yin and Yang of software development.  Effective developers don't design impractical solutions for the sake of principle and don't implement solutions without overarching values.  They are willing to compromise based on time, cost, scope and quality constraints, but can also obtain compromise from others based on sound principles.

Keep It Simple Software (KISS)

Effective developers implement the simplest possible thing that will work while not painting themselves into a corner.  They don't implement anything more than is needed right now, remaining mindful about what might be needed in the future.  Effective developers know that the less moving parts there are, the less likely it will break and favor elegance and simplicity over convoluted cleverness.

If You Don't Know the Answer, Know Someone Who Does

Software developers aren't renown for their social prowess, but some of the most effective developers I know are excellent at networking.  If you give a random 100 question test to a group of people, no one individual will score 100%, but collectively, with few exceptions, the group can answer all the questions correctly.  There is so much technology, so many areas of speciality, you can only be an expert on one, maybe two subject areas.  Effective developers know the limit of their knowledge, aren't afraid to admit when they don't know something and have many friends and colleagues in their network they can reach out to for help.

Focus on Value

Effective developers understand the forces driving the project, its stakeholders and their goals.  Using this knowledge to guide their decision making, they focus on delivering tangible value to their customers over anything else.  Effective developers prioritize work based on its value--the so called "bang for the buck," and avoid projects and features they don't believe in.

Puts the Needs of the Many Before the Needs of the One

I've seen small teams accomplish extraordinary things; it's amazing what "two guys and a laptop" can accomplish.  Call it teamwork or synergy or whatever you like, when a group of people put common goals before their own, they converge like light into a laser beam.  Contrast this with the arrogant, rogue and cowboy developers who go against team standards or design intents because "that's how I do it" or "that's how you should do it."  The message they are really sending is "I am smarter than the team."

Conclusion

These seven habits give me something to work towards and keep me focused.  I only had room for seven habits in this article, and I'm sure you can think of many more or define effective in your own way.  The important thing is to take a value-driven approach to your software development career and do intentional things that move you towards your definition of success.

(From http://blogs.msdn.com/johnwpowell/archive/2008/05/22/the-7-habits-of-highly-effective-developers.aspx)

Tuesday, May 13, 2008

History's Worst Software Bugs

In 1945 engineers found a moth in Panel F, Relay #70 of the Harvard Mark II system.The computer was running a test of its multiplier and adder, when the engineers noticed something was wrong. The moth was trapped, removed and taped into the computer's logbook with the words: "first actual case of a bug being found."

 
Sixty years later, computer bugs are still with us, and show no sign of going extinct. What seems certain is that bugs are here to stay. Here, in chronological order, is the Wired News list of the 10 worst software bugs of all time … so far.
 

July 28, 1962 -- Mariner I space probe. A bug in the flight software for the Mariner 1 causes the rocket to divert from its intended path on launch. Mission control destroys the rocket over the Atlantic Ocean. The investigation into the accident discovers that a formula written on paper in pencil was improperly transcribed into computer code, causing the computer to miscalculate the rocket's trajectory.

1982 -- Soviet gas pipeline. Operatives working for the Central Intelligence Agency allegedly (.pdf) plant a bug in a Canadian computer system purchased to control the trans-Siberian gas pipeline. The Soviets had obtained the system as part of a wide-ranging effort to covertly purchase or steal sensitive U.S. technology. The CIA reportedly found out about the program and decided to make it backfire with equipment that would pass Soviet inspection and then fail once in operation. The resulting event is reportedly the largest non-nuclear explosion in the planet's history.

1985-1987 -- Therac-25 medical accelerator. A radiation therapy device malfunctions and delivers lethal radiation doses at several medical facilities. Based upon a previous design, the Therac-25 was an "improved" therapy system that could deliver two different kinds of radiation: either a low-power electron beam (beta particles) or X-rays. The Therac-25's X-rays were generated by smashing high-power electrons into a metal target positioned between the electron gun and the patient. A second "improvement" was the replacement of the older Therac-20's electromechanical safety interlocks with software control, a decision made because software was perceived to be more reliable.

What engineers didn't know was that both the 20 and the 25 were built upon an operating system that had been kludged together by a programmer with no formal training. Because of a subtle bug called a "race condition," a quick-fingered typist could accidentally configure the Therac-25 so the electron beam would fire in high-power mode but with the metal X-ray target out of position. At least five patients die; others are seriously injured.

1988 -- Buffer overflow in Berkeley Unix finger daemon. The first internet worm (the so-called Morris Worm) infects between 2,000 and 6,000 computers in less than a day by taking advantage of a buffer overflow. The specific code is a function in the standard input/output library routine called gets() designed to get a line of text over the network. Unfortunately, gets() has no provision to limit its input, and an overly large input allows the worm to take over any machine to which it can connect.

Programmers respond by attempting to stamp out the gets() function in working code, but they refuse to remove it from the C programming language's standard input/output library, where it remains to this day.

1988-1996 -- Kerberos Random Number Generator. The authors of the Kerberos security system neglect to properly "seed" the program's random number generator with a truly random seed. As a result, for eight years it is possible to trivially break into any computer that relies on Kerberos for authentication. It is unknown if this bug was ever actually exploited.

January 15, 1990 -- AT&T Network Outage. A bug in a new release of the software that controls AT&T's #4ESS long distance switches causes these mammoth computers to crash when they receive a specific message from one of their neighboring machines -- a message that the neighbors send out when they recover from a crash.

One day a switch in New York crashes and reboots, causing its neighboring switches to crash, then their neighbors' neighbors, and so on. Soon, 114 switches are crashing and rebooting every six seconds, leaving an estimated 60 thousand people without long distance service for nine hours. The fix: engineers load the previous software release.

1993 -- Intel Pentium floating point divide. A silicon error causes Intel's highly promoted Pentium chip to make mistakes when dividing floating-point numbers that occur within a specific range. For example, dividing 4195835.0/3145727.0 yields 1.33374 instead of 1.33382, an error of 0.006 percent. Although the bug affects few users, it becomes a public relations nightmare. With an estimated 3 million to 5 million defective chips in circulation, at first Intel only offers to replace Pentium chips for consumers who can prove that they need high accuracy; eventually the company relents and agrees to replace the chips for anyone who complains. The bug ultimately costs Intel $475 million.

1995/1996 -- The Ping of Death. A lack of sanity checks and error handling in the IP fragmentation reassembly code makes it possible to crash a wide variety of operating systems by sending a malformed "ping" packet from anywhere on the internet. Most obviously affected are computers running Windows, which lock up and display the so-called "blue screen of death" when they receive these packets. But the attack also affects many Macintosh and Unix systems as well.

June 4, 1996 -- Ariane 5 Flight 501. Working code for the Ariane 4 rocket is reused in the Ariane 5, but the Ariane 5's faster engines trigger a bug in an arithmetic routine inside the rocket's flight computer. The error is in the code that converts a 64-bit floating-point number to a 16-bit signed integer. The faster engines cause the 64-bit numbers to be larger in the Ariane 5 than in the Ariane 4, triggering an overflow condition that results in the flight computer crashing.

First Flight 501's backup computer crashes, followed 0.05 seconds later by a crash of the primary computer. As a result of these crashed computers, the rocket's primary processor overpowers the rocket's engines and causes the rocket to disintegrate 40 seconds after launch.

November 2000 -- National Cancer Institute, Panama City. In a series of accidents, therapy planning software created by Multidata Systems International, a U.S. firm, miscalculates the proper dosage of radiation for patients undergoing radiation therapy.

Multidata's software allows a radiation therapist to draw on a computer screen the placement of metal shields called "blocks" designed to protect healthy tissue from the radiation. But the software will only allow technicians to use four shielding blocks, and the Panamanian doctors wish to use five.

The doctors discover that they can trick the software by drawing all five blocks as a single large block with a hole in the middle. What the doctors don't realize is that the Multidata software gives different answers in this configuration depending on how the hole is drawn: draw it in one direction and the correct dose is calculated, draw in another direction and the software recommends twice the necessary exposure.

At least eight patients die, while another 20 receive overdoses likely to cause significant health problems. The physicians, who were legally required to double-check the computer's calculations by hand, are indicted for murder.

(From http://www.wired.com/software/coolapps/news/2005/11/69355)

Monday, May 12, 2008

Interview: Interfaces Vs. Abstract Classes

What is the power of "Interface" in Java and support your answer with a practical example which could be understood by most Java programmers?

Answer: Interface helps in designing systems or software with high-level of abstraction. It helps design API and establish protocols between various systems being iteracted or interfaced. Let's take an example of java.sql.Connection. It totally depend on the implemented JDBC driver to define what the connection is doing. It could be a Oracle, MySQL database connection or it could be just a flat file based database connection. Same is the case with javax.servlet.Servlet interface. I can throw more & more examples. Anyway, the bottom line is... JDBC, Servlets, JMS, EJB etc. are all possible because of Interface.

I am not saying that is the best answer anyone can give or that is the only usage of Interface. Honestly, I should admit, I didn't know the real usage/power of Interface for a long time working in Java, until I reached a point where I felt... Yep... This is it. This is why interface was invented for...:)

I am not denying or underestimating the usage of abstract classes. And, I do think you can design APIs with just abstract classes. But, you almost had to fake some implementation to get high-level of abstraction. Abstraction is one of the biggest blessing in Software Programming. Think about OS level system calls, its all abstracted to the application level programs. We don't care how the file is being read or written at the byte level. As an application level programmer we do our job (of reading & writing file right by the application program we are working with) & expect the OS to do its job. I dont want to go off topic with all these metaphors. I think, I made my point clear.

Interfaces are great at specifying standards. Abstract classes help define frameworks. You cannot build an SDK out of interfaces. It doesn't give you anything but structure. In order to actually implement and distribute an implementation of one of these standards, you have to use abstract classes. You have to write functionality that can be seamlessly integrated with your client's derived classes.

(http://blogs.boxysystems.com/2008/5/9/power-of-interface-in-java)

Wednesday, May 07, 2008

A Conversation with James Gosling, Part II

 
Failure and Exceptions
 
Summary
James Gosling talks with Bill Venners about how to build solid apps, organize your catch clauses, scale checked exceptions, and deal with failure.

Much has been written recently about the value that checked exceptions add, or subtract, from Java. Some programmers feel that checked exceptions help them build robust applications. Others find that checked exceptions are an annoyance that hinders their productivity. In this article, Java's creator James Gosling voices his opinions about checked exceptions and error handling.

In this interview, which will be published in multiple installments, James Gosling talks about many aspects of programming.

  • In Part I: Analyze this!, Gosling describes the ways in which Jackpot can help programmers analyze, visualize, and refactor their programs.
  • In this installment, Gosling talks about how to build solid apps, organize your catch clauses, scale checked exceptions, and deal with failure.

Creating Solid Software

Bill Venners: In your weblog, you wrote:

Lots of newbie's coming in from the C world complain about exceptions and the fact that they have to put exception handling all over the place—they want to just write their code. But that's stupid: most C code never checks return codes and so it tends to be very fragile. If you want to build something really robust, you need to pay attention to things that can go wrong, and most folks don't in the C world because it's just too damn hard.

One of the design principles behind Java is that I don't care much about how long it takes to slap together something that kind of works. The real measure is how long it takes to write something solid.

What does "solid" mean?

James Gosling: Solid means you can run the software day in and day out. When the usual crazy things happen, the software survives. The software deals with the problems. If you change the system configuration around, the system, as much as possible, copes—or at least recognizes when things are wrong.

One of the traditional things to screw up in C code is opening a data file to read. It's semi-traditional in the C world to not check the return code, because you just know the file is there, right? So you just open the file and you read it. But someday months from now when your program is in deployment, some system administrator reconfigures files, and the file ends up in the wrong place. Your program goes to open the file. It's not there, and the open call returns you an error code that you never check. You take this file descriptor and slap it into your file descriptor variable. The value happens to be -1, which isn't very useful as a file descriptor, but it's still an integer, right? So you're still happily calling reads. And as far as you can tell, the world is all rosy, except the data just isn't there.

Problems like that are really hard to test for. It is really hard to test the unlikely things, if only because the unlikely things never really occur to you. In this example, the programmer will think, "Well of course the file is there. Why would anybody not have the file there?"

A programming language can't solve all the problems. A language can't guarantee that no matter how screwed up the environment gets the program will survive. But anything the language can do to increase the probability that programs will be reasonably graceful under fire is a good thing. For example, just making people at least willfully ignore return codes helps. In Java you can ignore exceptions, but you have to willfully do it. You can't accidentally say, "I don't care." You have to explicitly say, "I don't care."

Bill Venners: You don't have plausible deniability.

James Gosling: Yeah, there's no plausible deniability when it comes to checked exceptions.

Orgnanizing Your Catch Clauses

Bill Venners: I recently published an interview with C#'s creator Anders Hejlsberg in which we talked about checked exceptions and why C# doesn't have them. I wanted to ask you about some of his comments. He said:

It is funny how people think that the important thing about exceptions is handling them. That is not the important thing about exceptions. In a well-written application there's a ratio of ten to one, in my opinion, of try finally to try catch.

In the finally, you protect yourself against the exceptions, but you don't actually handle them. Error handling you put somewhere else. Surely in any kind of event-driven application like any kind of modern UI, you typically put an exception handler around your main message pump, and you just handle exceptions as they fall out that way. But you make sure you protect yourself all the way out by deallocating any resources you've grabbed, and so forth. You clean up after yourself, so you're always in a consistent state. You don't want a program where in 100 different places you handle exceptions and pop up error dialogs. What if you want to change the way you put up that dialog box? That's just terrible. The exception handling should be centralized, and you should just protect yourself as the exceptions propagate out to the handler.

I do catch exceptions in an outer loop sometimes. But most times my catch clauses tend to be spread around the program. I find that catch clauses usually have a natural home—the method that has enough contextual knowledge to know how to deal with the exception. How would you recommend people organize their catch clauses?

James Gosling: I tend to do catches much more frequently than Anders would have you do, because the knowledge of the situation is always fairly localized. When you try to open a file and it's not there, you're coping strategy is really determined by what you were going for. Some guy miles away isn't going to know what to do. The code that tried to open the file knows what to do, whether it be trying a backup file, looking in a different directory, or asking the user for another filename.

Having one big catch clause on the outside really only works if your exception handling philosophy is simply to die. If you have an event loop, you can maybe cause that one event to just be tossed. If you have a plugin architecture, the enclosing environment could respond to a failure in the plugin by disabling it—like an app server deciding to disable a servlet if it sees failures. But if you're not doing an event driven program or plugins, there isn't an outside place where you can take big hunks of functionality and saw them off. On the other hand, typically you should have last ditch try catch blocks. If you're writing a web server, for example, it's a good thing to put a last ditch try catch block around processing a request. But pretty much all that a try catch block like that can do is blow the request away. There's no ability to respond gracefully. There's no ability to take account of local context to cope and adapt, which is really one of the key hallmarks of truly reliable software.

Bill Venners: It adapts to problems?

James Gosling: Instead of just rolling over and dying.

Scalability of Checked Exceptions

Bill Venners: Another concern Anders Hejlsberg had about checked exceptions, which is a concern I've heard many people express, is scalability. He said:

In the small, checked exceptions are very enticing. With a little example, you can show that you've actually checked that you caught the FileNotFoundException, and isn't that great? Well, that's fine when you're just calling one API. The trouble begins when you start building big systems where you're talking to four or five different subsystems. Each subsystem throws four to ten exceptions. Now, each time you walk up the ladder of aggregation, you have this exponential hierarchy below you of exceptions you have to deal with. You end up having to declare 40 exceptions that you might throw. And once you aggregate that with another subsystem you have 80 exceptions in your throws clause. It just balloons out of control.

James Gosling: I've almost never seen that actually happen in large systems. One of the coping strategies I've seen for dealing with that kind if situation is exception wrapping. If you have a subystem that might be hit with hundreds of different exceptions, you can always take those exceptions and wrap them in a new one. You can create a new exception and list other exceptions as their cause. Also, the exception class hierarchy can help. For example, there are dozens of different IOExceptions, but it's common to not declare that you throw the specific subclasses. You just throw IOException.

But in general, when you are writing a declaration in a throws clause, it is good to try to be as specific as possible.

Bill Venners: Why?

James Gosling: Because it gives more information to the context about what exactly went wrong. That helps client programmers discriminate among the different sources of failure in their catch clauses.

Bill Venners: Have you seen the throw clause scalability problem in your visits out in the industry?

James Gosling: I've never seen issues where people have a gazillion items in their throws clause. Three, four, or five, maybe—and even those numbers are rather large. Almost always it's zero or one.

Bill Venners: I've found that many people don't seem to think about programming so much in terms of the interface as an abstract contract and the implementation as one way to implement that contract. They just think in terms of "the code." But the throws clause is part of the interface. If someone makes an implementation change that results in a method being called that throws a new checked exception, that doesn't mean that exception should necessarily appear in throws clauses up the call stack. If you automatically plop exceptions into throws clauses, you're letting the implementation drive the interface, instead of thinking about what the throws clause should contain at the abstract contract level.

James Gosling: That's a place where exception translation can be a good thing. If you have something that's supposed to be reading a database, and somewhere deep inside it, it could conceivably get a MalformedURLException, it probably doesn't make sense to propagate that outward as a MalformedURLException. It's better to think about what kind of exceptions are really a part of the interface, and not just an artifact of how the underlying method was implemented. In the Java exceptions mechanism, exceptions can have a reference to other exceptions as their cause. So you create a new IOException, and you set its cause to this MalformedURLException. And you bundle them together. That's been very effective.

Exception Handling versus the One True Path

Bill Venners: What percentage of time do you think people should be spending programming the one true path—the path taken if nothing goes wrong—versus handling all the potential errors?

James Gosling: It's all over the map. Ideally you should be spending almost all of your time on the one true path. But if you look at various domains, the percentages are different. The worst case would be people doing avionics software. If they spend a few percent of their time working on the one true path, they feel very good about themselves. That's the kind of area where the high nineties percentage of your time is spent dealing with things that could go wrong, and speculating about things that could go wrong. In that area, life is truly dynamic. There are real random number generators up there, with turbulence doing strange things to wing tips and all kinds of weird stuff that may never actually happen.

Almost as bad as avionics is networking software. When you're trying to write some piece of software that is dealing with something across the network, trying to make that truly reliable can be a lot of work. I've done code that tries to maintain reliable database access, for example, and that can be 90% error handling. You look at most protocol implementations and at some level they're almost all error handling. If you believed everything was perfect all you would do was spew packets. You wouldn't worry about timeouts, flow control negotiations, and any of the other things that go on. Networking is all about how you deal with errors at all various different levels. But when you're in a fairly well-controlled regime like, "Here's a web request, compute the result please," there shouldn't be a whole lot that you're actually worried about.

Bill Venners: Yeah, I think there's a spectrum. At one end you have pace makers and airplanes. If you don't deal with certain kinds of unexpected situations people can die. At the other end you have one off scripts. I remember one script I wrote that was pulling information out of web pages and putting it into XML files, and the script worked on maybe 90% of the pages I was processing. And that was good enough because it was faster for me to fix the other 10% by hand than to make the script better at dealing with badly formed input files. In that case, there was a system administrator who was quite happy to spend an hour fixing things by hand, because that was cheaper than spending 2 or 3 hours trying to get the script to be more solid.

James Gosling: Right. It all depends on what the consequences of failure are. If you're just extracting information from pages like that and you're a system administrator, the consequences of failure are pretty minor. But if you're writing transaction reconciliation software for some bank, you could find that oh, thirteen billion dollars leaked out of some system because of a bug. I actually had a friend who basically lost thirteen billion dollars in one night because of a bug.

Bill Venners: Thirteen billion dollars?

James Gosling: Yep. Thirteen billion. They were actually able to reconstruct it from transaction logs, but it was a real big mess. Thirteen billion dollars is real money, so you're actually probably willing to test, willing to spend some time in dealing with handling those exceptions and making things reliable.

Bill Venners: I have heard a lot of people complain that in practice Java's checked exceptions encourage a lot of empty catch clauses. This empty catch clause problem seems to be more common than exceptions being propagated in throws clauses going all the way up the call stack. The compiler forces a programmer to catch an exception, so they catch it but they don't do anything. Then if the exception is ever thrown, it ends up being swallowed. It is not handled and not propagated. It is lost. Do you think that in a lot of places there's a lack of a culture of programmers wanting to deal with failure, perhaps because in the past they didn't have to deal with failure as much?

James Gosling: Anytime somebody has an empty catch clause they should have a creepy feeling. There are definitely times when it is actually the correct thing to do, but at least you have to think about it. In Java you can't escape the creepy feeling.

It really is a culture thing. When you go through college and you're doing assignments, they just ask you to code up the one true path. I certainly never experienced a college course where error handling was at all discussed. You come out of college and the only stuff you've had to deal with is the one true path. You get a job working in some IT department's data center, and they're using the software in production runs. If it doesn't work, it's a real problem. All of a sudden there's all this painful stuff that you don't like to do, and you're feeling grumpy about it because this isn't as much fun as just writing clean code.

There's really nothing a hacker likes more than having an empty editor buffer. You can just start to write code. That's the way university assignments are: here's a problem, just write the code. The real world is much cruftier.

But there's also a spectrum. You talk to people in banks, where large quantities of money get lost if there's a problem. They take failure very seriously. The spookiest folks are the people who have been doing real time software for a long time. I've spent a certain amount of time with that crowd. By and large these folks are very conservative and very careful. A lot of them know what it's like to go visit the family of the deceased and explain the bug to them. There are a number of places that have policies that if a test pilot augers in, then once it's all figured out what happened, the people who engineered the thing that failed have to go explain it to the family. I've actually only met one person who has ever actually had to do that. That would change your attitude about dealing with failure really quickly.

A Conversation with James Gosling, Part I

 
Analyze this!
 
Summary
James Gosling talks with Bill Venners about his current research project, code-named Jackpot, which builds annotated parse trees for programs and can help you analyze, visualize, and refactor your program.

For the past several years, Java's creator James Gosling has been working at Sun Labs, researching ways to analyze and manipulate programs represented as annotated parse trees, a project called Jackpot. Compilers have long built parse trees when they translate source code into binary. But traditionally, programmers have worked with source code primarily by manipulating text with editors. The goal of the Jackpot project is to investigate the value of treating the parse tree as the program at development time, not just at compile time.

In this interview, which will be published in multiple installments, James Gosling talks about many aspects of programming. In this first installment, Gosling describes the ways in which Jackpot can help programmers analyze, visualize, and refactor their programs.

Treating Programs as Algebraic Structures

Bill Venners: What's the state of Jackpot, your current research project?

James Gosling: Jackpot has been really cool lately. It's what I'm spending most of my time on, and it's been a lot of fun. I was really hoping to have something I could hand out at JavaOne this year, but I've been finding too many entertaining things to do.

It's a very different world when a program is an algebraic structure rather than a bag of characters, when you can actually do algebra on programs rather than just swizzling characters around. A lot of things become possible.

Bill Venners: Like what?

James Gosling: If you look at any of the refactoring books, most of those refactoring actions become much more straightforward, in ways that are fairly deep.

Moving a method isn't just cutting and pasting text. It's a lot more than renaming the parameters and swizzling them around, because you really want to be able to do things like construct forwarding methods. When you construct forwarding methods, they're different from the original methods.

You can't just replace all uses of the forwarding method by uses of the moved method, because they actually behave slightly differently. The difference is usually around what happens when the pivot parameter is null. That can lead you into a deep morass of essentially theorem proving about properties of the code fragments that you're moving, to understand how they behave with respect to null. And you can treat all kinds of code manipulation that way.

So Jackpot has a baby theorem prover, or algebraic simplifier, that knows an awful lot about data flow and the implications of values. And it really does treat your program as a piece of algebra to be simplified and transformed. It can do an awful lot of interesting analysis that pays off when you want to make fairly significant pervasive changes to very large programs. That analysis pays off, for example, when you want to replace one API with another API that is almost the same. Often "almost the same" is actually harder than "radically different." I spent most of the last four months working on this baby theorem prover, and that's been a lot of fun.

Creating Visual Representations of Programs

Bill Venners: I read that Jackpot can create interesting graphical representations of a program. What is that about?

James Gosling: Jackpot can take this underlying algebraic structure— it's really the annotated parse tree—and generate a visual representation from that. Our internal notion of the truth is not text. But once it's not text, all of a sudden you can display it in really interesting ways.

We've got an underlying rule engine that's able to do structural pattern matching very efficiently. We can go from the structural patterns it sees in your code to visual representations. So you can write what is kind of like a reverse grammar, where you associate structural patterns with what you can think of almost as TeX descriptions of how to represent the patterns graphically. What you see on the screen has been generated from this pattern matching. So we can, on a user chosen basis, turn various program structures into all kinds of visual representations.

You can, for example, turn the square root function into the obvious mathematical notation. You can turn the identifier theta into the Greek letter theta. You can turn division into the horizontal bar with numbers stacked. And we've done experiments with wackier things, such as trying to generate real time flow charts. That's kind of goofy, but entertaining. Other things like hiding block contents, doing interesting typography, doing typography on comments, all actually work out reasonably well.

Bill Venners: At previous JavaOnes, I have seen some visualization tools that I thought were useful. One of them analyzed your code and drew diagrams that showed the coupling between packages. I felt those diagrams could help you realize that you've got a lot of coupling going from one package to another, which you may not realize by looking at individual source files. Visualization tools like that can help, I think, but a lot of tools that draw graphical representations from source don't seem to help much. Let's say you analyze a big program and generate inheritance charts, with thousands of boxes and lines going all over the place. That often looks as confusing as the source code does.

James Gosling: Yes, doing that kind of visualization is a real challenge.

Coupling Analysis with Action

Bill Venners: What kind of analysis does Jackpot do?

James Gosling: We've got a bunch of hooks in Jackpot for plugging in analysis modules. We want not only to be able to do analysis, but to be able to act on that analysis. We have some pieces that do pretty interesting things.

For example, often it's considered bad form to have public instance variables. One piece of analysis, therefore, is to find all the public instance variables. But we can find them and also make them private, add all the setters and getters, and account for what it means to actually access the variables via setters and getters. We can also do things like find all methods whose natural home is not the class they are actually in.

Bill Venners: How do you detect that?

James Gosling: If you look at the analysis books, there are various ways of detecting that. For instance, if you've got a static method that takes an object as a parameter, and it modifies that object, then somebody probably just slapped that method in there because it was easy. They were editing that file, so they put the method there. But they really should have put it someplace else. We've got something that will find those methods and actually move them, then change all the uses of that method to do the right thing. So we're trying to couple analysis with action.

Visualizing with JavaDoc

Bill Venners: What I mostly use for visualization is JavaDoc, because it's an abstract view of the public interface. I generate JavaDoc a lot as I'm designing and developing. I look at the HTML pages generated by JavaDoc and think, well, this looks kind of confusing. And I go back and make some changes to the code. I may not be able to see that it is confusing just by looking at the code. So I think having different ways to visualize code and designs as it is being developed can help guide the design.

James Gosling: Jackpot's editor component tries essentially to do what amounts to real time JavaDoc. JavaDoc is a funny thing. When I did the original JavaDoc in the original compiler, even the people close around me pretty soundly criticized it. And it was interesting, because the usual criticism was: a good tech writer could do a lot better job than the JavaDoc does. And the answer is, well, yeah, but how many APIs are actually documented by good tech writers? And how many of them actually update their documentation often enough to be useful?

Bill Venners: For me JavaDoc doesn't just serve as a way to document the design, it serves as a way to visualize the design. If I see huge classes with 300 public methods, or dozens of packages with only few classes in each, I know there's a problem. It's more obvious when you're looking at the JavaDoc than at the source.

James Gosling: Right. JavaDoc has been enormously successful and enormously powerful. It's really been quite wonderful. And it's also been interesting to see the way that professional tech writers have taken to JavaDoc. A lot of the early criticism from them were things like formatting. That's largely been solved by the sophisticated doclets that people have been able to write. But the tech writers seem to now spend a lot more time just documenting the semantics of what's going on, and a lot less time fussing with structure and formatting. And it actually feels like tech writers end up being more productive.

Bill Venners: So the tech writers are in there changing the code also, and checking in their changes?

James Gosling: Yeah. That's certainly what happens around here. The tech writers are intimately involved in the engineering. And actually I've always found that to be a really good thing to do. One of my general design principles is that it's really helpful to have a good tech writer on the engineering team early on. If you're building something and you have a tech writer trying to document it, and the tech writer walks into your office and says, "I don't know how to describe this," it means one of two things. Either you've got a really stupid tech writer who you should fire. Or much more likely, you've got a bad piece of design and you ought to rethink it. You have to rethink, because an API that isn't comprehensible isn't usable.

Bill Venners: So the tech writer is giving you feedback on your design. One of the values of design reviews is that programmers give you feedback, and that's useful if it's an API because the users of APIs are programmers.

James Gosling: The problem with programmers as reviewers, and especially programmers that have been involved in the program for a while, is that they are kind of oblivious to the complexity. And lots of engineers are complexity junkies. Complexity is in many ways just evil. Complexity makes things harder to understand, harder to build, harder to debug, harder to evolve, harder to just about everything. And yet complexity is often much easier than simplicity. There's that really famous Blaise Pascal letter, where he starts, "I apologize for this long letter. I didn't have the time to make it any shorter." And that's really true.

Bill Venners: I always think the designer's job is not only to create something that will work correctly and efficiently, but something that is also easy for the client to understand and use.

James Gosling: Yeah, you've always got a customer on the other side, whether that's some high end engineer, or some chemist in the lab who's writing a piece of code. Often you've got people whose real job is something other than software, and software is their tool. They don't necessarily get off on all of the complexity. Making things simple can be a real challenge.