- You should avoid the assertion and use an IllegalArgumentException.
- Why?
- Coz assertion will be disabled in production. It changes behaviour of your application and may lead to confuse.
- (?!)
Actually reasoning could be different, from "misuse of feature" coz "it generates java.lang.AssertionError that indicates significant error, like java.lang.OutOfMemoryError" up to "it put application on unpredictable state". I was pointed out to google such matter. And I actually did this, after all...
I won't dive into the jungle of distorted perception of the world. So many people, so many opinions. I don't care, really. That is depend on how bad experience had been in past. What actually I should admit, if experience was overdosed by Spring, the reasoning could jump a really unexpected direction. That actually may not surprise, if you never saw your application in profiler, just a Spring configuration… How you may know what really your application are doing, right?
So often in past, hunting the idea what the heck burning the Joules on a CPU, I can see the ridiculous situation when simple action followed by tremendous effort in attempt to do so. Just from top of my head, an update the element of array of rates of the currency pair with an incoming price may go through dozen of checks that this price is not null (or symbol it related to). Yes, dozen times! Damned org.springframework.util.Assert.* calls were everywhere. Just because application was written by many developers and each one decided to check input parameter(s) on each method entrance, on each f..n layer. I pretty sure that happen not only to me. Just have a look at the stack trace of your code, you may found similar cases on some of an execution paths. Especially if you uses Spring.
Yeah, it could be the my fault. Just a case of cognitive dissonance, but last time the insidious thought creeps my mind: continuous using of Spring may hurt. Let's have a look why the old fashion JDK assertions may be very attractive and I would encourage people to use them more broadly.
To avoid an abstract conversation about nothing let's look how usually those checks looks like. For a simplicity let's consider checks on NULL. (But all thinking below may be extrapolated on any preconditions that can be expressed by boolean expression. The NULL check actually could be extremely cheap so is worth to compare against.) So the classical assertion example, introduced with JDK 1.4:
assert null != object : "Object can't be null";
And its alternative. So emphatically lobbied ersatz:
if (null == object) { throw new IllegalArgumentException("Object can't be null"); }
Or even more infantile:
if (null == object) { throw new NullPointerException("Object can't be null"); }
And finally, more "advanced" variant:
Assert.notNull(object, "Object can't be null");
Ok, that is not so bad as it may look like. Yes, eventually all these checks could be elided by Hotspot. After all devirtualizations and method inlining that expand the horizon of optimisation and the meaninglessness of those checks may become obvious even to the most stupid JIT. Eventually. After the it shoveled magabytes of other shit and finally gets those holy checks. Unless, of course, an application is under Spring, with its indefatigable intention to weave everything with AOP injectors that just impossible to inline. No matter how smart JIT is, due the reflective-like proxying of a calls (either with CGLib or with JDK dynamic proxy). Yes, even so, the null pointer check is really very cheap. It could be managed by handler registered with hardware trap so that effectively eliminates an any explicit instruction. However such trick is a barrier to optimisation and reduce its scope. That could cost.
But let's avoid an preemptive optimization. (Ironically) Who would care about performance with a Spring? We are writing an application, not an OS or a DBMS, right? But our application will behave exactly the same way no matter where it is executed. Hmm. Really?
What actually might we expect on 2nd (or 3rd) times of such checking? As far as our application is modularized and many people are involved in development, we are doomed to check the same preconditions on each complete unit that is involved in the specific execution path. (We do remember we should check input parameters!) Is there anybody who think that on Nth times we may get something unexpected when we check that object is NULL? Moreover, from static analysis look point, we should cover by tests that code as well coz it goes to production. So, for each complete unit we should consider the silly tests that checks behavior on preconditions that never happen in a real life. Is it really what we would suppose to do?
May be we really need something else that would be executed on testing stage and eliminated in production? Kind of JDK assertions, no? On first, let's recall the definitions:
There is much more, actually. JLS, btw, is a very interesting reading. Please have a look in mean time.
And note, there is nothing about a special usage case or feature. Its just about of a simple boolean expression that can be evaluated or not. It doesn't dictates which purpose of those expression are and when they can / should be evaluated. That is up to you, to turn them on or off during execution. And moreover they are switched all together at once, just by command line parameter:
java -ea <class name>
Look simple, isn't? And without any configuration and inversion of control. (Btw, may be therefore people so afraid assertions, eh? Just because they are configured without Spring?) Really which aspect of CS religion prohibit to use assertion for an input parameters check? Yes, they are turned off by default, and so? Might be that is what we really need, eh?
During IT evolution the whole science was built around to simplify the software development. Was invented compilers that compiles the source code and thus the checking of static correctness of our code is performed. Linkers that bounds compiled code with an already compiled libraries and hence guarantee that our code are consistent with execution environment. We all are writing the tests that are executed as part of application build process and thus checks an application in dynamics. More and more things, methods, theories and algorithms were invented to help you build software. And believe you or not, all these are are not going to production. There is only our code and environment used by it. And thats it. Moreover even your code (in case of Java) are heavily modified and optimised by Hotspot. And you even can't imagine how dramatically it does. It doesn't bother you, no? So, what the heck you so miss the assertions? They done what they suppose to do on testing stage. Tests are executed, all test cases are checked - your code performed well. So, what do you expect from them in production?
That insane addiction for a "checks" looks really unhealthy, though. I would excuse it is an religion aspect, but we talking not about holy things, right? I would prefer an explicit checks that will go to production if and only if they constraints the class contract, they are the part of business logic. We can't rely on assertions here coz this checks are the part of our application use cases. For instance:
- an JCA adapter should check that incoming price (or its symbol) is not null or
- a Struts form fields should be validated on allowed values.
And it sounds for me as explicit checks. And to be honest that is not always followed by exceptions. We may just do an alternative execution path without any exceptions thrown. And we might do this checks only once, on start point. Make a sense?
Would you say that checking that the incoming price is not a null are part of your business logic on each layer / tier? Or may be on each unit? And that need to be checked dozen times? If it is yes still, that is not a price, dude. That looks like a bozon of Higgs, and you are not writing the software, you are seeking the proof of God presence.
No comments:
Post a Comment