Semi Null



  • Debugging through code that contains unknown pointcuts is a royal PITA. This guy took it to the next level.

    He was writing a graft-on feature for our system. He created a common base class that all of his objects would extend. Ok. He chose to use Spring to construct, initialize and inject his objects. Ok. Then he decided to use AOP pointcuts to do a variety of what should have been implemented as normal inline processing.

    One of the problems with this is that depending upon the exact point in the construct/init/inject sequence used by Spring, some of the objects referenced in the pointcut code might be null, constructed but not yet initialized, or be missing things that were still to be injected. His solution:

      public class BaseClass extends Object {
        private boolean isInitialized = false;
    
    // This should be overloaded by every class
    public boolean isInitialized() {
      return isInitialized;
    }
    
    // This should be overloaded by every class
    public void init() {
      ...
      isInitialized = true;
    }
    
    // OP: These are called throughout the pointcut code
    
    public final static boolean isNull(BaseClass x) {
      return x == null;
    }
    
    public final static boolean isSemiNull(BaseClass x) {
      return !isNull(x) && !isInitialized();
    }
    
    public final static boolean isGoodToGo(BaseClass x) {
      return !isNull(x) && !isSemiNull(x);
    }
    

    }

    These three functions are then called all over the pointcut code.

    When I showed this to my boss, he rejected the implementation, ordered the guy to go back to the drawing board, move the pointcut code into normal init and handler methods (it was totally unnecessary to put it in pointcuts), and asked me to start a series of lunchtime classes about how to know when to and when not to.



  • Expect future methods such as "isSemiTrue()" for logical expressions and "isSemiCommitted()" for database transactions.

    If your project is successfully using AOP can you talk about it a little? I have played with AOP but have yet to use it "for real".

     

    Thomas

     



  • Maybe it's just me, but AOP kinda sounds like someone said "You know what would make this language better? COMEFROM!"



  • true
    false
    it's complicated



  • @dhromed said:

    true
    false
    it's complicated

    Are you saying that two trues can't marry? What about two falses? Homophobe!



  • @t_wheeler said:

    If your project is successfully using AOP can you talk about it a little?

    AOP is the kind of thing that makes profilers possible. In the places where I've seen it used, it was a hack so that folks wouldn't need to go and fix the affected functions. In these cases, it just hides what's really happening because when you're just reading the code, there's no function call for you to know to follow. If you don't know where a pointcut is implemented, or don't even know it's there, and you're debugging and step into what looks like a serial function call, you wind up in stack-hell.

    In this particular case, they used Spring - because they wanted to - to instantiate and inject POJOs; nothing that needed to be configured in any way, shape or form. Then they couldn't get the initialization right because of what Spring does under the hood (instantiate using the default, or if specified, the desired constructor, then call init methods; and somewhere in there it does injection of one instantiated object into another) so they decided to hack around Spring with point-cuts. It just obfuscates what's going on.

    To clean it up, we ended up getting rid of Spring and AOP and just instantiated/initialized the objects when needed. There was one pair of objects that were codependent, and we didn't have time to refactor them (it was done pervasively) so we just instantiated them both as uninitialized, and factored the initialization into a helper object. It's stupid, but given the time constraints (and a few well-written comments), it's now supportable.

    The only way I've ever seen AOP used properly was to add some rudimentary profiling to an application (e.g.: note the start time and end time of every method) because the company wouldn't pay for JProbe. I'm sure there are many other valid uses for it.

    AOP, like any other tool, has its uses; this was not one of them.



  • @ekolis said:

    @dhromed said:

    true
    false
    it's complicated

    Are you saying that two trues can't marry? What about two falses? Homophobe!

    Are you one of those nutcases who thinks it should be illegal for 2 unmarried booleans to XOR?



  • @snoofle said:

        // This should be overloaded by every class
        public boolean isInitialized() {
          return isInitialized;
        }
    

     

    Overloaded or overridden?  And what would the overrides do differently exactly?

     

     



  • @Ben L. said:

    @ekolis said:
    @dhromed said:

    true
    false
    it's complicated

    Are you saying that two trues can't marry? What about two falses? Homophobe!

    Are you one of those nutcases who thinks it should be illegal for 2 unmarried booleans to XOR?

    Please, sir, my kids read this site!



  • @Ben L. said:

    @ekolis said:
    @dhromed said:

    true
    false
    it's complicated

    Are you saying that two trues can't marry? What about two falses? Homophobe!

    Are you one of those nutcases who thinks it should be illegal for 2 unmarried booleans to XOR?

    Not only that, he keeps boolean 'em over it.



  • @jnz said:

    @snoofle said:

        // This should be overloaded by every class
    public boolean isInitialized() {
    return isInitialized;
    }

     

    Overloaded or overridden?  And what would the overrides do differently exactly?

    The comment in the code was overloaded, but they meant overridden.

    I'm fairly certain that each init was to initialize it's own class, and call super.init() for the base class hierarchy.

    They just did it wrong in every possible way at every turn.



  • @Ben L. said:

    @ekolis said:
    @dhromed said:

    true
    false
    it's complicated

    Are you saying that two trues can't marry? What about two falses? Homophobe!

    Are you one of those nutcases who thinks it should be illegal for 2 unmarried booleans to XOR?

    What about File Not Found?  Are you just going to pretend they don't exist?

     



  • @El_Heffe said:

    What about File Not Found?  Are you just going to pretend they don't exist?
    If they don't exist, it would go a long way towards explaining why they're Not Found.



  •  I've never understood Spring, or what it does


  • :belt_onion:

    @snoofle said:

    There was one pair of objects that were codependent, and we didn't have time to refactor them (it was done pervasively) so we just instantiated them both as uninitialized, and factored helped the initialization into a helper in a Factory object.
    FTFY



  • I have never heard of AOP (which apparently stands for Aspect-oriented programming before now. Based solely on reading the wikipedia article, I am partly horrified that it even exists.

    Even in the logging example, I can't see the value. It means that you need to write 2 additional methods for every proper method you write? And, you can't tell that these additional methods are being called in the method concerned? No thanks, I prefer my "caller -> callee" method hierarchy.



  • @pkmnfrk said:

    I have never heard of AOP (which apparently stands for Aspect-oriented programming before now. Based solely on reading the wikipedia article, I am partly horrified that it even exists.

    Yah ditto. Sounds like a over-complicated "solution" to a complete non-problem. The world would be a lot better if there were fewer people writing shit like this, and more people writing code that actually solves problems human beings need solved.



  • @Severity One said:

     I've never understood Spring, or what it does


    It's that time of year when all the animals get together and have fun.



  • @pkmnfrk said:

    Even in the logging example, I can't see the value. It means that you need to write 2 additional methods for every proper method you write?
    No, you're supposed to write maybe 3 or 4 methods (total) that use reflection/AOP libraries/magic to figure out where they are, and then shove them into multiple proper methods at once. The value is that you can write a function that prints "Entering <insert-method-name-here>", and rely on AOP to insert that method name and inject it into each and every proper method you make, without you having to remember to do so and without "polluting" your source code.@pkmnfrk said:
    And, you can't tell that these additional methods are being called in the method concerned?
    Nope! It's confusing as hell!



  • @snoofle said:

    some of the objects referenced in the pointcut code might be ... constructed but not yet initialized

    My brain just tried to parse that concept and threw an exception.  In OOP, the object initialization method is the constructor.  If it is possible in your code to have an object that's "constructed by tnot yet initialized," you are almost certainly Doing It Wrong.  Very wrong.

     



  • I've never heard of "pointcuts" before this thread. Took about five Wikipedia articles to even begin to make sense of it.



  • @Mason Wheeler said:

    @snoofle said:

    some of the objects referenced in the pointcut code might be ... constructed but not yet initialized

    My brain just tried to parse that concept and threw an exception.  In OOP, the object initialization method is the constructor.  If it is possible in your code to have an object that's "constructed by tnot yet initialized," you are almost certainly Doing It Wrong.  Very wrong.

     

    Nah. You see, the purpose of calling the constructor is just to be able to have a reference to the object. You should use "lazy initialization" to configure the object just before use. That way you don't waste processing power and memory.

     

     



  • @t_wheeler said:

    Nah. You see, the purpose of calling the constructor is just to be able to have a reference to the object. You should use "lazy initialization" to configure the object just before use. That way you don't waste processing power and memory.

     

     

    Wouldn't lazy initialization be the exception? Either way, you're using the same processing power and memory for initialization, it's just happening in a different place. So unless there's some co-dependency with another object that prevents initializing at construction, or cpu/ram is especially strained at construction (all of which are project specific constraints), why wouldn't you initialize when you construct as a general rule? Seems much less prone to confusion to do it that way.



  •  @lethalronin27 said:

    @t_wheeler said:

    Nah. You see, the purpose of calling the constructor is just to be able to have a reference to the object. You should use "lazy initialization" to configure the object just before use. That way you don't waste processing power and memory.

    Wouldn't lazy initialization be the exception? Either way, you're using the same processing power and memory for initialization, it's just happening in a different place. So unless there's some co-dependency with another object that prevents initializing at construction, or cpu/ram is especially strained at construction (all of which are project specific constraints), why wouldn't you initialize when you construct as a general rule? Seems much less prone to confusion to do it that way.

    I guess I ought to have put  in the </sarcasm> tag at the end of my post. Sorry 'bout that.

     

     



  • @Mason Wheeler said:

    @snoofle said:

    some of the objects referenced in the pointcut code might be ... constructed but not yet initialized

    My brain just tried to parse that concept and threw an exception.  In OOP, the object initialization method is the constructor.  If it is possible in your code to have an object that's "constructed by tnot yet initialized," you are almost certainly Doing It Wrong.  Very wrong.

     

    I would say that using the constructor to do initialization is probably the best thing to do, but object construction and resource initialization are not the same.

    For example, let's say you have some kind of ORM (Object-Relation mapping) system in place, and you have objects that represent queries. You may not want the queries to run at the exact time you create the object, maybe only when you try to access the data, in case you never use it at all. In that case, initializing the data is a potentially expensive operation that you don't need to do if you don't use it.


Log in to reply