Santosh K. had seen all the emails about the upcoming code audit.
He thought Oh, I’m safe, all my code has been in Production and working fine, surely someone would have complained! But, alas, here he was – in the main conference room having to explain himself to an auditor for authoring what was declared as being the worst offending code in the codebase.
Santosh could feel the auditor’s piercing stare. He could practically hear him thinking “Why oh WHY?! Why would you ever code a getter like that?”
Santosh cleared his throat and switched his laptop over to the overhead projector. To make matters worse, the after effects of the two coffees from earlier this morning had just hit his lower regions.
"W-Well, you see, in object encapsulation, when one object requests another object to perform some task, it's supposed to send a message to the other object.”
“I wanted to create a base class to encapsulate all the DB work, and it would have two queues to handle inbound and outbound messages. The widgets could then just extend it. To have only one instance of each queue, I needed to have a static queue for all instances of Widget, and each getter would send a message, via the queue, to the asynchronous thread in the base class, which would perform the requisite action and return the data (also via a queue-message) to the getter.”
The auditor shot Santosh a cocked eyebrow of seeming disapproval as the slideshow progressed.
“Unfortunately, no matter how I coded it, I couldn't get the messages to go to the right Widget instances. This was as good as I could make it:"
class BaseDAO extends Thread { private ArrayBlockingQueue<String[]> requestQueue = new ArrayBlockingQueue<String[]>(10); private ArrayBlockingQueue<String[]> responseQueue = new ArrayBlockingQueue<String[]>(1 0); public BaseDAO() { start(); } public void addRequest(String []request) { requestQueue.add(request); } public String [] getResponse() { return responseQueue.take(); } public void run() { while (true) { try { String []request = requestQueue.take(); if ("GETQTY".equalsIgnoreCase(req uest[0])) { String []response = new String[1]; response[0] = "" + selectQuantityFromDB(request); responseQueue.add(response); continue; } // process other get-requests here } catch (Exception e) { // log error } } } private Integer selectQuantityFromDB(String []request) throws Exception { String schema = request[1]; String table = request[2]; String where = request[3]; String sql = "select count(1) from " + schema + "." + table + " where " + where; Connection con = ...; PreparedStatement ps = con.prepareStatement(sql); ResultSet rs = ps.executeQuery(); rs.next(); Integer n = rs.getInt(1); rs.close(); ps.close(); con.close(); return n; } } class Widget extends BaseDAO { public Integer getNumWidgets() throws Exception { addRequest(new String[]{ "GETQTY", "SchemaName", "TableName", "where-clause-expression"}); String []response = getResponse(); return Integer.parseInt(response[0]); } }
A-And it is used as:
Widget wd = new Widget(); int nw = wd.getNumWidgets();
“So,” the auditor summarized, “each and every time you call a simple getter, it involves?” as Santosh pulled up the following slide…
POJO-Widget is instantiated and runs thread Widget.getter is called getter adds message to queue getter blocks while reading queue to get response base thread run-method reads message from queue base thread run-method calls appropriate function utility function calls the database to get the data base thread run-method constructs and puts response on queue getter gets response off of queue getter converts response back into usable form and returns it
…and then shifted into full-on confession mode.
“...and I didn't use cached database connections.”
“...and there is a separate thread with two queues for every instance of Widget.”
“...and the result is not cached, so all of this happens every time the getter is called.”
“...and if there is an exception, it gets logged, but no message is sent back to the caller of the getter, which just hangs there waiting for a response that will never come.”
“...and I've since learned what sending a message to an object actually means.”
Santosh finally sighed and slumped in his chair.
“I figured that once I debugged it, there wouldn't be any more exceptions, so that wouldn't be a problem,” Santosh meekly offered, “I suppose that I could have used some guidance with the design, but I wanted to show my superiors that I could do it.”
“I understand. In fact I’m glad that you identified the problems in your code, it’s the first step to being a better developer. Believe me, you’re doing fine based on your experience level,” the auditor assured, “Just remember - after you’re hired when your internship is over, NEVER be afraid to ask for help.”