<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3558296680025304582</id><updated>2012-01-30T07:12:06.923-05:00</updated><category term='linux'/><category term='sandbox'/><category term='system'/><category term='sudo'/><category term='android'/><category term='tools'/><category term='jdbc'/><category term='exception handling'/><category term='web-development'/><category term='java'/><category term='multi-threading'/><category term='cache'/><category term='debugging'/><category term='refactoring'/><category term='security'/><category term='optimization'/><category term='maps'/><category term='database'/><category term='oracle'/><title type='text'>Process Fork</title><subtitle type='html'>A discussion of all things related to developing software.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-2505152234854160128</id><published>2010-04-21T22:14:00.000-04:00</published><updated>2010-04-22T10:16:26.449-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cache'/><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android Data Caching</title><content type='html'>One of the applications I'm building for the Android platform is meant to be used in remote regions of the developing world. While cellular coverage is getting more ubiquitous across the globe, there will inevitably be dead zones. With this in mind, all data-driven aspects of the application are being designed to degrade gracefully when there is no data connection available. One way in which this is being handled is by pre-caching data whenever possible.&lt;br /&gt;&lt;br /&gt;Solving this problem in an application-specific manner is fairly straightforward. There are essentially 3 steps:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Identify those items that you can cache - Since much of the information for this application is geo-coded, deciding what to cache is usually pretty straightforward (I can, for example, pull in all the data points tagged within a given radius of the device's current position).&lt;/li&gt;&lt;li&gt;Watch for data connectivity changes and download cacheable data whenever a connection is available - registering a broadcast receiver to listen for status change messages makes this fairly trivial&lt;/li&gt;&lt;li&gt; Store data locally that needs to be sent and send it whenever you have a data connection - again, a broadcast receiver makes this simple.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Beyond this core functionality, I've also built some ancillary features to allow users to better control their bandwidth usage in the event that they're not on an unlimited plan (a user can opt to only perform cache downloads if they have a WiFi connection as opposed to a cellular connection and they can choose what types of data they want to cache).&lt;br /&gt;&lt;br /&gt;While this works well for the application, the real problem I'd like to address is doing this in a generic, reusable fashion. I haven't done so yet, but I am planning on building a library that can handle both cache population and data upload. The library would handle the nuts and bolts of listening to status changes and initiating downloads/uploads based on user preferences while delegating the decision of what to download (and how to do it) to user-supplied helper classes. These helpers can extend a base CacheAwareHelper class that, on invocation can first check to see if the data is already in cache and, if not, then invoke the method that actually performs the fetch of the data from the remote location. The result, in addition to being returned to the calling method, can then be cached.&lt;br /&gt;&lt;br /&gt;This is still just a thought and I'm sure the details will flex a bit once I start writing the real design and implementation. I am still thinking about how to handle cache invalidation such that things are only evicted when they absolutely need to be. Stay tuned for a follow-up post once the library is done. At that time I'll include a few diagrams to show how it works. If anyone is actually reading this blog, I'd love to hear some feature suggestions in the comments as I'm planning on releasing this library as open-source.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-2505152234854160128?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/2505152234854160128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2010/04/android-data-caching.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/2505152234854160128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/2505152234854160128'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2010/04/android-data-caching.html' title='Android Data Caching'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-7746476462205402556</id><published>2010-03-25T21:48:00.001-04:00</published><updated>2010-03-26T14:35:05.281-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>An Exercise: Porting a Java Applet to Android</title><content type='html'>In 2003 I wrote a simple casual game for a computer graphics course as part of my masters' degree program. While the game itself was nothing special -- a simple 2-dimensional app where balls bounced around the screen and the player had to click on each of them in ascending order before a timer expired -- I thought it would be worth revisiting since it would provide a way to learn the way in which to handle graphics and animation on the Android platform. &lt;br /&gt;&lt;br /&gt;Since the initial implementation of the game was an assignment to introduce the concept of double-buffering and simple animation, not much attention was paid to organizing the game logic in a manner that made it easy to add new game modes and rules. To facilitate this, the code was completely reorganized into a few discrete components. In the newly refactored game, the overall architecture is still pretty simple. It consists of a model class that implements all the game rules, score keeping, and the current state of the game, a custom data-structure to maintain the state of individual "balls", an animation thread that determines if and when to draw the objects and a view class that services as the bridge between the Android system (and things like touch events, menu key presses, etc) and the game. In the sections that follow, each of the components will be outlined with special emphasis on anything that was done differently due to capabilities/limitations of the Android platform.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Model &amp; Data Structures:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The model class was responsible for maintaining the current state of the game. This state includes the score, the current level, the amount of time remaining, the list of all the Ball objects which, in turn, contain their position, that will be displayed and the current game mode (running, paused, game-over, etc). For simplicity of maintaining game state upon activity pause, all members of the model class must be serializable since they will be serialized into and out of a Bundle object when the game's Activity is suspended or resumed.&lt;br /&gt;&lt;br /&gt;In addition to holding the state, the model class needed to contain the game logic. This consists of two main functions: determining if a particular set of coordinates are within the "target" ball and determining if two balls have collided. In the original implementation, this was done via an inelegant, brute-force manner that was expensive in terms of both memory and CPU cycles. Since the Android platform is more resource-constrained than your average desktop, reducing the processing required for each iteration through the program's main loop was necessary.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Collision Detection:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the old version of the game, a two-dimensional array of bits the same size as the screen was allocated and the bits were set to either 0 or 1 based on whether or not some ball occupied that pixel. Every time the ball moved, the bits at its origin location were cleared and the bits at the destination were checked. If they were already set, a collision occurred and the ball changed direction and speed (i.e. it bounced) but if the bits were clear, then the space was empty so the ball's position was updated and the bits were set.&lt;br /&gt;&lt;br /&gt;To reduce the need to iterate over every pixel on the screen, the new implementation segments the playing surface into a grid where each cell is approximately 100x100 pixels. An ArrayList is allocated for each cell in the grid and balls are to the list that corresponds to the cell in which their center lies. Since balls are always smaller than the cells, a ball in cell i,j can only collide with a ball that is in the 9-cell "superblock" surrounding it (cell i,j and the up-to 8 cells that surround it). To check for collisions, the list of all balls in the superblock is retrieved and the Euclidian distance is calculated between the ball being checked and every other ball in the list. If the distance measure is less than the sum of the balls radii, then the balls are overlapping and thus have collided.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Animation:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The actual logic for updating the state of all the model components (i.e. moving all the balls) remained fairly unchanged from the original implementation. What was added, however, was logic to attempt to keep the frame rate constant regardless of the CPU clock speed on the target device (something that, in retrospect, should have been in the original implementation too). To keep the animation looking smooth, a frame rate of 25 fps was desired. This equates to 40 milliseconds per frame. The code in the animation loop tracks how long it takes to do the state update and the drawing and if that time was less than 40 ms, it will sleep for the remaining time. This approach is about as simple a mechanism as can be employed and, obviously, it is totally ineffectual if the actual time needed to render the frame exceeds 40 milliseconds. Luckily, for this game, that time is sufficient on all device configurations tested.&lt;br /&gt;&lt;br /&gt;Communication between the animation thread and the UI thread was another item that needed to be handled in an Android-specific manner. Some events in the game were not triggered by user interaction but rather by a condition within the model (the timer expiration, for instance). When the timer expired, a modal dialog box showing the final score was to be displayed. Rather than drawing one on the surface manually, it was much easier to use the built in DialogBuilder to pop-up an AlertDialog. If this was done directly in the model class as part of the updateState method (the method called by the animation loop to update the ball positions, timer and other state information) it would throw an exception since this was not running on the UI thread. Instead, a &lt;a href="http://developer.android.com/reference/android/os/Handler.html"&gt;Handler&lt;/a&gt; had to be used to pass a message from the animation thread back up to the UI thread. The message could, in turn, contain a custom GameEvent class that allowed the UI thread to react appropriately.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;View:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To adapt the view classes, the first thing that had to be done to port the game was to re-plumb all the drawing logic. Since the original implementation was created using the Java AWT and drawn directly to the ContentPanel of an Applet using the methods of &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/awt/Graphics.html"&gt;java.awt.Graphics&lt;/a&gt; all the code that actually wrote the pixels to the screen needed to be revisited.&lt;br /&gt;&lt;br /&gt;Android provides a Canvas upon which arbitrary shapes and text can be drawn. If you want to add the canvas to a view that may or may not contain other views, a &lt;a href="http://developer.android.com/reference/android/view/SurfaceView.html"&gt;SurfaceView &lt;/a&gt;is a good choice since it provides a drawing surface embedded in the normal view hierarchy. As the developer, you can control the contents and size of the surface but the system takes care of positioning it at the right place on the screen (based on whatever else is in your view hierarchy).&lt;br /&gt;&lt;br /&gt;Drawing on an Android Canvas was not that different from drawing on a JPanel. The difference, however, was in the view life cycle. Just like any other Android application, the system can suspend your Activity any time the user does something that causes app to lose focus (like taking a call, for instance). At that point, the surface on which you're drawing may be destroyed (but not always).&lt;br /&gt;&lt;br /&gt;In response to the Activity pause event, the game pauses the animation (by setting a volatile flag on model class) which tells the animation routine to stop updating the position of the balls and to stop decrementing the timer. At this point, the animation thread runs to completion (to be a good citizen and avoid busy-waiting in the background). When the user returns to the game, the game animation can be resumed. What we cannot do, however, is resume the thread (since you cannot call Thread.start() on the same thread more than once). Instead, the handler must create a new thread and seed it with the information from the "old" game model (instead of creating a new model instance) and start the thread.&lt;br /&gt;&lt;br /&gt;Understanding the life cycle of the view classes is important. It is worth pointing out that it is not handled correctly in the &lt;a href="http://developer.android.com/resources/samples/LunarLander/index.html"&gt;Lunar Lander&lt;/a&gt; sample application included on the Android development site. In that example, the surfaceCreated method on the view class starts the thread that was initialized in the constructor. The problem is that surfaceCreated can be called by the system whenever the surface regains the foreground (even though the View's constructor may not have been called since it is the same view instance). Since the thread is a member variable and may have already been started, calling start could (and often does) result in an exception. This isn't meant to be a critique of the example code (I've said it before and I'll say it again: the wealth of examples and documentation is one of the strengths of the Android platform) but it should be noted that not everything in the example code is 100% correct all the time and if something "feels" wrong, it very well may be.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Impressions and Future Work:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Porting this application was a worthwhile exercise. Since the "game" portion was already done, it allowed me to focus on the nuances of the platform itself rather than the mechanics of the game play. All said and done, it took approximately 15 hours from start to finish (it could have been a lot shorted had I kept the brute-force collision detection instead of refactoring that). It was time well-spent in that it helped illustrate some of the finer points of handling the animation (frame rate limiting,  surface life cycle, percolation of events back up to the UI thread).&lt;br /&gt;&lt;br /&gt;Despite the fact that game itself is exceedingly simple, I plan on adding to it in the coming weeks. I am contemplating using the game as a proof-of-concept for a server-side component that can handle reporting high scores, issuing user challenges and handling teams/clans. I plan on exposing the server platform via a REST API and building a client library that could be included in any Java application for easy integration.  I'd be interested in hearing if any of the (few) people who read this think there is any merit in a system like that and, if so, what other features it should support.  I hope to have more to say on this topic soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-7746476462205402556?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/7746476462205402556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2010/03/exercise-porting-java-applet-to-android.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/7746476462205402556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/7746476462205402556'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2010/03/exercise-porting-java-applet-to-android.html' title='An Exercise: Porting a Java Applet to Android'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-689129218931624722</id><published>2010-03-09T20:24:00.000-05:00</published><updated>2010-03-10T17:26:23.221-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maps'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Google Maps API  Keys on Android</title><content type='html'>For any Android devices with the Google APIs add-on installed, there is a very convenient way to integrate Google Maps with your application: the MapView. Using this view allows an app developer to create custom interfaces using other components rather than just launching the built-in Google Maps application via an intent. Needless to say, it is a very powerful feature that can be added with minimal effort.&lt;br /&gt;&lt;br /&gt;To use this feature, however, one has to register for an application key from Google. Normally, this would be a reasonable request. In this day and age of mash-ups and public APIs, registering for keys is the status quo. What differs here is that the public-key fingerprint of certificate used to sign the application must be submitted in order to get the key. The key is generated using this fingerprint as a seed for the key generation and will only work when deployed in an app signed by that same certificate. At first glance, this too is perfectly reasonable. The annoyance comes when one realizes that a different certificate is used to sign your application for development/debugging than is used for production release (which is the default behavior for the Android Development Toolkit). If 2 different certificates are used, two different keys are needed and, since the key is embedded in the layout file that uses the MapView, one must have two different build configurations - one that uses the debug key and another that uses the release key in the layout file.&lt;br /&gt;&lt;br /&gt;This leaves one with little recourse but to either use the production certificate during development/debug, manually change the key in the layout file before doing a build, or use a tool like ANT or Maven to swap in the right version of the file at build time based on a profile. I was planing on configuring Maven for this project using an &lt;a href="http://code.google.com/p/maven-android-plugin/"&gt;open-source Maven ADK plug-in&lt;/a&gt; at some point anyway, looks like I have another reason to do so.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-689129218931624722?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/689129218931624722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2010/03/google-maps-api-keys-on-android.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/689129218931624722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/689129218931624722'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2010/03/google-maps-api-keys-on-android.html' title='Google Maps API  Keys on Android'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-8884938345058998758</id><published>2010-02-21T09:37:00.000-05:00</published><updated>2010-02-22T09:39:43.259-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android Optimization</title><content type='html'>Since the Android platform uses the Java programming language and, at a high level, seems to support a large portion of the language, it is easy to forget that one is still developing for an embedded device. I am, by no means, an expert -- in fact, this is my first foray into the world of embedded programming but there is no harm in outlining the little bit I've learned if it has a slight chance at helping someone else. This is the first platform on which I've really had to think of "micro" level optimizations (rather than macro, algorithmic optimization). It definitely adds another dimension to the analysis one must undertake when attempting to solve a problem.&lt;br /&gt;&lt;br /&gt;To understand the best way in which to write Android programs, one first must understand a bit about the virtual machine at the heart of the system: The &lt;a href="http://en.wikipedia.org/wiki/Dalvik_virtual_machine"&gt;Dalvik VM&lt;/a&gt;. I won't go into details about the internals of the VM, but suffice it to say that the fact that it is made to run on devices with limited memory and CPUs, the compiler makes some choices in bytecode generation that differ from those that would be made by Sun's compiler.&lt;br /&gt;&lt;br /&gt;In starting development on my Android project, I came across &lt;a href="http://developer.android.com/guide/practices/design/performance.html"&gt;this page&lt;/a&gt; on the developer resources site. While the page listed a number of things that I would not have even thought of  -- the way in which &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/foreach.html"&gt;enhanced for loops&lt;/a&gt;, for example, result in the implicit allocation of an Iterator -- I was glad that the first bullet point was "Optimize Judiciously." This advice is probably the most important on the page. They even goes as far as including one of my favorite quotes on the subject:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.&lt;br /&gt;—Donald E. Knuth&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The dangers of premature optimization are by no means limited to the realm of embedded programming (though they may be even more precarious since some of the optimizations done in this space may seem odd to developers accustomed to working in the desktop world) and I've seen them derail or over-complicate a number of projects in the past. Maintainability and understandability are just as important as correctness when writing software.&lt;br /&gt;&lt;br /&gt;Pontificating aside, here is the process I am taking with respect to optimization:&lt;br /&gt;&lt;br /&gt;1. Devise the most efficient algorithm for the logic I'm performing: this is no different than I would do on any other platform (just because you have more resources doesn't mean your software should use all of them).&lt;br /&gt;&lt;br /&gt;2. Make the "easy" optimizations the first time around: this includes things like declaring variables using concrete classes rather than interfaces, only using the enhanced for loop when an iterator would be needed anyway, etc&lt;br /&gt;&lt;br /&gt;3. Make the code as simple and clean as possible: again, this is no different than any other platform&lt;br /&gt;&lt;br /&gt;4. Refactor often: this is probably the most important step. At this point, I've refactored so much of the application that I've basically rewritten it twice over. After each refactoring round, the code is cleaner, more efficient and more maintainable. I have paid special attention to the view portion of the code as small changes there can have a huge impact on performance.&lt;br /&gt;&lt;br /&gt;There is nothing novel about the approach outlined above. My only point in calling it out is that the sequence is important. I don't start the refactoring phase until I'm sure that the algorithm is correct and the code implementing the logic is as simple as it can be. This helps keep things maintainable. I also endeavor to keep my layers and object dependencies clean. Performance "optimization" is not an license to throw away decades of solid software design principles. Keeping the components well-defined an clean may seem like you're leaving a few more CPU cycles of performance gain on the table but, in the long run, one is probably still better off with quality code that (so long as it performs well enough -- and what "enough" is varies depending on the application) versus spaghetti code that uses the fewest possible CPU cycles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-8884938345058998758?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/8884938345058998758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2010/02/android-optimization.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/8884938345058998758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/8884938345058998758'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2010/02/android-optimization.html' title='Android Optimization'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-5927076742566814491</id><published>2010-02-18T21:23:00.001-05:00</published><updated>2010-02-19T09:26:03.187-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android Development</title><content type='html'>I have recently started programming for the Android platform. This post is the first in what I plan to be a series discussing my experience writing code for this environment. That being said, I'll jump right into it.&lt;br /&gt;&lt;br /&gt;We chose the Android platform for our application because it offered a lot of capabilities that we could take advantage of right out of the box (camera for video/image capture, GPS for location-awareness, Wi-Fi and Bluetooth for fast data transfer, etc).  The free/open nature of the platform was also appealing. At this point, I've implemented the core use cases for all those features and am now concentrating on improving the user experience, bug fixes, and overall polishing. So far, I have no regrets as I have not yet come across a use case I could not implement in a fairly straightforward manner.&lt;br /&gt;&lt;br /&gt;At the risk of sounding like a Google Fanboy, I have to say that I really do enjoy working on the Android platform. The core reason is that Google really put a lot of thought/effort into the &lt;a href="http://developer.android.com/sdk/index.html"&gt;SDK &lt;/a&gt;and development tools. For &lt;a href="http://eclipse.org"&gt;Eclipse &lt;/a&gt;users, there is an Android Development Tools &lt;a href="http://developer.android.com/sdk/eclipse-adt.html"&gt;plug-in&lt;/a&gt; that makes building and debugging applications as simple as a single click. Additionally, since Android has gone through a fairly rapid evolution and there is a wide variety of devices running a number of different versions of the OS, the emulator provided with the SDK makes it simple to test different device configurations running differing platform versions. While emulators are great for initial debugging, there is no substitute for running on an actual device. Since the platform is designed to be open, deploying one's applications to a real device is as simple as turning on an option in the phone's settings menu, plugging it into your PC and clicking a button in Eclipse. Again, none of these things are groundbreaking, but having full IDE support makes it much easier to concentrate on the details of the application rather than the nuances of packaging.&lt;br /&gt;&lt;br /&gt;That last point applies to a lot more than just Android. Whether it is IDE plug-ins or a life-cycle management tool like &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt;, comprehensive tooling makes getting up and running on a project easy. I cannot overstate how much of a difference Maven has made on other projects, especially those with complex builds and many dependencies. That being said, I am planning on trying to integrate Maven with my Android builds using this &lt;a href="http://code.google.com/p/maven-android-plugin/"&gt;plug-in&lt;/a&gt; shortly (for reasons I'll outline in a subsequent post).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-5927076742566814491?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/5927076742566814491/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2010/02/android-development.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/5927076742566814491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/5927076742566814491'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2010/02/android-development.html' title='Android Development'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-8334675656940342057</id><published>2009-05-01T08:07:00.002-04:00</published><updated>2009-05-01T08:09:34.803-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multi-threading'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='sandbox'/><category scheme='http://www.blogger.com/atom/ns#' term='system'/><title type='text'>Proper System Properties</title><content type='html'>&lt;p class="MsoNormal"&gt;In &lt;a href="http://en.wikipedia.org/wiki/Sandbox_%28computer_security%29"&gt;sandboxed &lt;/a&gt; programming platforms like .Net and Java, the developer is insulated from the details of the underlying machine upon which the code is running. At times, however, it is often useful to have more knowledge about the environment. One way to provide such information without introducing any machine-dependent code into the sandbox is via system properties. They can be implemented in a number of ways, but the most common is a set of name/value pairs that can be accessed via a core class in the language runtime. In java, one can get a list of all the system properties using &lt;b&gt;System.getProperties()&lt;/b&gt;.&lt;/p&gt;&lt;p class="MsoNormal"&gt;The properties are not limited to those set by the language virtual machine; they can be extended to include any property the developer wants to set. Most languages provide a way to do this at virtual machine initialization or programmatically within the application code. Having system properties is a powerful tool and can enable code to handle certain conditions based on the capabilities of the underlying machine in an elegant way. With power, though, comes responsibility.&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Some developers have been abusing this construct and using it as if were a container for global variables: instead of passing parameters into methods, a method will simply look up a value from the system properties. This is especially egregious when the property is not universally true from the system perspective. One such example is specifying a HTTP proxy. In Java, the default HttpConneciton class uses system properties to specify a proxy. In most cases, this is fine, but in some enterprise environments, the proxy server one must use depends on the address being accessed. If your program needs to access two addresses that use different proxies, then changing proxies involves updating the values in the system properties. Again, this is usually not a big problem, but if you have a multi-threaded program, this could cause a race condition unless one enforces the atomicity of the property update with the HTTP request. Depending on the application requirements, this may or may not be an acceptable answer.&lt;/p&gt;&lt;p class="MsoNormal"&gt;While there is not much one can do about the proxy issue (outside of using some other library to make HTTP requests), developers &lt;i&gt;can&lt;/i&gt; prevent imposing similar limitations on their own code. Since it is impossible to anticipate every way in which code may be used and it is equally impossible to know every possible system configuration, the use of system properties that do not actually describe the &lt;i&gt;system&lt;/i&gt; upon which the code is executing should be avoided.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-8334675656940342057?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/8334675656940342057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2009/05/proper-system-properties.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/8334675656940342057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/8334675656940342057'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2009/05/proper-system-properties.html' title='Proper System Properties'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-2157452777567939002</id><published>2009-04-24T13:14:00.004-04:00</published><updated>2009-04-24T13:21:43.430-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multi-threading'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='exception handling'/><title type='text'>Threads &amp; Exceptions</title><content type='html'>&lt;p class="MsoNormal"&gt;In this age of multi-core processors, being able to write efficient and correct multi-threaded programs is becoming increasingly important. Unfortunately, however, writing such programs is not a trivial task. Deadlocks, race conditions, and thread starvation are among the myriad pitfalls that could break one's programs. Complicating matters further are “legacy” (for lack of a better term) third-party libraries that may or may not be thread-safe.Errors due to threading issues are among the worst class of bugs: the elusive &lt;a href="http://en.wikipedia.org/wiki/Unusual_software_bug"&gt;Heisenbug&lt;/a&gt;. The use of a good profiler tool is essential in tracking down and eradicating bugs like this.&lt;/p&gt;&lt;p class="MsoNormal"&gt;Just as important as knowing how to avoid writing code subject to deadlocks and race conditions is knowing how your programming environment responds to bugs that occur in child threads. In the Java programming language, for example, one's program could find itself in an unexpected state due to an uncaught exception in a child thread. When one is running a single-threaded program and an uncaught exception occurs the system will exit and print the exception's stack trace to standard error. Not graceful, but also not a very subtle error condition. When an uncaught exception occurs in a child thread, however, the flow of control is as follows:&lt;/p&gt;&lt;ol&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;li&gt; The JVM checks the UncaughtExceptionHandler of the Thread object. This is null by default. If you wish to specify your own handler, you must call the setUncaughtExceptionHandler method on the thread instance (usually before starting its execution). Setting this handler only applies to the thread instance upon which you installed the handler (not descendant threads).&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;li&gt;If the thread does not have an UncaughtExceptionHandler, then the ThreadGroup is checed to see if it has a handler of its own.&lt;/li&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;li&gt;If the thread's ThreadGroup does not provide a handler, then the default handler is invoked. Unless the programmer changes it (by calling the static Thread.setDefaultUncaughtExceptionHandler method) the default handler simply prints the exception's stack trace to standard error.&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;/ol&gt;&lt;p class="MsoNormal"&gt;The Java API documentation contains a very important &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html#setDefaultUncaughtExceptionHandler%28java.lang.Thread.UncaughtExceptionHandler%29"&gt;warning &lt;/a&gt;for those programmers who want to provide their own default UncaughtExceptionHandler:&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p class="MsoNormal"&gt; The default uncaught exception handler should not usually  defer to the thread's ThreadGroup object, as that could cause  infinite recursion. &lt;/p&gt;&lt;/blockquote&gt;&lt;p class="MsoNormal"&gt;When developing code that has any potential for reuse in other applications, one has a responsibility to take threading considerations into account. If it is decided that a method or class will not be thread-safe, then it is the developer's responsibility to clearly document this limitation in both the in-code documentation (i.e. JavaDoc) and any other API/Development guides.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-2157452777567939002?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/2157452777567939002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2009/04/threads-exceptions.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/2157452777567939002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/2157452777567939002'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2009/04/threads-exceptions.html' title='Threads &amp; Exceptions'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-6225015957440461064</id><published>2009-03-18T07:14:00.002-04:00</published><updated>2009-03-18T07:16:31.197-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><category scheme='http://www.blogger.com/atom/ns#' term='jdbc'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>Oracle RAC Load Balancing</title><content type='html'>&lt;p class="MsoNormal"&gt;Relational databases play a central role in many software systems. In many enterprises, Oracle is the RDBMS of choice. Among those, many mission-critical systems make use of Oracle's Real Application Cluster (RAC), a load-balanced multi-node database that can handle failures of individual nodes without causing an outage. This &lt;a href="http://www.datadirect.com/developer/odbc/odbc_oracle_rac/index.ssp"&gt;article&lt;/a&gt; provides a decent summary of RAC.&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;While RAC has many features and advantages (as well as trade-offs), that isn't why this post is here. It is here because the way in which the Java ODBC driver establishes a connection to the RAC is worth understanding in the event that one suspects a connectivity issue between the client code and the database server.&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;For a Java developer, using RAC is very similar to any other Oracle database. Usually, the only indication that you're using a RAC is the contents of your connect string. It typically lists a number of database server addresses in an &lt;b&gt;ADDRESS_LIST&lt;/b&gt; element. For the purposes of illustrating the discussion, an example may be helpful:&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;i&gt;jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = dbserver1.somedomain.com)(PORT = 12345))(ADDRESS = (PROTOCOL = TCP)(HOST = dbserver2.somedomain.com)(PORT = 12345))(LOAD_BALANCE = yes)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = dbServiceName.somedomain.com) ) )&lt;/i&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;There are two types of load balancing offered by the RAC: client-based load balancing and server-based load balancing. The system can be configured to use one, both or neither forms of load balancing.&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;The &lt;b&gt;LOAD_BALANCE &lt;/b&gt;element in the connect string above specifies that the client code should perform its own load balancing. Essentially, this means that the client will randomly choose one of the servers from the &lt;b&gt;ADDRESS_LIST&lt;/b&gt; whenever a connection is requested.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If server-based load balancing is enabled, a listener service provides automatic load distribution across&lt;i&gt; all nodes in the RAC&lt;/i&gt;. The listener will use the query optimizer to determine which node in the RAC should service the request (based on their current workload, machine profiles and, in newer versions of Oracle, admin-specified rules).&lt;/p&gt;&lt;p&gt;If one were to use the connect string above and server-based load balancing were enabled, the sequence of events that would occur when a call to &lt;i&gt;DriverManager.getConnection(...)&lt;/i&gt; is invoked are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The driver selects &lt;i&gt;dbserver2&lt;/i&gt;.&lt;i&gt;somedomain.com&lt;/i&gt; (this choice was made at random by the driver) and issues a connection request.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The listener on &lt;i&gt;dbserver2&lt;/i&gt;.&lt;i&gt;somedomain.com &lt;/i&gt;determines that the most under taxed node in the RAC is &lt;i&gt;dbserver&lt;b&gt;3&lt;/b&gt;.somedomain.com &lt;/i&gt;and returns it to the client. &lt;b&gt;&lt;i&gt;NOTE: &lt;/i&gt;&lt;/b&gt;this assumes that the RAC has 3 nodes. It is important to note that all the nodes do NOT need to be included in the connect string... the nodes in the &lt;b&gt;ADDRESS_LIST&lt;/b&gt; simply indicate which nodes the client will balance its initial "getConnection" requests against&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The client will attempt to establish a connection to &lt;i&gt;dbserver3.somedomain.com&lt;/i&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-6225015957440461064?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/6225015957440461064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2009/03/oracle-rac-load-balancing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/6225015957440461064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/6225015957440461064'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2009/03/oracle-rac-load-balancing.html' title='Oracle RAC Load Balancing'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-8665195037569340721</id><published>2009-03-15T15:50:00.003-04:00</published><updated>2010-03-11T22:33:31.635-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sudo'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Sudo Voodoo</title><content type='html'>The Unix &lt;span style="font-weight: bold;"&gt;sudo &lt;/span&gt;command can be quite useful when one needs to give another user access to a select group of commands that need to be run as a certain user without having to give up the password for that user account. The easiest way to do this is to edit the &lt;span style="font-weight: bold;"&gt;sudoers &lt;/span&gt;file (usually in &lt;span style="font-weight: bold;"&gt;/etc/sudoers&lt;/span&gt;). The file allows an administrator to configure a list of commands that a user can execute as another user without a password. The policy file follows a fairly simple context-free grammer (defined quite concisely in the man page for sudoers). There are a few things to keep in mind when editing the sudoers file:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You must edit the file using the &lt;span style="font-weight: bold; font-style: italic;"&gt;visudo &lt;/span&gt;command as root&lt;/li&gt;&lt;li&gt;When defining a command, you must use the fully qualified path to the command. The system will report a syntax error if you attempt to save the sudoers file with a command that does not start with a &lt;span style="font-weight: bold;"&gt;/&lt;/span&gt;character. This makes sense when one condiders that the whole point of the command is to run something as another user. That being the case, the system can make no guarantees as to what the working directory will be when running the command so requiring the absolute path is a reasonable constraint.&lt;/li&gt;&lt;li&gt;The command(s) defined in the sudoers file must exactly match the command to be run.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Here is an example of a simple sudoers configuration:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Cmnd_Alias      SOME_COMMANDS = /home/somedir/command1.sh,/home/somedir/command2.sh&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;user1 ALL=(ALL) NOPASSWD: SOME_COMMANDS&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first line sets up a "command alias" or a list of commands specified using their absolute path with each command separated by a comma. If you needed to pass a comma into a command as an argument, for example, it would need to be escaped using the backslash character.&lt;br /&gt;&lt;br /&gt;The next line tells the system that the user user1 is allowed to run any of the commands listed in &lt;span style="font-weight: bold;"&gt;SOME_COMMANDS&lt;/span&gt; as any other user without having to specify a password.&lt;br /&gt;&lt;br /&gt;Once you've installed these lines in the sudoers policy file, the &lt;span style="font-weight: bold;"&gt;user1 &lt;/span&gt;user can log in and execute &lt;span style="font-weight: bold; font-style: italic;"&gt;sudo -u user2/home/somedir/command1.sh&lt;/span&gt; to run the &lt;span style="font-weight: bold;"&gt;command1.sh&lt;/span&gt; script as &lt;span style="font-weight: bold;"&gt;user2 &lt;/span&gt;without ever having to provide user2's credentials.&lt;br /&gt;&lt;br /&gt;For a full treatment of how to configure sudo policies, the &lt;a href="http://linux.die.net/man/5/sudoers"&gt;man pages&lt;/a&gt; are the best resource.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-8665195037569340721?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/8665195037569340721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2009/03/sudo-voodoo.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/8665195037569340721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/8665195037569340721'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2009/03/sudo-voodoo.html' title='Sudo Voodoo'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-2725883405557963598</id><published>2009-02-23T19:02:00.002-05:00</published><updated>2009-02-23T19:05:45.339-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='web-development'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>A Dearth of Debugging</title><content type='html'>There seem to be two schools of thought for getting to the bottom of a piece of buggy software: those who log everything vs. those that use the debugger. I've been surprised to learn how large the former camp is, at least among those developing for web-based applications.  I'm not saying that one should use one approach exclusively, just that the debugger is underused in web programming.&lt;br /&gt;&lt;br /&gt;I suppose a reason for this is the perceived difficulty in debugging server-side code from a client machine, but this is more a case of lack of knowledge than an actual technical issue. Most application servers support some facility for remote debugging. Similarly, in Java, at least, the virtual machine itself can be configured to accept connections from remote debugger clients (if, for example, you wanted to configure the JVM to listen for debugger connections on port 8000, you'd include this in the command-line arguments: -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000). Once started in this way, the debugger can connect to the remote JVM and do everything it could do if it were running on the same machine.... you can set breakpoints, inspect the contents of memory, evaluate statements and see the full stack trace for all the running threads... all of which are quite powerful when looking for an elusive bug.&lt;br /&gt;&lt;br /&gt;The heuristic I use for deciding whether to use the debugger or a logger to find the root of an issue is as follows:&lt;br /&gt;&lt;br /&gt;If the bug occurs infrequently and it is not clear how to duplicate it, I use a logger to see if I can detect a pattern. If I can, then I'll use the debugger to look deeper into things. Conversely, if it's clear how to duplicate the bug, I'll usually jump right in with the debugger.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here are some resources for remote debugging:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;JBoss: &lt;a href="http://www.onjava.com/pub/a/onjava/2005/08/31/eclipse-jboss-remote-debug.html"&gt;http://www.onjava.com/pub/a/onjava/2005/08/31/eclipse-jboss-remote-debug.html&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Tomcat: &lt;a href="http://wiki.apache.org/tomcat/FAQ/Developing#Q1"&gt;http://wiki.apache.org/tomcat/FAQ/Developing#Q1&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;IIS: &lt;a href="http://support.microsoft.com/kb/910448"&gt;http://support.microsoft.com/kb/910448&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;PHP: &lt;a href="http://www.php-debugger.com/dbg/"&gt;http://www.php-debugger.com/dbg/&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-2725883405557963598?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/2725883405557963598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2009/02/dearth-of-debugging.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/2725883405557963598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/2725883405557963598'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2009/02/dearth-of-debugging.html' title='A Dearth of Debugging'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3558296680025304582.post-8030151213924691700</id><published>2009-02-22T12:20:00.000-05:00</published><updated>2009-02-22T12:20:17.571-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multi-threading'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Volatility</title><content type='html'>In the last few months, I've found myself writing a lot more multi-threaded programs than I usually do. This made me reflect upon some of the constructs Java provides for multi-threading. Two such constructs are the &lt;span style="font-weight:bold;"&gt;volatile&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;synchronized &lt;/span&gt;keywords. In my years working with a wide range of developers, I've found that most know (at least at a cursory level) what &lt;span style="font-weight:bold;"&gt;synchronized &lt;/span&gt;means, but very few know what &lt;span style="font-weight:bold;"&gt;volatile &lt;/span&gt;means or when it should be used.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;The semantics of the volatile keyword are similar to those of the synchronized keyword, but they're not equivalent. When one thinks of multi-threaded programs, they have 3 primary properties: visibility - the ability of one thread to see the work of another thread, atomicity - defining sets of indivisible actions, and ordering - enforcing that some operations in one thread happen before others in another. Using &lt;span style="font-weight:bold;"&gt;synchronized&lt;/span&gt;, a developer can enforce all three properties. When one uses &lt;span style="font-weight:bold;"&gt;volatile&lt;/span&gt;, however, one cannot enforce atomicity. &lt;br /&gt;&lt;p&gt;&lt;br /&gt;Why would one want to use &lt;span style="font-weight:bold;"&gt;volatile &lt;/span&gt;over &lt;span style="font-weight:bold;"&gt;synchronized &lt;/span&gt;since it seems to be a less powerful construct? Well, for one thing, it incurs slightly less overhead than obtaining locks with &lt;span style="font-weight:bold;"&gt;synchronized&lt;/span&gt;. Additionally, &lt;span style="font-weight:bold;"&gt;volatile &lt;/span&gt;can be used on primitives and null values (you can't directly synchronize on a primitive).  One common use case is for a flag value that is updated by one thread but read by another. Declaring it &lt;span style="font-weight:bold;"&gt;volatile &lt;/span&gt;ensures that the other thread is reading the current value and not its own cached copy.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Java is an interesting programming language for many reasons, not the least of which is the way it insulates the developer from so many concerns of the low-level machine. The difference between volatile and synchronized, however, illustrates that, despite this abstraction, developers are obligated to understand the inner workings of the JVM if they are to write correct and efficient code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3558296680025304582-8030151213924691700?l=processfork.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://processfork.blogspot.com/feeds/8030151213924691700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://processfork.blogspot.com/2009/02/volatility.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/8030151213924691700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3558296680025304582/posts/default/8030151213924691700'/><link rel='alternate' type='text/html' href='http://processfork.blogspot.com/2009/02/volatility.html' title='Volatility'/><author><name>Chris</name><uri>http://www.blogger.com/profile/05991166819575970167</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
