|
|
|
||
|
I was talking with another developer the other day and he revealed an interesting piece of information: he believed that comments and code style were a matter of personal choice. To me this was like believing that the world was flat and then having someone say that it's round. All of that time I spent perplexed wondering why I couldn't see things from long distances over a "flat" plane finally become crystal clear. Learning that developers may believe comments and code style are a matter of personal choice has allowed me to understand and put into perspective a number of other conversations that I have had with developers. Code comments and style are a function of quality. This is currently my running hypothesis that I am attempting to prove through empirical evidence. My non-scientific research has shown it to be true. The difficulty in firmly establishing quantitative evidence for this hypothesis stems from the fact that, for example, diligently and effectively commenting code intrinsically changes ones approach to coding. In other words, you cannot separate out the processing of adding and maintaining comments without changing the nature of how one programs. |
|
||
|
In an attempt to dispel the "I don't need to comment my code since if the code is written clearly enough it should describe itself" theory, I present the following: The purpose of code comments is to present intent. A software defect is a deviation from intent. This definition does not make a distinction between implicit (i.e. expected but not defined in a requirement) and explicit (i.e. defined in a requirement) intent. Code is incapable of sufficiently presenting desired intent. Proof I will provide an indirect proof of Theorem 1.1 by assuming "code is capable of sufficiently presenting desired intent" and obtaining a contradition. Choose a section of code that contains defects. By Definition 1.2 this section of code does not correctly describe the intent. QED Notice that Theorem 1.1 contains the word desired. This is necessary to distinguish between the intent that a section of code with defects presents and the intent that is required. Also notice that Theorem 1.1 contains the word sufficiently. Later entries will expound on this in more depth but for now it will suffice to say that code utilizing crafty programming may obfuscate intent. I do acknowledge that for those who use the "I don't need to comment my code since if the code is written clearly enough it should describe itself" to mean "I'm too cool / talented / whatever to comment" or to cover for "I'm too lazy to comment" that my argument will have fallen on deaf ears. I'm getting to you next! |
|
||
|
I simply cannot remember which is normalized and which is denormalized. I cannot do coordinate transforms -- I consider myself "spatially impared". And I can never remember the truth table for implies. "p implies q" or "p only if q" has the following truth table:
p | q | p -> q
---+---+--------
T | T | T
T | F | F
F | T | T
F | F | T
where p and q are propositions. It is logically equivalent to say:
For example: If a person is a father then a person is male. This statement is of the form p -> q where:
It is necessary for a person to be male to be a father. Being a father is a sufficient condition for being male. If a person is not a father, nothing can be said about if they are male. Whereas if a person is not male, they may not be a father. This last statement is the contrapositive of the proposition.
p | q | -p | -q | p -> q | -q -> -p
---+---+----+----+--------+----------
T | T | F | F | T | T
T | F | F | T | F | F
F | T | T | F | T | T
F | F | T | T | T | T
where - represents negation. Since both p -> q and -q -> -p have identical truth tables they are said to be logically equivalent. |
|
||
|
The instructions for my frozen lunch state: pierce film 3 - 4 times. "3 - 4"? Can you pierce something 3.3 times? What's a 0.3 of a pierce? Since pierce isn't defined (is it one inch long by 0.001 inches wide?), couldn't you renormalize to just 3? And why not just "3" or "4". Why a range? Is there some legal precedent that caused this to occur? U.S v. Hungry Jack: Exactly n piercings leads to multiple deaths. And what happens if I go outside of the pierce operating range of my frozen lunch? Will death result? Perhaps when they were putting the food through the QA cycle, the average number of piercings that caused a "perfectly cooked meal" was 3.6. Knowing that the average american is too dumb to know what a 0.6 of a piercing is (cuz I sure as heck don't!), they made it a range (Can you imagine the number of calls asking: what's a 0.6 of a pierce? The phone company would be brought to its knees!) This is just a theory at this point, but in order to finally get some sleep at night, I'm going to have to believe something. The answer is out there! |
|
||
|
While doing some research for a greedy algorithm that I'm working on, I stubled across the McNugget(tm) Number. Who says that mathematicians can't be fun? |
|
||
|
I had the opportunity to visit Chicago's new Millennium Park over the weekend. To quote Cindy Pritzker, "Isn't this the spiffiest thing you ever saw?". Yes Cindy, yes it is and thank you for all of your contributions that made it possible. Chicago threw one helluva party in a way that only Chicago could do. The number of activities and events that were available for all ages was simply staggering -- and they were free. From rap to jazz to classical all forms of music were available. There was dancing. There was drumming. There was juggling. I spent most of Friday evening, Saturday and Sunday in the park and I don't think that I saw everything that there was to see! (I will be updating this entry with pictures and comments on the new park. Check back for updates!) |
|
||
|
As if the previous Update After I determined that the write selector was lying to me on Linux, and after pouring over Stevens' Advanced Programming in the UNIX Environment to refresh my memory on Update II It seems that the results of drain-then-fill are dependent on how the sink is filled. If the sink is filled one Closing thoughts Given that Linux's write selector is not accurate and always returns "none available" when there is data in the pipe (but will always return "go ahead" when the pipe is empty), it is nearly impossible to generically replace a file or network channel with a Link-back to main entry: NIO and SSL. |
|
||
|
The number of Windows will eventually give you the known value of The code used is as follows:
// create a Pipe and retrieve its sink and source
// NOTE: the sink and source are SelectableChannels
final Pipe pipe = Pipe.open();
final WritableByteChannel sink = pipe.sink();
final ReadableByteChannel source = pipe.source();
// set the sink to non-blocking and create and register a write
// Selector on it. The Selector is used to determine when the sink
// is "full".
// NOTE: the cast is required since there is no common super-type
// for selectable + readable / writable
((SelectableChannel)sink).configureBlocking(false/*non-blocking*/);
final Selector writeSelector = Selector.open();
((SelectableChannel)sink).register(writeSelector, SelectionKey.OP_WRITE);
// continue to write to the sink until it is "full"
// NOTE: the sanity upper-bound is used to ensure that, in a remote
// case, a sink is not infinite
final ByteBuffer writeBuffer = ByteBuffer.allocate(BUFFER_SIZE);
for(int i=0; i<BUFFER_SIZE; i++)
writeBuffer.put((byte)(i & 0xFF)); // arbitrary
writeBuffer.flip();
boolean isInfinite = true; // set to false if limit found on write
int numberOfBytesWritten = 0;
for(int i=0; i<UPPER_BOUND/*sanity*/; i++)
{
// ensure that data can be written
// NOTE: selectNow() is used so that it does not block
if(writeSelector.selectNow() > 0)
{
// clear the selected keys (required)
writeSelector.selectedKeys().clear();
// write the data
// NOTE: the actual data written is arbitrary
numberOfBytesWritten += sink.write(writeBuffer);
writeBuffer.rewind();
} else
{
// the sink is full. Flag that a limit was found and break
// out of loop.
isInfinite = false;
break;
}
}
And, no, changing I should mention that An interesting Linux tidbit: if the following code is added after the code listed above with a // attempt to write more to the sink even though we shouldn't be // able to writeBuffer.limit(1/*writes one byte*/); numberOfBytesWritten = sink.write(writeBuffer); writeBuffer.rewind(); It seems that the Linux write selector is lying to us. This is not the case on Windows. Link-back to main entry: NIO and SSL. |
|
||
|
Here's some Q:What happens when you close the sink of a pipe? For all those that answered "The source returns Q:What happens when you close the source of a pipe? Belt it out! "Writing to the sink will throw
The concern is the windows case where a write (or multiple writes) can be performed successfully. Why isn't there a Expect to see a defect report / RFE in the bug parade on this topic. A big hearty thanks goes out to Igor for doing the Linux testing! Link-back to main entry: NIO and SSL. |
|
||
|
If you've been following my lamenting over NIO and SSL then you can probably guess that I've made it to step 5 (acceptance). I had a moment of elation this morning when I found another one of those obscure NIO classes: First grieveing and now momentary elation followed by good swift kick in the gut. Doesn't Sun care about the unstable mental state all of this has left me in?!? Side note: isn't it annoying that there's no interface that describes a selectable, readable / writeable channel? In other words, there's no common way to describe a |
|
||
|
I have worked with NIO quite a bit in the past. It has a high activation energy but once you're over that initial hump, it's pretty smooth sailing. I find it difficult not to write non-blocking IO these days. I recently wrapped up a client / server prototype and I am just beginning to get it ready for a "real world" test. The first thing that I thought of was SSL. So like all good programmers, I brought up Google and typed "NIO SSL". Much to my chagrin I find that it is not possible to combine NIO, To make a painful story short, there is no information regarding SSL ever being a possibility with NIO in 1.4. 1.5 will introduce an For those in the same boat as I am, there are solutions for using I'll spare you the Sun rant but let's just say that I'm less that impressed with their decisions to not provide SSL with NIO and to, for all intents and purposes, cover it up. When you read the 1.4 datasheet about NIO and then about JSSE, you get the impression that all is just sunshine, rainbows and lollipops. How can one think that it's acceptible to provide developers with the ability to "write ultra-scalable, high-performance server applications" without parity with existing sockets? And then, in 3 years, not make up for the discrepancy? If you're into conspiracy theories, what do you think about the missing RFE for SSL + NIO? My tin foil hat has been firmly placed on my head! Follow up: I've been doing a lot of poking around to see if there are freeware implementations of JSSE that support NIO. There aren't. I did find this interesting link. Given all of my ramblings about features vs. quality, if Sun didn't ship SSL with NIO due to quality risks then I can buy that. If Sun hasn't shipped an updated JSSE for NIO due to pervasive changes required then I can buy that too. The length of time between releases is just hard to swallow. As you may be able to tell, I have moved onto phase three of the Kubler-Ross 5 stages of grief. The initial entry was written while firmly in phase two. I fully expect to be at phase five by mid-day tomorrow and I will begin to find an acceptable solution to my current problems. Related Entries
|
|
||
|
As mentioned in another entry the classic tradeoff is: features vs. quality. A further refinement of this is: do you release a high priority feature even if it is not complete? It is common for a project bend to the pressures of client expectation and release a feature that may not be complete or is known to have defects. The thought that leads to this is that it is better to meet the expectation of the feature and deal with the quality risks later than it is to miss expectation. In my experience, the reality is the exact opposite. Releasing a feature with defects lowers the overall expectation of the product to a level much lower than that of a single missing feature. Let's take a look at this in more detail. Releasing a product with a missing feature defines a single point of contention (i.e. the missing feature). The client will have a focused attack on the omission that tends not to spread to other features (unless of course there are other missing features). I have no theories as to why an omission does not spread -- I only have experience that says that it does not impact the preception of the rest of the product. Releasing a product with a defect heavy feature tends to lower the overall perception of the product. I believe that this follows a "If this feature has this many problems, then how bad is the rest of it?" progression. On top of this is the onslaught of defect reports (most of which are already known internally to the developers) that accompanies the feature. The amount of man power required to deflect or stop the barrage is sometimes greater than that required to simply fix the bugs. (Developers may be thinking "Just fix the bugs and ignore the client's bug reports. Once the fixed version comes out all of the bug reports can be cleaned up en masse." Unfortunately, it just doesn't work this way unless the fix comes out a very short time thereafter. In most situations, the client hand-holding and expectation resetting combined with handling of the defect reports consumes needed resources.) I have seen projects where this barrage eventually stalls all progress and the entire team ends up in defect triage, changing focus from strategic to immediate tactical. My recommendation in this situation is to take the omission hit and follow it up with a well planned and executed (and, if possible, ahead of expectated delivery) patch / release that includes the missing feature. If you botch the followup release, well, let's just say that that tends to be worse than had the defective feature been released in the first place. |
|
||
|
I am a big fan of movies -- especially independent and foreign. Nary a week will go by that I wont see a previously unseen movie. I always send a quick email or IM to friends about the movie and if they should see it or not. On more occasions than I can count, people have asked me to post a list of these movies. I've been avoiding doing this out of sheer laziness for quite some time, but after unintentionally seeing the same movie twice, the final shoe has dropped. What would a movie list be without some ordering or structure? I'm firmly against the starring system used in the industry. It has a tendancy to downplay or misrepresent wonderful movies. For example, how can you use the same "quality" rating system to compare:
Clearly, putting Vacation and Deer Hunter into the same quality category would be a crime against nature. Or even attempting to compare the comedic aspects of Shrek 2 and Vacation would leave one or the other standing in the mud. But when all is said and done, all three movies are a must see. I will adopt the following structure:
Movies that I just don't care for will not be present in the list. So how does one distinguish between a movie that has not yet been added and one that is just not on the list (*cough* Lord of the Rings)? You don't. It's just one of those gambles in life. And so, without further ado, The List. Must See
Should See
If You Have the Time
Still need to be categorized
This list is by no means static. I will add to it as time permits. Also, it's possible for movies to change categories. |
|
||
|
final JarFile jarFile = new JarFile("rt.jar");
System.out.println(jarFile.getEntry("/java/lang/Object.class"));
System.out.println(jarFile.getEntry("java/lang/Object.class"));
will return:
null
java/lang/Object.class
In general, this is not a big deal. But when manually parsing URLs (don't ask) such as:
jar:file://rt.jar!/java/lang/Object.class
it can bite you in the butt. |
|
||
|
Let me begin by saying that I have a lot of respect for the Eclipse team. They have maintained tight milestones on a massive project. They have remained responsive to bug reports and feature requests. I could go on for quite a while. Much can be learned from that project. Unfortunately, they stumbled on the classic tradeoff and that has lead to a classic mistake. The classic tradeoff is: features vs. quailty. Do you spend more time fixing defects or creating new features? The classic mistake is: releasing a feature with a high defect rate. Classic mistake Notice that I said defect rate and not defect count. It may be that a feature has zero defects when it is shipped but in the recent past the number of defects found and resolved was high. Understanding the difference goes back to a firm understanding of QA and a little math. The defect rate is the number of defects found per unit time. The unit of time is commonly determined by the frequency and duration of test / fix cycles. A large defect rate means that there were many defects found in a cycle whereas a small defect rate means that there were few defects found. The defect rate for a complex feature typically increases then decreases. This trend follows the common sense rule that a single test cycle will not reveal all defects. In fact, in early test cycles, defects will block other defects from being seen. As fixes are put in place, the number of defects will eventually decrease. For those more savvy, the change rate of the defect rate (a defect acceleration of sorts) is also useful. A positive acceleration means that there are more defects found in a cycle than previously. A negative acceleration means that less defects were found than previously. And a zero acceleration does not mean that zero defects were found -- it means that the same number of defects were found and were found previously. Releasing a feature while the defect acceleration is positive (or zero with large defect count) or while the defect rate is still large will typically result in a feature with a high defect rate. In effect what you're doing is replacing a testing cycle with your client. This is the classic mistake. Classic tradeoff If there is one thing that clients are exceptionally bad at it would be understanding that development takes a finite amount of time (and typically longer than they expect). After the process of requesting and specifying a feature has finished and while development is occurring, the client is already thinking about the next set of features. By the time that development releases the features, the client already has expectations beyond that of the release. This results in development always trailing or missing expectations. (If you're a developer reading this, you've probably thought Well, duh!. Trust me, clients really don't understand the basis of these skewed expectations.) What I've just described always occurs. It's the background noise that developers and project managers have to deal with. Deciding between missing features or having defects while being affected by the background noise is the classic tradeoff. Eclipse tradeoff and mistake Late in development of Eclipse 3.0, code folding was introduced. There was a high defect rate (and a positive defect acceleration) associated with the feature. It interacted with a significant number of other features and is highly complex (this adds up to a high quality risk). Lo and behold, code folding is significantly buggy. Should code folding, a much asked for feature, have been included in the release? Check back for a follow up entry on this subject. |
|
||
|
More times than I can count, I have heard someone say "We're trying for XX percent code coverage with our unit tests". If XX is 100% are you guaranteed to have no defects? The first thing that comes to my mind when people start rambing on about unit tests is: What about integration and system testing? There are a number of blog entries out there that talk about the difference between the types of testing. It suffices to say that pure unit testing, even at 100% code coverage, is only going to reveal a small percentage of an application's defects. So what are you actually trying to do? Test for a reason -- don't just test to test. You can get into a cycle where you're writing unit test apon unit test and still releasing applications that are defect riddled. First you need to define a quality metric (a way to measure the quality of the application). "As few bugs as possible" isn't it! Ask yourself questions such as: What's a bug or defect? and How is the priority and severity of a defect determined? (e.g. Are spelling errors bugs? They may not be to a developer, but they may be show stoppers to a client.) Everyone wants to jump in and test up the wazoo but the problem is, if you test the wrong things and you don't know what a bug or defect is then your testing is potentially wasting time. Let's put this another way: let's say you have 80% coverage with all of your tests. What's preventing that 20% that you're not testing from containing 90% of the defects and 100% of the P1 show-stoppers?
Your goal is to identify the cross product of the areas of highest quality risks and the areas that are most important to the user of the application. These areas must have enough testing to ensure that the desired level of quality is met. For example, what if the 20% that you did not test just so happens to be the login page? The client cannot log into the application! So what's the point of testing or even writing the rest of the app? This is an obvious overtrivialization as the login page is an obvious element to test. But in reality, the show stoppers commonly fall into a trivial category. A number of projects that I've performed triage in the past suffered from this problem to an alarming degree. Months of work and testing when into components of the product that, at the end of the day, were not high on the clients list and were overshadowed by trivial defects. Plan ahead. Identify what determines quality in your application. Test effectively. |
|
|
Unless otherwise expressly stated, all original material of whatever nature created by Rob Grzywinski and included in this weblog and any related pages, including the weblog's archives, is licensed under a Creative Commons License. |