<?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-37481637</id><updated>2012-02-16T05:23:33.711-08:00</updated><category term='gtd'/><category term='business'/><category term='software process'/><category term='tutorials'/><category term='architecture'/><category term='work'/><category term='web'/><category term='programming'/><category term='software development'/><title type='text'>Agile Software Architecture</title><subtitle type='html'>Agile software processes applied to architecture.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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>37</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-37481637.post-2784866383957930257</id><published>2010-05-17T11:27:00.000-07:00</published><updated>2010-05-17T12:06:47.281-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorials'/><title type='text'>Want to Start Game Programming?  Start With Pong</title><content type='html'>In this post you will learn:  basic game programming, including collision detection, timing and threading, and event handling.&lt;br /&gt;&lt;br /&gt;Even though Pong was created in 1972, it still has a lot to teach us today about basic gaming.  I will use Java to show the basics, since Java includes screen widgets in the basic API.  You can use just about any language to do this, though.&lt;br /&gt;&lt;br /&gt;Step 1:  create the screen.  We will need a basic screen layout to hold the game screen and a high score screen.  Because what fun is a game if you don't keep score?  I will use a class that extends JPanel to hold the two sub-panels.  Why JPanel?  It allows easy re-use of the logic.  If you want to make this a stand-alone app, create a JFrame in the main method to hold it.  If you want to use this as part of a larger app, you can add the Panel to whatever parent container you wish - JTabbedPane, Applet, etc.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;public JavaPongPanel(){&lt;br /&gt; Dimension size = new Dimension(600, 400);&lt;br /&gt; setLayout(new BorderLayout());&lt;br /&gt; mainPanel = new JPanel();&lt;br /&gt; scorePanel = new JPanel();&lt;br /&gt; add(mainPanel, BorderLayout.CENTER);&lt;br /&gt; add(scorePanel, BorderLayout.EAST);&lt;br /&gt; mainPanel.setPreferredSize(size);&lt;br /&gt; scorePanel.setPreferredSize(new Dimension(100, size.height));&lt;br /&gt;...&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What we've got so far is a screen that's 600x400, and two panels added to it - one in the center, and one to the right.&lt;br /&gt;&lt;br /&gt;Step 2:  draw and move paddles.  Nothing going on so far.  We need to get some interactivity.  We will add a MouseMotionListener to the game panel to make the paddles track the user's movements.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt; @Override&lt;br /&gt; public void mouseMoved(MouseEvent arg0) {&lt;br /&gt;     Point2D.Double p = new Point2D.Double(arg0.getPoint().x, arg0.getPoint().y);&lt;br /&gt;     mousePoint = p;&lt;br /&gt;     Dimension d = mainPanel.getSize();&lt;br /&gt;     double xPoint = mousePoint.x - (PADDLE_WIDTH / 2);&lt;br /&gt;     double leftXPoint = 10;&lt;br /&gt;     double rightXPoint = d.width - PADDLE_HEIGHT - 10;&lt;br /&gt;&lt;br /&gt;     double yPoint = mousePoint.y - (PADDLE_WIDTH / 2);&lt;br /&gt;     double bottomYPoint = d.height - PADDLE_HEIGHT - 10;&lt;br /&gt;     double topYPoint = 10;&lt;br /&gt;&lt;br /&gt;     //top paddle&lt;br /&gt;     tPaddle.x = xPoint;&lt;br /&gt;     tPaddle.y = topYPoint;&lt;br /&gt;     //bottom paddle&lt;br /&gt;     bPaddle.x = xPoint;&lt;br /&gt;     bPaddle.y = bottomYPoint;&lt;br /&gt;     //left paddle&lt;br /&gt;     lPaddle.x = leftXPoint;&lt;br /&gt;     lPaddle.y = yPoint;&lt;br /&gt;     //right paddle&lt;br /&gt;     rPaddle.x = rightXPoint;&lt;br /&gt;     rPaddle.y = yPoint;&lt;br /&gt;  &lt;br /&gt;     animate();&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The four paddle variables are global Rectangle2D.Doubles, to allow us to track collisions.  We'll get to that in a minute.  Notice the animate() method call at the end.  That is to update the screen with the movement of the mouse, to make the paddles track the mouse.  We also need to call&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  mainPanel.addMouseMotionListener(this);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;to have mouse events forward from the panel to the listener.&lt;br /&gt;&lt;br /&gt;Step 3:  Animation.  There will be two sources of animation changes - the paddle motion that we just did, and the movement of the ball.  The movement of the ball will be done regardless of user interaction, so for that we will need to use a thread.  JavaPongPanel already implements Runnable, so we will need to define a run() method.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;   @Override&lt;br /&gt;   public void run() {&lt;br /&gt;       try {&lt;br /&gt;           while (ballMoving) {&lt;br /&gt;               Thread.sleep(10);&lt;br /&gt;               pdv.setPoint(pdv.getNextPoint());&lt;br /&gt;               checkCollision();&lt;br /&gt;               animate();&lt;br /&gt;           }&lt;br /&gt;       } catch (Throwable t) {&lt;br /&gt;           t.printStackTrace();&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now we've got a thread that will set the ball location (pdv is a PointDirectionVelocity class that holds the ball's current position, direction and velocity to calculate the next position if it doesn't hit anything), check for collision, and redraw the screen.  Now we just need a reason to start the thread.  We will print a message to the screen, and when the user clicks on the screen, the game will start.  So in the constructor, you will have this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;   MouseInputAdapter adapter = new MouseInputAdapter(){&lt;br /&gt;       public void mouseClicked(MouseEvent arg0) {&lt;br /&gt;           if(!JavaPongPanel.this.ballMoving){&lt;br /&gt;               JavaPongPanel.this.ballMoving = true;&lt;br /&gt;               Thread t = new Thread(JavaPongPanel.this);&lt;br /&gt;               t.start();&lt;br /&gt;               }&lt;br /&gt;           }&lt;br /&gt;       };&lt;br /&gt;   mainPanel.addMouseListener(adapter);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which will start the thread when the user clicks on the screen, if the game isn't already started.  The animate method needs to draw the ball position, the paddle position, and the score.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;   private void animate(){&lt;br /&gt;       drawScore();&lt;br /&gt;       Dimension d = mainPanel.getSize();&lt;br /&gt;       Graphics2D screen = (Graphics2D) mainPanel.getGraphics();&lt;br /&gt;       Graphics2D graphics = (Graphics2D) image.createGraphics();&lt;br /&gt;       graphics.setBackground(Color.black);&lt;br /&gt;       graphics.clearRect(0, 0, d.width, d.height);&lt;br /&gt;       graphics.setColor(Color.white);&lt;br /&gt;&lt;br /&gt;       graphics.fill(tPaddle);&lt;br /&gt;       graphics.fill(bPaddle);&lt;br /&gt;       graphics.fill(lPaddle);&lt;br /&gt;       graphics.fill(rPaddle);&lt;br /&gt;       drawBall(graphics);&lt;br /&gt;       screen.drawImage(image, 0, 0, null);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private void drawScore(){&lt;br /&gt;       Graphics2D scoreG = (Graphics2D) scorePanel.getGraphics();&lt;br /&gt;       scoreG.setBackground(Color.blue);&lt;br /&gt;       scoreG.clearRect(0, 0, scorePanel.getWidth(), scorePanel.getHeight());&lt;br /&gt;       scoreG.setColor(Color.white);&lt;br /&gt;       scoreG.drawString("Score: " + score, 10, 20);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private void drawBall(Graphics2D graphics){&lt;br /&gt;       graphics.setColor(Color.white);&lt;br /&gt;       if(ballMoving){&lt;br /&gt;           ball.x = pdv.getPoint().x - (BALL_WIDTH / 2);&lt;br /&gt;           ball.y = pdv.getPoint().y - (BALL_HEIGHT / 2);&lt;br /&gt;           graphics.fill(ball);&lt;br /&gt;       }&lt;br /&gt;       else{&lt;br /&gt;           Dimension d = mainPanel.getSize();&lt;br /&gt;           resetBall();&lt;br /&gt;           int xCenter = d.width / 2;&lt;br /&gt;           int yCenter = d.height / 2;&lt;br /&gt;           graphics.drawString("Click to Begin", xCenter - 50, yCenter - 20);&lt;br /&gt;           graphics.fill(ball);&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note that I'm actually using the graphics object from an image, not from the component.  This is double-buffering and allows clearer screen refreshing than drawing each thing at a time to the live screen.  It's not absolutely necessary, but it helps the game look cleaner.  To create the image, you would call&lt;br /&gt;&lt;code&gt;&lt;br /&gt;image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;in the constructor after you set the screen size.&lt;br /&gt;&lt;br /&gt;Step 4:  Collision detection.  I have used the Java Shape API to define the Rectangles for the paddles, and the Ellipse for the ball.  This gives me the ability to let Java check for intersection and react when the ball is in contact with the paddle.  We now have a checkCollision method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;   private void checkCollision(){&lt;br /&gt;       Dimension d = mainPanel.getSize();&lt;br /&gt;       Point2D.Double ballPoint = pdv.getPoint();&lt;br /&gt;       //paddle detection&lt;br /&gt;&lt;br /&gt;       double direction = pdv.getDirection();&lt;br /&gt;       if(ball.intersects(tPaddle) &amp;amp;&amp;amp; (direction &gt; 90 &amp;amp;&amp;amp; direction &lt;&gt; 270 &amp;amp;&amp;amp; direction &lt;&gt; 180 &amp;amp;&amp;amp; direction &lt;&gt; 0 &amp;amp;&amp;amp; direction &lt;&gt;= d.width){&lt;br /&gt;     ballMoving = false;&lt;br /&gt;     resetBall();&lt;br /&gt; }else if(ballPoint.x &lt;= 0){      ballMoving = false;      resetBall();  }  else if(ballPoint.y &gt;= d.height){&lt;br /&gt;     ballMoving = false;&lt;br /&gt;     resetBall();&lt;br /&gt; }else if(ballPoint.y &lt;= 0){      ballMoving = false;      resetBall();  }     } &lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The check for direction in the paddle collision checking is to handle the case where the collision isn't detected until the ball is somewhat inside the paddle, and the next point would not totally clear the paddle.  Without this check, the ball would appear to "stick" to the paddle and shimmy down the length of it.  This is not what we want.  The screen edge detection will put the ball back in the center, and restart the game.&lt;br /&gt;&lt;br /&gt;So there you go:  a couple hundred lines of Java code, and you're got a playable game.  From here, there are many things you could do.  Instead of just reflecting the ball off the paddle, you could adjust the angle relative to the paddle, and if the hit isn't on-center, you can add some angle to the ball.  You've already got a ball bouncing off of rectangles, you're most of the way to a Breakout-style game.  It's all up to your imagination.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-2784866383957930257?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/2784866383957930257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=2784866383957930257' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2784866383957930257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2784866383957930257'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2010/05/want-to-start-game-programming-start.html' title='Want to Start Game Programming?  Start With Pong'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-2233565839293293064</id><published>2009-08-10T08:07:00.000-07:00</published><updated>2009-08-10T08:20:14.627-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Rapid Java Webservice Prototyping with Hyperjaxb (Part 2)</title><content type='html'>We resume the HyperJAXB example with some business logic.&lt;br /&gt;&lt;br /&gt;Step 4:  Let’s start with the basics:  save, delete and query.  We’ll leverage Hiberate’s ability to perform a saveOrUpdate, so we don’t need separate methods for both.  Create a class, PurchaseOrderPersistence, and initialize Hibernate.  I chose to use a singleton, just to make sure that the access will be atomic.  So I’ve got two methods:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; public static PurchaseOrderPersistence getInstance() {&lt;br /&gt;  if (instance == null) {&lt;br /&gt;   instance = new PurchaseOrderPersistence();&lt;br /&gt;  }&lt;br /&gt;  return instance;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; private PurchaseOrderPersistence() {&lt;br /&gt;  persistenceProperties = new Properties();&lt;br /&gt;  InputStream is = null;&lt;br /&gt;  try {&lt;br /&gt;   System.out.println("loading properties");&lt;br /&gt;   is = PurchaseOrderPersistence.class.getClassLoader()&lt;br /&gt;     .getResourceAsStream("persistence.properties");&lt;br /&gt;System.out.println(PurchaseOrderPersistence.class.getClassLoader().getResource("persistence.properties"));&lt;br /&gt;   System.out.println("is: " + is.toString());&lt;br /&gt;   persistenceProperties.load(is);&lt;br /&gt;   System.out.println("props: " + persistenceProperties.toString());&lt;br /&gt;  } catch (IOException e) {&lt;br /&gt;   // TODO Auto-generated catch block&lt;br /&gt;   e.printStackTrace();&lt;br /&gt;  } finally {&lt;br /&gt;   if (is != null) {&lt;br /&gt;    try {&lt;br /&gt;     is.close();&lt;br /&gt;    } catch (IOException ignored) {&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  entityManagerFactory = Persistence.createEntityManagerFactory(&lt;br /&gt;    " PurchaseOrder ", persistenceProperties);&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What it’s doing is looking for the persistence.properties file and passing it to the EntityManagerFactory along with the persistence unit name (PurchaseOrder) defined in the build.  Remember that we created persistence.properties in step 3 to define our Hibernate connection properties.  In the example, we used JNDI to bind to the datastore, but you could use a JDBC URL as well.  Now that the system knows what to do with the beans, we can start creating methods.  Basic getOrder method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; public PurchaseOrderType getOrder(long id) {&lt;br /&gt;  PurchaseOrderType order = null;&lt;br /&gt;  EntityManager em = null;&lt;br /&gt;  try {&lt;br /&gt;   em = entityManagerFactory.createEntityManager();&lt;br /&gt;   order = em.find(PurchaseOrderType.class, id);&lt;br /&gt;  } catch (Throwable t) {&lt;br /&gt;   t.printStackTrace();&lt;br /&gt;  } finally {&lt;br /&gt;   if (em != null &amp;amp;&amp;amp; em.isOpen()) {&lt;br /&gt;    try {&lt;br /&gt;     //em.close();&lt;br /&gt;    } catch (Throwable t) {&lt;br /&gt;     t.printStackTrace();&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  return order;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Using EntityManager, we are able to lookup the requested object by ID without needing any SQL.  Repeat as necessary for update and delete methods.&lt;br /&gt;&lt;br /&gt;Step 5:  Create the web service interface.  Create a class to contain the web methods and use the WS annotations to declare the class as a web service.  It should look like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@WebService(serviceName = "PurchaseOrderWS")&lt;br /&gt;public class PurchaseOrderWS {&lt;br /&gt;&lt;br /&gt; private static ObjectFactory of = new ObjectFactory();&lt;br /&gt;&lt;br /&gt; @WebMethod&lt;br /&gt; public PurchaseOrderType getOrder(long orderID) {&lt;br /&gt;  PurchaseOrderType task = null;&lt;br /&gt;  try {&lt;br /&gt;   PurchaseOrderPersistence pop = PurchaseOrderPersistence&lt;br /&gt;     .getInstance();&lt;br /&gt;   task = pop.getOrder(orderID);&lt;br /&gt;   if (task != null) {&lt;br /&gt;    System.out.println("getTask: " + task.toString());&lt;br /&gt;   }&lt;br /&gt;  } catch (Throwable t) {&lt;br /&gt;   t.printStackTrace();&lt;br /&gt;  }&lt;br /&gt;  return task;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This creates a web service named PurchaseOrderWS, and web method getOrder that returns a PurchaseOrderType.  Keep in mind this is all without doing anything to the data object beyond defining them in the XSD.  It's not 100% necessary to have the web methods in a separate class from the persistence methods, since there's a 1 to 1 mapping between them, but it's good practice to allow some flexibility in the design.&lt;br /&gt;&lt;br /&gt;Step 6:  Package and deploy the web service.  Create a web.xml deployment descriptor (is this necessary with annotations?)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"&amp;gt;&lt;br /&gt; &amp;lt;display-name&amp;gt;&lt;br /&gt; PurchaseOrderWS&amp;lt;/display-name&amp;gt;&lt;br /&gt; &amp;lt;servlet&amp;gt;&lt;br /&gt;    &amp;lt;servlet-name&amp;gt;PurchaseOrderWS&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;    &amp;lt;servlet-class&amp;gt;com.jon.purchaseorder.PurchaseOrderWS&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;    &amp;lt;servlet-name&amp;gt;PurchaseOrderWS&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;    &amp;lt;url-pattern&amp;gt;/PurchaseOrderWS&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt; &amp;lt;welcome-file-list&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;index.html&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;index.htm&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;index.jsp&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;default.html&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;default.htm&amp;lt;/welcome-file&amp;gt;&lt;br /&gt;  &amp;lt;welcome-file&amp;gt;default.jsp&amp;lt;/welcome-file&amp;gt;&lt;br /&gt; &amp;lt;/welcome-file-list&amp;gt;&lt;br /&gt;&amp;lt;/web-app&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This defines the mapping of the web service to the implementation class.  Package a war file using ant like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &amp;lt;!-- copy ws-related stuff --&amp;gt;&lt;br /&gt;  &amp;lt;copy todir="${basedir}/target/classes"&amp;gt;&lt;br /&gt;   &amp;lt;fileset dir="${basedir}/lib"&amp;gt;&lt;br /&gt;    &amp;lt;include name="runtime-0.4.1.5.jar" /&amp;gt;&lt;br /&gt;    &amp;lt;include name="commons-lang-2.1.jar" /&amp;gt;&lt;br /&gt;    &amp;lt;include name="hyperjaxb*.jar" /&amp;gt;&lt;br /&gt;   &amp;lt;/fileset&amp;gt;&lt;br /&gt;  &amp;lt;/copy&amp;gt;&lt;br /&gt;  &amp;lt;!-- create war file--&amp;gt;&lt;br /&gt;  &amp;lt;jar destfile="${basedir}/target/classes/generated-classes.jar"&amp;gt;&lt;br /&gt;   &amp;lt;fileset dir="${basedir}/target/classes"&amp;gt;&lt;br /&gt;    &amp;lt;include name="**/*.class" /&amp;gt;&lt;br /&gt;   &amp;lt;/fileset&amp;gt;&lt;br /&gt;   &amp;lt;fileset dir="${basedir}/resources"&amp;gt;&lt;br /&gt;    &amp;lt;include name="*" /&amp;gt;&lt;br /&gt;   &amp;lt;/fileset&amp;gt;&lt;br /&gt;  &amp;lt;/jar&amp;gt;&lt;br /&gt;  &amp;lt;war destfile="${basedir}/target/PurchaseOrderWS.war"&lt;br /&gt;   webxml="${basedir}/resources/web.xml"&amp;gt;&lt;br /&gt;   &amp;lt;lib dir="${basedir}/target/classes"&amp;gt;&lt;br /&gt;    &amp;lt;include name="*.jar" /&amp;gt;&lt;br /&gt;   &amp;lt;/lib&amp;gt;&lt;br /&gt;   &amp;lt;metainf dir="${basedir}/target/generated-sources/xjc/META-INF"&amp;gt;&lt;br /&gt;    &amp;lt;include name="*" /&amp;gt;&lt;br /&gt;   &amp;lt;/metainf&amp;gt;&lt;br /&gt;  &amp;lt;/war&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will package the war file using the web.xml from above, including the META-INF directory generated by Hibernate containing the persistence.xml with the object-relational mapping file.  It also includes a jar file of the generated classes, since they are compiled into a separate directory from the implementation classes.  It also includes the necessary hibernate/hyperjax jars in WEB-INF/lib.  Copy the resulting .war file into your JBoss/server/deploy directory and start it up.  If all has gone well, you should be able to navigate to the WSDL for your web service.  If you invoked the service, you would persist your data in the remote database without writing any SQL.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-2233565839293293064?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/2233565839293293064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=2233565839293293064' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2233565839293293064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2233565839293293064'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2009/08/rapid-java-webservice-prototyping-with_10.html' title='Rapid Java Webservice Prototyping with Hyperjaxb (Part 2)'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-7851432387808495097</id><published>2009-08-05T14:22:00.000-07:00</published><updated>2009-08-10T08:25:51.811-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Rapid Java Webservice Prototyping with Hyperjaxb (Part 1)</title><content type='html'>Something different: a hands-on example of integrating a number of FOSS/COTS tools into one useful suite for rapid prototyping.&lt;br /&gt;&lt;br /&gt;Prerequisites:&lt;br /&gt;JBoss 4.2.3&lt;br /&gt;Hyperjaxb 0.5.3&lt;br /&gt;Oracle 9i (although the database doesn’t really matter)&lt;br /&gt;JDK 1.6.&lt;br /&gt;&lt;br /&gt;Rapid prototyping with Hyperjaxb&lt;br /&gt;This assumes JBoss 4.2.3, Hyperjaxb 0.5.3, Oracle 9i (although the database doesn’t really matter) and JDK 1.6.&lt;br /&gt;Foreword:  Hyperjaxb provides an object-relational mapping for JAXB objects.  That means that a JAXB-compliant bean can be mapped to database persistence.  Leveraging JAX-B and Hibernate (hence the name), it can take a schema and generate JAXB and Hibernate annotations in the generated beans.  This feature allows for very rapid Web Service development, since the beans that your service uses are the exact same objects as you are saving into the database, and are generated with little more effort than writing the schema.&lt;br /&gt;&lt;br /&gt;Step 1.  Create a schema.  For our example, we will use the well-known PurchaseOrder xsd from  &lt;br /&gt;http://www.w3.org/TR/xmlschema-0/#POSchema.  Since it’s short, we’ll just include it here:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;xsd:schema xsd="http://www.w3.org/2001/XMLSchema"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;xsd:annotation&amp;gt;&lt;br /&gt; &amp;lt;xsd:documentation lang="en"&amp;gt;&lt;br /&gt;  Purchase order schema for Example.com.&lt;br /&gt;  Copyright 2000 Example.com. All rights reserved.&lt;br /&gt; &amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;&amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;xsd:element name="purchaseOrder" type="PurchaseOrderType"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;xsd:element name="comment" type="xsd:string"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;xsd:complextype name="PurchaseOrderType"&amp;gt;&lt;br /&gt; &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element name="shipTo" type="USAddress"&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element name="billTo" type="USAddress"&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element ref="comment" minoccurs="0"&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element name="items" type="Items"&amp;gt;&lt;br /&gt; &amp;lt;/xsd:element&amp;gt;&lt;br /&gt; &amp;lt;xsd:attribute name="orderDate" type="xsd:date"&amp;gt;&lt;br /&gt;&amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;xsd:complextype name="USAddress"&amp;gt;&lt;br /&gt; &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element name="name" type="xsd:string"&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element name="street" type="xsd:string"&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element name="city" type="xsd:string"&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element name="state" type="xsd:string"&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element name="zip" type="xsd:decimal"&amp;gt;&lt;br /&gt; &amp;lt;/xsd:element&amp;gt;&lt;br /&gt; &amp;lt;xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"&amp;gt;&lt;br /&gt;&amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;xsd:complextype name="Items"&amp;gt;&lt;br /&gt; &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;   &amp;lt;xsd:element name="item" minoccurs="0" maxoccurs="unbounded"&amp;gt;&lt;br /&gt;     &amp;lt;xsd:complextype&amp;gt;&lt;br /&gt;       &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;         &amp;lt;xsd:element name="productName" type="xsd:string"&amp;gt;&lt;br /&gt;         &amp;lt;xsd:element name="quantity"&amp;gt;&lt;br /&gt;           &amp;lt;xsd:simpletype&amp;gt;&lt;br /&gt;             &amp;lt;xsd:restriction base="xsd:positiveInteger"&amp;gt;&lt;br /&gt;               &amp;lt;xsd:maxexclusive value="100"&amp;gt;&lt;br /&gt;             &amp;lt;/xsd:maxexclusive&amp;gt;&lt;br /&gt;           &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;         &amp;lt;/xsd:simpletype&amp;gt;&lt;br /&gt;         &amp;lt;xsd:element name="USPrice" type="xsd:decimal"&amp;gt;&lt;br /&gt;         &amp;lt;xsd:element ref="comment" minoccurs="0"&amp;gt;&lt;br /&gt;         &amp;lt;xsd:element name="shipDate" type="xsd:date" minoccurs="0"&amp;gt;&lt;br /&gt;       &amp;lt;/xsd:element&amp;gt;&lt;br /&gt;       &amp;lt;xsd:attribute name="partNum" type="SKU" use="required"&amp;gt;&lt;br /&gt;     &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;   &amp;lt;/xsd:element&amp;gt;&lt;br /&gt; &amp;lt;/xsd:element&amp;gt;&lt;br /&gt;&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- Stock Keeping Unit, a code for identifying products --&amp;gt;&lt;br /&gt;&amp;lt;xsd:simpletype name="SKU"&amp;gt;&lt;br /&gt; &amp;lt;xsd:restriction base="xsd:string"&amp;gt;&lt;br /&gt;   &amp;lt;xsd:pattern value="\d{3}-[A-Z]{2}"&amp;gt;&lt;br /&gt; &amp;lt;/xsd:pattern&amp;gt;&lt;br /&gt;&amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;&amp;lt;/xsd:schema&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This schema defines a purchaseOrder object as contaiing shipping information (shipTo), billing information (billTo), and the ordered item information (items).&lt;br /&gt;&lt;br /&gt;Step 2.  Compile the schema.  The relevant portion of the build.xml looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;xjc destdir="${basedir}/target/generated-sources/xjc" extension="true"&amp;gt;&lt;br /&gt;         &amp;lt;arg line=" -Xhyperjaxb3-ejb&lt;br /&gt;         -Xhyperjaxb3-ejb-persistenceUnitName=PurchaseOrder -Xhyperjaxb3-ejb-roundtripTestClassName=RoundtripTest&lt;br /&gt;-Xequals&lt;br /&gt;                -XhashCode&lt;br /&gt;                -XtoString"&amp;gt;&lt;br /&gt;         &amp;lt;binding dir="schemas"&amp;gt;&lt;br /&gt;              &amp;lt;include name="jaxbBinding.xml"&amp;gt;&lt;br /&gt;         &amp;lt;/include&amp;gt;&lt;br /&gt;         &amp;lt;schema dir="schemas"&amp;gt;&lt;br /&gt;             &amp;lt;include name="po.xsd"&amp;gt;&lt;br /&gt;         &amp;lt;/include&amp;gt;&lt;br /&gt;         &amp;lt;classpath&amp;gt;&lt;br /&gt;             &amp;lt;fileset dir="${basedir}/lib"&amp;gt;&lt;br /&gt;                 &amp;lt;include name="*.jar"&amp;gt;&lt;br /&gt;             &amp;lt;/include&amp;gt;&lt;br /&gt;         &amp;lt;/fileset&amp;gt;&lt;br /&gt;     &amp;lt;/classpath&amp;gt;&lt;br /&gt;&amp;lt;/schema&amp;gt;&lt;br /&gt;&amp;lt;/binding&amp;gt;&lt;br /&gt;&amp;lt;/arg&amp;gt;&lt;br /&gt;&amp;lt;/xjc&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which tells xjc (jaxb compiler) to allow extension, use hyperjaxb-ejb as an extension, and compile po.xsd.  Binding allows schema overrides to be custom-defined.  This creates 4 classes:  Items.java, ObjectFactory.java, PurchaseOrderType.java and USAddress.java  Let’s look at PurchaseOrderType.java.  You’ll notice that the JAXB annotations are present on the class variables.  In addition, the JPA/Hibernate annotations are present on the accessor methods.  Also, note that a field not defined in the schema, hjid, has been added.  This will serve as the primary key for the table since one was not defined in the schema.  Later, we’ll show you how to handle this.&lt;br /&gt;For the field shipTo, the declaration looks like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; @XmlElement(required = true)&lt;br /&gt; protected generated.USAddress shipTo;&lt;br /&gt;&lt;br /&gt;and the accessor methods look like this:&lt;br /&gt; @ManyToOne(targetEntity = generated.USAddress.class, cascade = {&lt;br /&gt;     CascadeType.ALL&lt;br /&gt; })&lt;br /&gt; @JoinColumn(name = "SHIPTO_PURCHASEORDERTYPE_ID")&lt;br /&gt; public generated.USAddress getShipTo() {&lt;br /&gt;     return shipTo;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; public void setShipTo(generated.USAddress value) {&lt;br /&gt;     this.shipTo = value;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note that shipTo declares a ManyToOne relation, which indicates that many shipTo elements will reference this one PurchaseOrder, and will contain a foreign key to the primary key in the PurchaseOrder (the hjid).&lt;br /&gt;&lt;br /&gt;Step 3.  Hibernate configuration.  Obviously, this will vary depending on your environment and your intended target.  In this case, we will be creating a web service, served by JBoss, and connected to an Oracle database.  In any case, you will need a persistence.properties file to define connection properties.  For example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;hibernate.dialect=org.hibernate.dialect.Oracle9iDialect&lt;br /&gt;hibernate.connection.driver_class=oracle.jdbc.driver.OracleDriver&lt;br /&gt;hibernate.connection.username= user&lt;br /&gt;hibernate.connection.password=password&lt;br /&gt;hibernate.hbm2ddl.auto=create-drop&lt;br /&gt;hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider&lt;br /&gt;hibernate.jdbc.batch_size=0&lt;br /&gt;hibernate.connection.datasource=/OracleDS&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This  tells hibernate that it will connect to an Oracle9i database using the Oracle driver, connected via JNDI to /OracleDS.  Configuration of OracleDS can be found in the JBoss documentation.  For our example, we’ll assume it is set up and working.  Note that Hibernate allows us to replace the underlying datastore without requiring any change to the business logic.  That means the dialect parameter would be the only change required to migrate to another DBMS.&lt;br /&gt;&lt;br /&gt;That's enough for today.  The next entry will focus on writing the business logic to use the generated beans in a web service and deploying the web service into the application server.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-7851432387808495097?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/7851432387808495097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=7851432387808495097' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/7851432387808495097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/7851432387808495097'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2009/08/rapid-java-webservice-prototyping-with.html' title='Rapid Java Webservice Prototyping with Hyperjaxb (Part 1)'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-362713310886261030</id><published>2009-03-23T13:08:00.000-07:00</published><updated>2009-03-24T12:29:55.036-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Evolutionary Architecture</title><content type='html'>Agile Architecture, Round 2.  As I (&lt;a href="http://searchsoa.techtarget.com/news/article/0,289142,sid26_gci1351335,00.html"&gt;and others)&lt;/a&gt; have said, "&lt;a href="http://c2.com/xp/DoTheSimplestThingThatCouldPossiblyWork.html"&gt;Do The Simplest Thing That Could Possibly Work&lt;/a&gt;" applies to more than your software. So today, we'll look at the common growth process for a system, and some of the constraints that limit each phase. Our example is a web-based, database-driven application, but can be applied to any system with persistent storage. (Thanks to &lt;a href="http://www.mxgraph.com/demo.html"&gt;mxGraph&lt;/a&gt; for images).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_C03EJGDvKjw/Scfx_TKJ7LI/AAAAAAAAAEw/ngxKp_eokjk/s1600-h/basic.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: none; cursor: pointer; width: 181px; height: 201px;" src="http://4.bp.blogspot.com/_C03EJGDvKjw/Scfx_TKJ7LI/AAAAAAAAAEw/ngxKp_eokjk/s320/basic.jpg" alt="" id="BLOGGER_PHOTO_ID_5316483954911079602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Step 1 is the absolute basic setup:  everything running on one server.  One webserver, one database backend.  I suppose Step Zero would be no database, just files or something.  But even that trivial example is enough to get us off the ground.  No failover, no backup, no load handling?  No problem!  Now, I would not advise using this type of system in a live environment, but for prototyping and identifying performance bottlenecks, it's just fine.  Get something up and running, then see how it behaves.  The ultimate limit of the system with this configuration is limited by how big of a box you can get your hands on.  But most likely, one giant enterprise server would not work as well as step 2, for reasons that will be explained.&lt;br /&gt;&lt;br /&gt;This also would be a good place to mention the value of monitoring and logging at this level.  In order to identify bottlenecks, you need to be able to see how your system responds to load.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_C03EJGDvKjw/Scfzr6ljCEI/AAAAAAAAAE4/0EzwJyby2Ic/s1600-h/simple.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 164px;" src="http://4.bp.blogspot.com/_C03EJGDvKjw/Scfzr6ljCEI/AAAAAAAAAE4/0EzwJyby2Ic/s320/simple.jpg" alt="" id="BLOGGER_PHOTO_ID_5316485820920825922" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Step 2 is a very common setup.  It's not that much different from step 1, except that the database and webserver are on physically separate machines.  This is the first step toward separating into functionality, except the functionality is as coarse-grained as it can be at this point.  You could just as easily add a clone of the first machine, but now you've got two sets of processes to manage, which we will address in the next iteration.  This setup allows us to tune each machine for its specified task:  application or database access.&lt;br /&gt;&lt;br /&gt;By introducing a second machine, we've now introduced a synchronization issue between them.  If one machine goes down, the second machine needs to be able to address that somehow.  Fail the request?  Queue and retry?  The answer is "It depends" on the situation being addressed.  Serving webpages, the user may wish to submit their query again.  Storing credit card requests may need to be more robust.  But we can handle the problem with the next step:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_C03EJGDvKjw/Sckp3QH_1-I/AAAAAAAAAFI/__Vkzg35qcQ/s1600-h/cluster.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 107px;" src="http://4.bp.blogspot.com/_C03EJGDvKjw/Sckp3QH_1-I/AAAAAAAAAFI/__Vkzg35qcQ/s320/cluster.jpg" alt="" id="BLOGGER_PHOTO_ID_5316826864285636578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Step 3 could theoretically be scaled out to hundreds or thousands of servers, and Step 4 is really a subdivision of Step 3.  Notice that our number of servers is increasing exponentially.  We started at 1, then added a second.  Now we're managing (at least) 4.  The cluster implementation can be as simple or as complicated as you make it - J2ee container-managed cluster or simple proxy software.  The important things with this step are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;you can now scale as many servers as you may need, quickly and simply.&lt;/li&gt;&lt;li&gt;you're removed almost all failures from impacting availability.&lt;/li&gt;&lt;li&gt;you're still constrained by the database master server.&lt;/li&gt;&lt;/ul&gt;This step is assuming that you're still dealing with fairly homologous data at this point:  all the data coming and going from the servers can be dealt with similarly.  This type of layout is pretty common among the Less Than Huge websites, that is, excepting the Ebay's, Facebook's, and Google's of the world.  Once you get that huge, you will probably need a unique approach to handle your traffic anyway.  But this will get you to 99% of the way there.  At this point, you've already addressed pushing updates to your servers and handling inconsistency between them (in the previous step).  But let's say your monitoring is indicating that you're either writing too much data for one write-only database to keep up with.  Or let's say you identified a major performance bottleneck in the system.  That's where step 4 comes into play:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_C03EJGDvKjw/Sckv6PDWNbI/AAAAAAAAAFQ/N4o5GMDwaSs/s1600-h/arch.jpg"&gt;&lt;img style="cursor: pointer; width: 400px; height: 220px;" src="http://2.bp.blogspot.com/_C03EJGDvKjw/Sckv6PDWNbI/AAAAAAAAAFQ/N4o5GMDwaSs/s400/arch.jpg" alt="" id="BLOGGER_PHOTO_ID_5316833512607069618" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We're now, finally, at a point that could be considered "architecture."  Each type of process is located on its own server, connecting to a database that contains the data that it needs to perform that function.  This would be the point where de-normalization may come into play.  By removing the need for connecting the databases, the minor performance/space hit taken by denormalization would be offset by the lack of interconnection between the databases.  Also at this point, there may be additional vertical stacking, separating the presentation layer from specific data-processing.  Now we're into the classic 3 (or n)-tier model, but the internals of those layers can scale as large as we want (within some physical limits).&lt;br /&gt;&lt;br /&gt;So to sum up, your architecture should "grow" along with your application.  It should provide a framework to allow your application to handle growth, not restrict you to grow in a specific path.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-362713310886261030?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/362713310886261030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=362713310886261030' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/362713310886261030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/362713310886261030'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2009/03/evolutionary-architecture.html' title='Evolutionary Architecture'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_C03EJGDvKjw/Scfx_TKJ7LI/AAAAAAAAAEw/ngxKp_eokjk/s72-c/basic.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37481637.post-6156412322775214614</id><published>2009-03-10T11:46:00.000-07:00</published><updated>2009-03-11T12:44:25.683-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Schedule, LOC, and Budget?  You're Lying</title><content type='html'>Software engineering is an imprecise science.  Anyone who tells you differently is either not working very hard, or doesn't understand that fact (or both).  Actually, calling it engineering is a bit of a misnomer itself, since the engineering work in building systems is as different as engineering a submarine vs. a bridge.  Engineering involves creating repeatable systems of common features.  That is, there are a set of rules for building sets of bridges that have little in common with the rules for building submarines.&lt;br /&gt;&lt;br /&gt;The problem with defining software as engineering lies in the identification of the dividing line between engineering and manufacturing.  Determining the amount of effort (time, code, and people) for software is much less defined than traditional "peoplespace" engineering because of the fluidity of the tools that are used.  Imagine writing a proposal to build the &lt;a href="http://en.wikipedia.org/wiki/First_Transcontinental_Railroad"&gt;first transcontinental railroad&lt;/a&gt;.  50 miles per year, thousands of workers.  Now image the proposal today:  much more production, much less workers.  Computers allow the creation of these monstrously efficient production mechanisms.  Hence the statement "hardware is cheap, people are expensive."&lt;br /&gt;&lt;br /&gt;Looking at schedules, we see there are two types of release schedules:  time-constrained (release on a certain date, like Ubuntu), or effort-constrained (all these features are in release X, like, say, Apache Httpd).  Time-constrained releases on a set date, with a variable number of features.  Effort-constrained delivers when the set features are done.  Neither schedule mechanism has any concern with people or time.  So either you release on a scheduled date, with whatever is done at that time, or you release when everything is done, regardless of date.&lt;br /&gt;&lt;br /&gt;It would be silly to create a release schedule that released every 10,000 lines of code, but that's what our snakeoil salesman are proposing.  Here's how it works:  a budget is calculated based on the estimated lines of code, times the number of man/hours that would take to create, based on historical estimates of productivity.  So, like Earl Sheib, you're saying "I can build that system with 100,000 lines of code!"  Calculating budget is now a function of hourly billing rate times productivity and estimated lines of code. &lt;br /&gt;&lt;br /&gt;Here's an example:  customer says "build me a new SuperWidget."  Contractor looks thoughtful and says "We think SuperWidget should take 50,000 lines of code, since it's kind of like TurboSquirrel we built before.  Our normal efficiency is 1 LOC per hour (seriously), and billing rate is $200 per hour.  So budget is $10 million dollars.  There's 2,000 man/hours per year, so we need 25 people and you can have it in one year."  There's your budget, schedule, and estimate, all rolled into one.  If one changes, the others have to change as well.  SuperWidget is a large project, obviously.&lt;br /&gt;&lt;br /&gt;That's seriously how it works.  Oh sure, there's supposed to be more analysis to determine how similar the project will be to previous projects, but the number is still, at best, a guess.  It's not like building a bridge:  you can't estimate (very well) the amount of steel and concrete, simply because software is not bound to physical properties.&lt;br /&gt;&lt;br /&gt;So how do you get this model to work?  The "fudge factor" is in the productivity.  You set your productivity so low that you know, absolutely, you won't miss the estimate.  Why do you only produce 1 LOC per hour?  StarOffice, considered one of the largest open source projects, is estimated around 9 million LOC.  That's 4,500 man/years, using our previous calculation of 1 LOC per day.  4.5 years with 1,000 developers, or 45 years with 100 developers.  Obviously, something else is going on.  Estimates show that productivity can be around 10 times our estimate.  But how do you get there?  That's the topic for next time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-6156412322775214614?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/6156412322775214614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=6156412322775214614' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/6156412322775214614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/6156412322775214614'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2009/03/schedule-loc-and-budget-youre-lying.html' title='Schedule, LOC, and Budget?  You&apos;re Lying'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-1495050452913546744</id><published>2009-03-06T12:13:00.000-08:00</published><updated>2009-03-06T13:00:19.671-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='work'/><title type='text'>Score Your Work!</title><content type='html'>Today's topic will be a quiz:  how much does your employer suck?  Total up the points at the end (javascript if I feel nice).&lt;br /&gt;&lt;br /&gt;1.   Cafeteria - Does you company: &lt;br /&gt;offer tasty, fresh food upon request for reasonable price, including free?  (1 point)&lt;br /&gt;offer mediocre food at their convenience?  (0 points)&lt;br /&gt;employ LunchLady Doris?  (-1 point)&lt;br /&gt;&lt;br /&gt;2.  Security - Does your company:&lt;br /&gt;treat you like an adult, and keep physical security to a minimum (badge readers, etc)?  (1 point)&lt;br /&gt;Have some sort of obviously CYA policy in place involving security guards?  (0 points)&lt;br /&gt;check your badge at the gate, again at the building, then again at the entrance to your office? (-1 point)&lt;br /&gt;&lt;br /&gt;3.  Work Environment - Does your company:&lt;br /&gt;Have modern, clean, up-to-date, large, well-lit work areas? (1 point)&lt;br /&gt;Have old, dirty, out-of-date, small, dark work areas?  (0 points)&lt;br /&gt;Have all of the previous and have on-going construction so it sounds like you're working on a major street at rush hour?  (-1 point)&lt;br /&gt;&lt;br /&gt;4.  Equipment - Does your company:&lt;br /&gt;provide you with what you need to do your job, and provide an easy mechanism to acquire it?  (1 point)&lt;br /&gt;begrudgingly provide the minimum of what you need, but make the process so tedious that it's usually not worth the effort? (0 points)&lt;br /&gt;prefer to maintain a death-grip over the infrastructure, in order to maintain their need to exist?(-1 point)&lt;br /&gt;&lt;br /&gt;5.  Management - Does your company:&lt;br /&gt;have a reasonable number of managers, who are willing and capable of working with you to effect change in the way the company does business?  (1 point)&lt;br /&gt;have too many managers, some of whom have no noticeable effect on productivity?  (0 points)&lt;br /&gt;have so many managers that they create a totally separate reporting chain to separate work and labor-related issues?  (-1 point)&lt;br /&gt;&lt;br /&gt;More to come!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-1495050452913546744?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/1495050452913546744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=1495050452913546744' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1495050452913546744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1495050452913546744'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2009/03/score-your-work.html' title='Score Your Work!'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-2596665001090863613</id><published>2009-02-19T07:52:00.000-08:00</published><updated>2009-02-19T09:01:04.070-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>The Blob Problem</title><content type='html'>No, that's not a typo of Blog.  The Blob Problem goes hand in hand with &lt;a href="http://en.wikipedia.org/wiki/Scope_creep"&gt;scope creep&lt;/a&gt;.  As a project grows, it grows from a well-defined box into a poorly defined blob.  The box, and blob, correspond to the answers to the questions "What does it do?" and "How does it do it?"  From the beginning, the box clearly defines the application's domain, and the volume inside the box (I'm already stretching the metaphor) is open and visible.&lt;br /&gt;&lt;br /&gt;As the project grows, "dark areas" of the system appear, and the box becomes less transparent, more translucent.  It grows out of its original area, and starts stretching to join other areas of interest.  Rather blob-like.  Over time, the function and scope of the original project has morphed into something largely different.&lt;br /&gt;&lt;br /&gt;So what do you do?  As always, &lt;a href="http://c2.com/xp/DoTheSimplestThingThatCouldPossiblyWork.html"&gt;Do The Simplest Thing That Could Possibly Work&lt;/a&gt;.  So the answer is, "It depends."  But do what you like.  I'm personally fond of a wiki with some design documentation in it.  The debate about whether UML fits into DTSTTCPW still rages on, but I like to use UML more like a sketch tool.  I don't care if it's correct, or that all aspects of the design are analyzed.  If it explains "X talks to Y," or "X does A, B, then C" better than words would, then it covers DTSTTCPW.&lt;br /&gt;&lt;br /&gt;Your system is still a set of Legos.  Once it becomes one large Lego, the internal shape needs to be described, so that someone can use it and/or work on it without a lot of extra effort.  The amount of documentation that is needed is surprisingly low, and for good reason:  too much documentation is worse than too little.  By trying to plow through a mountainous tome of documentation, you're wasting your developer's time.  But by creating, reviewing, and maintaining that stack, you're wasting everyone's time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-2596665001090863613?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/2596665001090863613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=2596665001090863613' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2596665001090863613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2596665001090863613'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2009/02/blob-problem.html' title='The Blob Problem'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-3483652053558824558</id><published>2008-12-30T14:05:00.000-08:00</published><updated>2008-12-30T14:47:58.204-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>PHP for Java Developers</title><content type='html'>After years (and years) of working solely with Java, I've started learning some basic PHP.  Coming from a strongly-typed, object-oriented background, it has been quite an interesting adventure.  First off, I'll say that with an IDE like Eclipse, the programming language is almost irrelevant, once you understand the basic syntax for control structures and declarations.  Once over that hurdle, it really becomes a matter of finding the right functions in the right libraries to do what you need to do.&lt;br /&gt;&lt;br /&gt;I don't intend to get into which language is better.  It's like arguing whether a hammer is a better tool than a saw.  They fill different niches, and the bottom line is it's always better to have more tools in the drawer.  But there are a few things that will catch a Java developer, and those are what I want to mention.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Global Scope and Declaration&lt;/span&gt;&lt;br /&gt;PHP lets you do something like this:&lt;br /&gt;&lt;br /&gt;        $textlocation = $linelocation + 5;&lt;br /&gt;&lt;br /&gt;Simple, right?  Well, the gotcha is if you forgot to declare $linelocation, it will try to figure out what you meant.  In this case, $linelocation will be an integer with value 0.  In Java, that wouldn't compile, since there's no type associated with $linelocation, and no value assigned to it.&lt;br /&gt;&lt;br /&gt;On the same topic, global variables have to be declared to be global.&lt;br /&gt;&lt;?php&lt;br /&gt;    $var = 5;&lt;br /&gt;   fuction foo()&lt;br /&gt;   {&lt;br /&gt;      echo "var: $var\n";&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;Would not output 5 as you might expect from&lt;br /&gt;public class Bar()&lt;br /&gt;   private int var = 5;&lt;br /&gt;    public void foo()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("var: " + var);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;The reason is again, the dynamic variables.  unless $var is declared as "global $var;" inside of foo, PHP will assume you don't want the global variable.&lt;br /&gt;&lt;br /&gt;Now, the good side of dynamic variables.  PHP will also allow you to do things like&lt;br /&gt;    $data = array ("date" =&gt; "12-29-2008", "name" =&gt; "Winter Park",&lt;br /&gt;"min temp" =&gt; 3);&lt;br /&gt; all in the same array.  First element is a date, second element is a string, and third element is an integer.  Now you can argue that Java deliberately doesn't allow that type of array, and the Generics changes in JDK 1.5 further restrict that kind of action, but there are instances where it is very handy and very quick.&lt;br /&gt;&lt;br /&gt;OK, quick complaint:  PHP doesn't have a println function.  You have to remember to print "\n" after every echo or print command.  There, I said it.  I guess I can make a&lt;br /&gt;function println($var)&lt;br /&gt;{&lt;br /&gt;    echo "$var\n";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;but that seems like overkill (even for a Java developer).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Database Access&lt;/span&gt;&lt;br /&gt;Unlike Java, PHP has a much more streamlined database access system.&lt;br /&gt;    $connection = mysql_connect("localhost:3306", "user", "pass");&lt;br /&gt;    $result = mysql_query("select * from schemaname.table");&lt;br /&gt;    while(($row = mysql_fetch_row($result)) != null)&lt;br /&gt;    {&lt;br /&gt;        var_dump($row);&lt;br /&gt;    }&lt;br /&gt;    mysql_close($connection);&lt;br /&gt;Opens, queries, prints the returned rows, and closes the database connection.  7 lines (counting braces).  And since $row is an array, you can access it like any other array $row[0] is the first column, etc.  Which leads into the next point:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Exception Handling&lt;/span&gt;&lt;br /&gt;PHP does not require any exceptions to be caught, even though they can be thrown.  It will handle migrating exceptions up the stack for you until it finds a handler or the top of the stack.  So you can effectively ignore errors without having ... throws OneException, TwoException on every method like Java.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Arrays&lt;/span&gt;&lt;br /&gt;Maybe I've written one too many classes using StringTokenizer, but being able to turn&lt;br /&gt;$var = "0 1 2 2";&lt;br /&gt;&lt;br /&gt;into an array of string using&lt;br /&gt;$vararray = explode(" ", $var);&lt;br /&gt;&lt;br /&gt;is really handy.&lt;br /&gt;As is being able to interchange arrays, lists, and tables on the fly.  So you can do things like this:&lt;br /&gt;&lt;br /&gt;$vararray[0] = "zero";&lt;br /&gt;$vararray["one"] = 1;&lt;br /&gt;$vararray[] = "two"; // add to end of list&lt;br /&gt;&lt;br /&gt;more to come!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-3483652053558824558?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/3483652053558824558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=3483652053558824558' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/3483652053558824558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/3483652053558824558'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/12/php-for-java-developers.html' title='PHP for Java Developers'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-5009192410087270146</id><published>2008-11-13T06:55:00.000-08:00</published><updated>2008-11-13T10:16:25.683-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Reformed Adblocker Speaks Out</title><content type='html'>Like most internet users, I am annoyed by ads.  So I use &lt;a href="http://adblockplus.org/en/"&gt;Adblock Plus&lt;/a&gt; in Firefox to eliminate ads.  Seems like 28,742,796 people agree with me, since that's the number of downloads Adblock Plus has had, according to Mozilla.com (as I write this).  That's a lot of people saying one thing: "Stop bugging me with ads."  But is it throwing out the baby with the bathwater?&lt;br /&gt;&lt;br /&gt;Many (most?) web site survive on a mixture of ad revenue and sales.  One of which is minute (ad revenue hangs around $0.005 per view, so 1,000 views will pay $5.00), the other is relatively large (buying a shirt at $30 or so).  Used correctly, the two can be used to create sustainable income.  Sustainable for the site bills, not necessarily for the owner's, anyway.  But the problem comes from logic that "if a little is good, more will be better," in this case, a little advertising generates X dollars, then more, intrusive, annoying advertising will generate X+Y dollars (I'm not even going to bother to make up numbers).&lt;br /&gt;&lt;br /&gt;Those of you who have been around long enough remember the progression.  First, a banner ad at the top of the site.  Then, an X10 pop-up (remember those?), then an inter-site ad between pages.  Now, all of those above, plus the textual-context pop-up and whatever else they can think of.  At some point the line was crossed and Adblock became a lifesaver.  People said "Enough blinking, flashing punching of monkeys!"  and blocked it all.&lt;br /&gt;&lt;br /&gt;Then along came Google, with simple, targeted text ads.  It's like the English butler of web ads.  "Excuse me sir, if I may, I have some products that may be related to what you are looking at.  They're over here if you'd like."  Compared to the used-car salesman method used before, Google single-handedly overhauled the web advertising model.  But, how many people can see them, assuming they are blocking all ads with Adblock?  Some may argue that they will look for products when they look for products and content when they look for content and don't want the two to mix.  That's fine, those people are not the ones I'm worried about.&lt;br /&gt;&lt;br /&gt;I think a reasonable middle-ground can be reached.  Use Adblock, but with a whitelist to approve of sites that you enjoy/aren't annoying with their ads.  Start with this:&lt;br /&gt;&lt;br /&gt;@@/pagead2.googlesyndication.com/*$script,subdocument&lt;br /&gt;&lt;br /&gt;to unblock Google ads.  Then remember to right-click on the Adblock stop sign icon and click "Disable on &lt;your&gt; site" so they can get some of their revenue back.&lt;br /&gt;&lt;br /&gt;I think a more permanent solution can be found with something like &lt;a href="http://openid.net/"&gt;OpenID&lt;/a&gt;.  With it, you can have an account and log into any participating site.  Using it, a site (or series of sites) can track how much a user has contributed and show/hide ads appropriately.  If a user makes a donation of $10, they don't see ads for a year.  Like a subscription, but applied to all the sites under the umbrella.  Recognizing that:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;people want something other than being bombarded by ads&lt;/li&gt;&lt;li&gt;web sites won't survive without revenue&lt;/li&gt;&lt;/ul&gt;will create a new model that benefits everyone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-5009192410087270146?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/5009192410087270146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=5009192410087270146' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5009192410087270146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5009192410087270146'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/11/reformed-adblocker-speaks-out.html' title='Reformed Adblocker Speaks Out'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-7007676257377022214</id><published>2008-09-29T07:55:00.000-07:00</published><updated>2008-09-29T09:26:36.561-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Where Does The Time Go?</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;When you start a project, don't you marvel at how efficient you are?  How much you can get done in so little time?  Why can't we always be that efficient?  There are a number of reasons why efficiency drops off.  Producing documentation (oh, you want someone else to help you, or you want someone else to use your project?), meetings (you need to work with these other people?), and bug fixes are the primary detractors from producing new functionality.&lt;br /&gt;&lt;br /&gt;I've said before that &lt;a href="http://stewartj76.blogspot.com/2008/01/loc-is-pointless-metric.html"&gt;Line of Code count is a horrible metric &lt;/a&gt;for measuring software development.  It's like measuring hammer strokes in building a house, or the number of licks to get to the center of a Tootsie Pop.  So I will be using percentage of time as a virtual metric.  What percentage of time is spent in which task is a much more useful estimation than counting the number of nails used in a wall.&lt;br /&gt;&lt;br /&gt;When you start a project, obviously most of your time is spent building new features.  There may be some note-taking along the way to help you remember what you're doing, but really you're just trying to produce something that works, to solve your original problem.  As you move along, there will be a equilibrium between new code, bug fixes, documentation, and meetings.  You will wind up with a graph that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_C03EJGDvKjw/SOD8fjqnxeI/AAAAAAAAACA/5fcxFfF2Dt8/s1600-h/good-code.JPG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 329px; height: 223px;" src="http://4.bp.blogspot.com/_C03EJGDvKjw/SOD8fjqnxeI/AAAAAAAAACA/5fcxFfF2Dt8/s320/good-code.JPG" alt="" id="BLOGGER_PHOTO_ID_5251474784594150882" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Good amount of new growth, reasonable amount of bugs being fixed, not too much other stuff.  Enough documentation to be useful, but not so much as to be a mountain.  A few meetings to discuss what's going on and how it's going.&lt;br /&gt;&lt;br /&gt;Compare to these two horror cases:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_C03EJGDvKjw/SOD_bi-bZoI/AAAAAAAAACI/IIC--0qnXfU/s1600-h/too-many-bugs.JPG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_C03EJGDvKjw/SOD_bi-bZoI/AAAAAAAAACI/IIC--0qnXfU/s320/too-many-bugs.JPG" alt="" id="BLOGGER_PHOTO_ID_5251478014224197250" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_C03EJGDvKjw/SOD_s3FdMAI/AAAAAAAAACQ/9-h-0iWhnsY/s1600-h/too-much-process.JPG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_C03EJGDvKjw/SOD_s3FdMAI/AAAAAAAAACQ/9-h-0iWhnsY/s320/too-much-process.JPG" alt="" id="BLOGGER_PHOTO_ID_5251478311680159746" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Given that there are only 24 hours in a day (please don't let my boss find that out...), for every additional chunk of time taken doing something else, that's time that can't be spent building software.  So how do we maximize the time spent building software, and find the sustainable balance between too much documentation and too little?  That's a topic for another day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-7007676257377022214?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/7007676257377022214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=7007676257377022214' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/7007676257377022214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/7007676257377022214'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/09/where-does-time-go.html' title='Where Does The Time Go?'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_C03EJGDvKjw/SOD8fjqnxeI/AAAAAAAAACA/5fcxFfF2Dt8/s72-c/good-code.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37481637.post-7573803439056599073</id><published>2008-09-04T07:02:00.000-07:00</published><updated>2008-09-04T07:40:52.983-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gtd'/><title type='text'>Making a List, Checking it Twice</title><content type='html'>I woke up this morning and thought to myself "How does Santa Claus keep himself motivated?  He has one big deadline once a year.  For 364 days of the year, he really doesn't have much to do." &lt;br /&gt;&lt;br /&gt;OK, seriously, like most people, I've been having a hard time getting out of bed, especially now that it's dark out when the alarm goes off.  And the first thing that goes through my head is "Ugh, another day, just like the last one."  But today I made a quick list of things I needed/wanted to get done for the day, and I actually felt motivated to get out of bed and go to work.  Of course, I'm now working on my blog, but I've still got an agenda for the day.&lt;br /&gt;&lt;br /&gt;The list for the day is pretty simple (hey, I though it up at 5:45 this morning, cut me some slack):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Configure &lt;a href="http://cruisecontrol.sourceforge.net/index.html"&gt;CruiseControl &lt;/a&gt;to do something useful&lt;/li&gt;&lt;li&gt;Find my best three job postings and send resumes to them&lt;/li&gt;&lt;li&gt;Write up a couple business ideas (things to do if I get tired of programming)&lt;/li&gt;&lt;/ul&gt;It definitely makes it easy to get out of bed when you've got something to do, something new to learn, something new to try.  Hope it helps you as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-7573803439056599073?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/7573803439056599073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=7573803439056599073' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/7573803439056599073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/7573803439056599073'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/09/making-list-checking-it-twice.html' title='Making a List, Checking it Twice'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-777515280470758733</id><published>2008-09-02T08:08:00.000-07:00</published><updated>2008-09-02T09:11:27.513-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>Is Your Company In Trouble?</title><content type='html'>Obviously, I'm going to look at this from a software development perspective, but it will include some general business observations (10 years of work experience gives you some business sense).  Without espousing a particular methodology (although I'm sure I've made it clear what I support), ask yourself the following questions:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Does this Company offer a challenge that's innovative and interesting?&lt;/li&gt;&lt;li&gt;Do they offer easy access to innovative and interesting challenges (how easy is it to work on something that interests me)?&lt;/li&gt;&lt;li&gt;How would a new idea be received?  With questions like "How do we budget for it?" or "How can we use that to save money?"&lt;/li&gt;&lt;li&gt;Is the Company worried about meeting estimates, rather than providing functionality?&lt;/li&gt;&lt;li&gt;What's the Meeting/Time Quotient?  Do you have to constantly attend meetings and provide status, or can you get your work done with few interruptions?&lt;/li&gt;&lt;li&gt;How is the office environment?  Are you provided with just what you need to get the job done, or do you have an office that you'd like to show people?&lt;/li&gt;&lt;li&gt;Is their business model currently or potentially threatened by other Companies?  Are they doing anything to become/remain the industry leader?  How open are they to new ideas to help the company?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;What is the company attitude about new software?  Can you try it out and see if it helps your situation, or do you need approval to try it?&lt;/li&gt;&lt;li&gt;How long does it take to "do something"?  How many steps in how many systems involving how many people does it take to report a bug/checkout/fix/build/deploy/test/check in/close the bug?  If any of those numbers is large, what is preventing the system from being optimized?&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-777515280470758733?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/777515280470758733/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=777515280470758733' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/777515280470758733'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/777515280470758733'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/09/is-your-company-in-trouble.html' title='Is Your Company In Trouble?'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-321108387039083649</id><published>2008-08-25T12:53:00.000-07:00</published><updated>2008-08-25T12:53:00.170-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Are You Wasting Time?</title><content type='html'>No, I don't mean reading my blog or surfing the internet or watching youtube videos.  I mean even when you are working, are you spending time doing repeatable tasks that could be automated, and are you doing tasks that do not contribute to the development of the product?&lt;br /&gt;&lt;br /&gt;The first question is the easy one to ask, but can be a hard one to fix.  For example, does your build require you to "do something" to go from the built baseline to a running executable to test or deploy?  If not, what's holding it up?  Is the build simply not setup to do that, or is some portion of your system not configured to do it?  If it's the second case, that's a bigger problem, but it can still be overcome by working with your system administrator and addressing the holdup.&lt;br /&gt;&lt;br /&gt;The second question is the bigger task, and will usually require buyoff from your program Higher-Ups.  I see this problem as the corollary to the &lt;a href="http://c2.com/cgi/wiki?AgileManifesto"&gt;Agile Manifesto&lt;/a&gt;, which states (among other things) "Working software over comprehensive documentation."  I like to sum that statement up simply "Does this help me do my job?  Would this help someone else do my job?"  If the answer is "No" don't do it.  You can quickly see where that would be a problem with the Higher-Ups, and the "That's the Way We Do It" crowd.&lt;br /&gt;&lt;br /&gt;Another corollary to the Agile Manifesto is "It's OK to Screw Up", meaning, do something, give it to the users, and they'll tell you what they like and don't like about it.  But do it fast enough to have enough time to fix the problems, and add the new features to it.  This can't be done in a rigid environment, where it takes weeks just to get a fix to the users, never mind the amount of time to develop a new feature.  To do it, and do it fast, and get it right, actually takes less overhead than you'd think.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-321108387039083649?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/321108387039083649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=321108387039083649' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/321108387039083649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/321108387039083649'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/08/are-you-wasting-time.html' title='Are You Wasting Time?'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-5464972524762304917</id><published>2008-08-22T07:00:00.000-07:00</published><updated>2008-08-22T07:15:55.626-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Building Blocks or Jigsaw Puzzle?</title><content type='html'>Is your system building blocks for a larger system, or jigsaw puzzle pieces to build the same system?  A puzzle piece fits into one and only one spot.  A building block will fit into one spot, but can fit into other spots as well.  I also like to think of it as a "spiky vs. smooth" interface.&lt;br /&gt;&lt;br /&gt;What make good building blocks?  The obvious buzz-words "extensible, re-usable, decoupled, cohesive modules" apply, but it's easier too look at.  How hard is it to add new data to the system, and how hard is it to make the system do something else?  If the answer to any of those is "not easy", then you're building jigsaw puzzle pieces.  Look at your method signatures.  Do they perform specific functions on specific types of data?  Those are puzzle pieces.  Do they perform specific functions on generic data, or (better still) generic functions on generic data?  Those are building blocks.&lt;br /&gt;&lt;br /&gt;So what makes reusable, extensible data objects?  Obvious answers are object inheritance and using a syntax like XML.  But no matter how you do it, you need to identify similarities between data and only handle unique data in special cases.  Abstraction of data into generic objects for modeling and design helps describe the mappings between similar data.&lt;br /&gt;&lt;br /&gt;An example of what I'm talking about.  How many times have you seen "The Bank Example?"  But imagine that example built to handle one very specific type of currency and a couple specific use cases:&lt;br /&gt;depositDollar&lt;br /&gt;and&lt;br /&gt;withdrawDollar.&lt;br /&gt;&lt;br /&gt;Simple, straightforward, and almost totally non-reusable (without refactoring).  The use cases would be diligently mapped to methods named&lt;br /&gt;depositDollar(Dollar dollar)&lt;br /&gt;and&lt;br /&gt;Dollar withdrawDollar()&lt;br /&gt;&lt;br /&gt;in class AccountAccess.  Dollar, being a good data class, would contain all the useful metadata about your dollar:  serial number, creation year, number of wrinkles, that sort of thing.  On the server, the business logic would need to store the Dollar and withdraw the Dollar from the Account, and do all the associated checking that goes along with it.  So now, how do we add a new data type or another operation?  Yup, create a new use case and a new method.  Repeat ad infinitum (or at least ad naseum).&lt;br /&gt;&lt;br /&gt;Now we've got a system doing very similar things on very similar data, but it's hard to refactor because you're used to thinking about the specific types of data, that a Dollar is somehow different than a Quarter, or a Euro.  The only thing that can pull us out of this mess is to re-evaluate the data, and more importantly, what the users want to do.  They want to put money into their account and withdraw money from their account.  Now, generically, we can use methods&lt;br /&gt;deposit(Money amount)&lt;br /&gt;and&lt;br /&gt;Money withdraw(Money amount)&lt;br /&gt;&lt;br /&gt;where Money is, of course, an interface that Dollar, Pound, Euro, etc. all implement.&lt;br /&gt;&lt;br /&gt;Now, I realize that there will be have to be some "business logic" in the system, otherwise the system doesn't do anything unique.  But the amount of uniqueness should be low, and decrease, not increase, as the system expands.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-5464972524762304917?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/5464972524762304917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=5464972524762304917' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5464972524762304917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5464972524762304917'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/08/building-blocks-or-jigsaw-puzzle.html' title='Building Blocks or Jigsaw Puzzle?'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-5651795516777789083</id><published>2008-08-13T06:13:00.000-07:00</published><updated>2008-08-13T07:03:47.898-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Branches, Refactoring, and Deprecation</title><content type='html'>One of the biggest hurdles in refactoring is answering the question "How do I merge changes into something that's no longer there?"  I will attempt to lay out a useful strategy for addressing that problem.&lt;br /&gt;&lt;br /&gt;In our example, we've got a class that has a number of methods.  The number of methods continues to grow (and the amount of logic in those methods grows as well), to the point that the class is unmanageable.  It's no longer clearly defining its task (if it ever did), and has wandered off into areas that are outside its scope.  But, because of its importance to many areas of the system, and because of its poorly defined task, it has a lot of bugs in it.  The bugs may be from improper implementation, or incomplete analysis.  Either way, there's a lot going on in here.&lt;br /&gt;&lt;br /&gt;The obvious answer is "Refactor it."  However, that's not going to be easy, since there are still bugs that need to be fixed during and after refactoring.  How do we deal with this?  With a cunning use of deprecation and branching. &lt;br /&gt;&lt;br /&gt;Step one is to create a branch for the refactoring.  The syntax and details of doing this are different for every version control system out there, so I won't get into it.  Now you've got an area set aside just for refactoring without any outside influence and are able to verify that you haven't broken anything, through automated or manual regression testing.&lt;br /&gt;&lt;br /&gt;Step two is to deprecate the methods or classes that you've modified during refactoring.  But don't remove them!  That will keep a merge point for you to pick up an additional changes that happend during refactoring and testing, and inform other developers that the class is about to change and the current method is no longer supported.  In addition, a beneficial practice when deprecating (I'll use Java as an example, since I'm most familiar with it) is to include the @see tag to point the other developers at the right method.&lt;br /&gt;&lt;br /&gt;Step three is merge in any changes into your branch.  This will be a two step process: merge the changes into the original spot, then apply them into the refactored locations.  This may seem time consuming, but is really the only way to ensure that your branch is up to date before merging into the main line.  Re-run any tests for the changes to make sure that you merged the changes correctly (at this point, the benefit of automated testing over manual testing should be more obvious).  Now you can merge your branch into its parent.&lt;br /&gt;&lt;br /&gt;Step four is only necessary if other people are working on their own branches as well.  After such time has passed that all the branches have picked up the refactored class, you may delete the deprecated methods or classes.  This additional wait allows the other branches to migrate to the new organization at their own pace.  They will have to do the same step you did before merging:  apply any changes they've made to the original method to the refactored one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-5651795516777789083?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/5651795516777789083/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=5651795516777789083' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5651795516777789083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5651795516777789083'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/08/branches-refactoring-and-deprecation.html' title='Branches, Refactoring, and Deprecation'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-4138035593238213371</id><published>2008-08-12T07:18:00.001-07:00</published><updated>2008-08-12T07:30:48.877-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Development by Telephone Game</title><content type='html'>Does your development process have a lot in common with the &lt;a href="http://en.wikipedia.org/wiki/Telephone_game"&gt;Telephone Game&lt;/a&gt; (also called Chinese Whispers or Russian Scandal)?  I mean, how many steps, and how many people, are involved in getting what the users want into their hands?&lt;br /&gt;&lt;br /&gt;Do the users tell their management, who tell the prime contractor's systems engineers, who tell your system engineers, who tell you what to build?  Then, do you give your build off to the integration team, who gives it to the maintenance team to give to the users?  Let's see, that's seven steps between the users and the end product.&lt;br /&gt;&lt;br /&gt;That's one key area where open-source does it right, because they have to.  The user submits a bug or new feature to the developers.  The developers fix it or build it and give it back.  That's one step (OK, there's probably a couple internal steps for reviews, and testing, but I overlooked those in the first example, so I'm overlooking them in this example too).  And funny enough, it creates a stable product that delivers the functionality the user wanted faster than "Doing it the right way."&lt;br /&gt;&lt;br /&gt;Are you naive enough to think "But think of how good the product would be if they did it our way?"  The reason open source works (and work fast) is that there aren't multiple steps between the user and his product.  The best tools are used BY the developers (see &lt;a href="http://en.wikipedia.org/wiki/GNU_Compiler_Collection"&gt;GCC&lt;/a&gt; for example) during development.  If there's uncertainty, the developer talks to the user.  There's no "pushing issues up the chain" and waiting for resolution.  There's just a need, and the fulfillment of that need.&lt;br /&gt;&lt;br /&gt;So call it Agile, call it XP, call it whatever you want.  But if you base your development around creating user functionality instead of data functionality or system functionality, you will produce more user-usable functionality faster, simply because everything you build addresses some user need.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-4138035593238213371?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/4138035593238213371/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=4138035593238213371' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/4138035593238213371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/4138035593238213371'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/08/telephone-game-requirements.html' title='Development by Telephone Game'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-2382707069160588364</id><published>2008-07-30T07:47:00.000-07:00</published><updated>2008-07-30T08:25:53.785-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><title type='text'>The Cost of Big Servers</title><content type='html'>I decided to compare the cost/benefit of a blade arrangement versus a "big server" setup.  For the comparison I've configured a &lt;a href="http://configure.us.dell.com/dellstore/config.aspx?c=us&amp;amp;cs=04&amp;amp;kc=productdetails%7Epedge_m600&amp;amp;l=en&amp;amp;oc=becw1k1&amp;amp;s=bsd&amp;amp;fb=1"&gt;Dell &lt;/a&gt;&lt;span class="para_intropara"&gt;&lt;a href="http://configure.us.dell.com/dellstore/config.aspx?c=us&amp;amp;cs=04&amp;amp;kc=productdetails%7Epedge_m600&amp;amp;l=en&amp;amp;oc=becw1k1&amp;amp;s=bsd&amp;amp;fb=1"&gt;PowerEdge M600&lt;/a&gt; as my blade and a &lt;/span&gt;&lt;a href="http://shop.sun.com/is-bin/INTERSHOP.enfinity/WFS/Sun_NorthAmerica-Sun_Store_US-Site/en_US/-/USD/ViewConfigurations-List;sid=IPaHrWQsD7SHrCy8XhHPqIuzpmOfsyViOgvG437RpmOfsw==?ProxyProductRefID=DUMMY2--Sun_Fire_X4600_Se_1@Sun_NorthAmerica-Sun_Store_US&amp;amp;CatalogCategoryID=F8pIBe.d9XIAAAEUpVo5G_c2&amp;amp;ShowAllProducts=false"&gt;Sun Fire X4600 M2&lt;/a&gt; as my "big server" setup.&lt;br /&gt;Price:&lt;br /&gt;Dell =&lt;span name="pricing_sale_price" class="pricing_sale_price"&gt; &lt;/span&gt;&lt;span name="pricing_sale_price" class="pricing_sale_price"&gt;$2,605&lt;/span&gt;&lt;span name="pricing_sale_price" class="pricing_sale_price"&gt;&lt;br /&gt;Sun = &lt;/span&gt;$15,995.00&lt;br /&gt;&lt;br /&gt;CPU:&lt;br /&gt;Dell = 2x&lt;span class="olt_table_content_cfg"&gt;Quad Core Intel® Xeon® E5405, 2x6MB Cache, 2.0GHz, 1333MHz FSB&lt;br /&gt;Sun = &lt;/span&gt;4 Dual-Core AMD Opteron - Model 8222, 3.0 GHz&lt;br /&gt;&lt;br /&gt;RAM:&lt;br /&gt;Dell = &lt;span class="olt_table_content_cfg"&gt;8GB 667MHz (8x1GB), Dual Ranked DIMMs&lt;/span&gt;&lt;br /&gt;Sun = 16 GB (8 x 2 GB DIMMs)&lt;br /&gt;&lt;br /&gt;Disk:&lt;br /&gt;Dell = &lt;span class="olt_table_content_cfg"&gt;2x73GB 10K RPM Serial-Attach SCSI 3Gbps 2.5-in HotPlug Hard Drive&lt;/span&gt;&lt;br /&gt;Sun = 292 GB (2 x 146 GB) 10000 rpm SAS Disks&lt;br /&gt;&lt;br /&gt;OS:&lt;br /&gt;Dell = &lt;span class="olt_table_content_cfg"&gt;RHEL 4.5ES (although I would put some other Linux variant on if it were up to me).&lt;/span&gt;&lt;br /&gt;Sun = Solaris 10 (shocker, I know)&lt;br /&gt;&lt;br /&gt;Roughly, the Dell is 6x cheaper than the Sun, which means I can buy 6 of them for the price of the Sun (duh).  Now, partitioning that system could create two database servers (those would need more disk, obviously) and four application/web servers.  So for the price of one "big server," I've already got a cluster of four app servers and a cluster of two database servers.  Arrange as needed for your system.&lt;br /&gt;&lt;br /&gt;Throwing disk arrays into the mix continues this thought.  Comparing a &lt;a href="http://configure.us.dell.com/dellstore/config.aspx?oc=bvcwfw1&amp;amp;c=us&amp;amp;l=en&amp;amp;s=bsd&amp;amp;cs=04&amp;amp;kc=productdetails%7Epvaul_nf600"&gt;Dell &lt;/a&gt;&lt;span class="para_intropara"&gt;&lt;a href="http://configure.us.dell.com/dellstore/config.aspx?oc=bvcwfw1&amp;amp;c=us&amp;amp;l=en&amp;amp;s=bsd&amp;amp;cs=04&amp;amp;kc=productdetails%7Epvaul_nf600"&gt;PowerVault NF600&lt;/a&gt; to a &lt;/span&gt;&lt;a href="http://shop.sun.com/is-bin/INTERSHOP.enfinity/WFS/Sun_NorthAmerica-Sun_Store_US-Site/en_US/-/USD/ViewConfigurations-List?ProxyProductRefID=DUMMY2--Sun_StorageTek_5320@Sun_NorthAmerica-Sun_Store_US&amp;amp;CatalogCategoryID=tYhIBe.dZOMAAAEUG2A5G_c2&amp;amp;ShowAllProducts=false"&gt;Sun StorageTek 5320 NAS Appliance&lt;/a&gt; again shows the case against "one big server", even though we're comparing Network disk servers&lt;br /&gt;&lt;br /&gt;Price:&lt;br /&gt;Dell = &lt;span name="pricing_sale_price" class="pricing_sale_price"&gt;$4,926&lt;/span&gt;&lt;br /&gt;Sun =&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;strong style="font-weight: normal;"&gt;&lt;span id="CTOPrice2" class="cmPrice"&gt;$ 48,164.00&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Disk capacity:&lt;br /&gt;Dell = 4x&lt;span class="olt_table_content_cfg"&gt;400GB 10K RPM Serial-Attach SCSI&lt;/span&gt;&lt;br /&gt;Sun = 16 x 500 GB 7200 rpm SATA Disk Drives&lt;br /&gt;&lt;br /&gt;CPU:&lt;br /&gt;Dell = &lt;span class="olt_table_content_cfg"&gt; Dual Core Intel® Xeon® 5110, 1.60GHz, 4MB Cache&lt;/span&gt;&lt;br /&gt;Sun = 1 x 2.6 GHz (assuming AMD)&lt;br /&gt;&lt;br /&gt;Now we're in the ballpark of 10x price difference.  So I could have 10 Dell NAS drives serving my 6 servers (again, I know there's no reason to have 10 drives for 6 hypothetical servers, but just to prove a point), vs one big drive serving one big server.&lt;br /&gt;&lt;br /&gt;The price of adding "commodity-level" hardware is so (relatively) low, that there's almost no reason not to do it.  Planning to build on this type of architecture quickly leads to partitioned applications, so that a new application can get its own host, or any service that needs more power gets more power, rather than improving the performance of the service.  Figure $100/hour per developer.  If it takes more than half a man/week to profile, re-code, retest and redeploy the service, you'd be better off throwing hardware at the problem.  And as the net load on the system grows, it's much easier to build out horizontally when the increment size is small. &lt;br /&gt;&lt;br /&gt;Now I know that you can run multiple virtual servers on one "big server", but the point I'm trying to get across is that the bang-for-the-buck of the "little" servers is much much greater, and acutally building around small servers creates a more modular, scalable software architecture.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-2382707069160588364?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/2382707069160588364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=2382707069160588364' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2382707069160588364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2382707069160588364'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/07/cost-of-big-servers.html' title='The Cost of Big Servers'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-26535405038395416</id><published>2008-07-23T07:24:00.000-07:00</published><updated>2008-07-23T07:48:50.613-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Agile Architecture</title><content type='html'>Agile (or eXtreme Programming) development usually focuses on the development of the software itself, but it can (and should) be applied to all parts of the system.  If the architecture of the system is determined before the first iteration and not open for refactoring or other redesign principles, then it falls into the category of &lt;a href="http://c2.com/cgi/wiki?BigDesignUpFront"&gt;BigDesignUpFron&lt;/a&gt;t.  To put the problem another way, how can the domain of the system be determined if what the system will do is not determined?  And, if the system functionality is already determined, then there's no room to &lt;a href="http://c2.com/cgi/wiki?DoTheSimplestThingThatCouldPossiblyWork"&gt;DoTheSimplestThingThatCouldPossiblyWork&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;One argument against &lt;a href="http://c2.com/cgi/wiki?DoTheSimplestThingThatCouldPossiblyWork"&gt;DoTheSimplestThingThatCouldPossiblyWork&lt;/a&gt; is that nothing complex (like a compiler) would be built.  I disagree, simply because DTSTTCPW should only be applied to the domain as it is understood.  So TheSimplestThing when you are getting started &lt;span style="font-weight: bold;"&gt;should&lt;/span&gt; be different than TheSimplestThing as your system becomes operational.  TheSimplestThing when you are working in isolation on your personal computer becomes massively different from TheSimplestThing when you are providing a service on the Internet.  As a ridiculous example, think about the problem of searching for a given word in your filesystem.  Would you build Google to do it?  No (or I sincerely hope not).  You'd use &lt;span style="font-style: italic;"&gt;find&lt;/span&gt; or perl or some other script language.  Now, if you want to let anyone search for any word in any word on the Internet, now you've got to build Google, and all the system availability and performance benchmarks that go along with it.&lt;br /&gt;&lt;br /&gt;The great thing about Web technologies is that they scale well, and don't require replacing to service greater demand or performance objectives.  If one webserver can handle your own requests, then a cluster can handle thousands of them.  But how do you refactor an architecture?  Most people think of architecture as an inflexible part of the design.  Nothing could be further from the truth.  Writing POJOs (Plain Old Java Objects) leads quickly into EJBs (Enterprise Java Beans) in a J2EE container, or web services.  Same goes for any web-based scripting language.  Command line PHP can be easily hosted by Apache and serve the same data over the web. &lt;br /&gt;&lt;br /&gt;The key point is that just as your software should be designed iteratively, so should the archtiecture.  As the system requirements grow and change, the architecture should grow and change with it.  Will there be additional software changes to handle the new architecture?  Probably.  Will the overall system be better suited to handle the system parameters?  Yes.  Otherwise, you will be trying to put a now square peg into a hole that's still round.  It can be done, but is sure isn't TheSimplestThing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-26535405038395416?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/26535405038395416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=26535405038395416' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/26535405038395416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/26535405038395416'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/07/agile-architecture.html' title='Agile Architecture'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-2341620758147837207</id><published>2008-07-21T07:36:00.000-07:00</published><updated>2008-07-22T11:35:11.556-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>The Network Is The Problem</title><content type='html'>The first goal of any architecture should address two questions:  how does the user interact with the system, and what does the system do when the user can't connect.  Obviously, the goal of the system is to provide as much connectivity as possible, but there will always be potential problems between the client and the first network connection.  The system will need to address how to handle data that does not make it to the server (like, blogger, for example).&lt;br /&gt;&lt;br /&gt;How the user interacts with the system will affect how the system handles the data when the network is down.  Of primary importance is what to do with any data that would have been transmitted from client or server, and how to recover once connectivity is restored.  For a time-critical system, an additional important decision must be addressed:  what to do if the request isn't received in time.  If the request can't be fulfilled, does it still have value?&lt;br /&gt;&lt;br /&gt;By focusing on the user input, you can keep your project in scope.  If you start looking at data, then you can start looking at all the places that data can go, and all the systems that need to interact to deal with the data.  By focusing on what the user needs, rather than what the system requires, you can iteratively add more and more features, and rebuild the system as new capabilities are required for those features.&lt;br /&gt;&lt;br /&gt;A trivial example:  a user needs to know what his work assignments are.  So he 1) logs into the system (define the scope of the user environment, address network connectivity - see, I told you it would be important), 2) requests his work (pre-defined data, manual query?) 3) displays the data (what kind of display is available?)&lt;br /&gt;&lt;br /&gt;Now, once those decisions are addressed, they don't need to be addressed for the user to create a new work assignment.  Rather than attempting to figure out all of the system up front, the system can provide a needed functionality quickly.  Once a decision is made, it can be applied to all other functionality in the system.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-2341620758147837207?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/2341620758147837207/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=2341620758147837207' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2341620758147837207'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2341620758147837207'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/07/network-is-problem.html' title='The Network Is The Problem'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-3479284496449460629</id><published>2008-07-14T06:48:00.000-07:00</published><updated>2008-07-14T08:01:14.402-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Agility 101:  Refactor Your Build</title><content type='html'>One of the problems with using an adjective like "agile" or "extreme" (ugh) is that it implies a degree.  As in, "A mouse is more agile than an elephant."  However, you could say the elephant is more agile than, say, an aircraft carrier.  So, off the bat, agile seems open for interpretation, whereas Rational Unified Process or Waterfall have well defined steps that you either are doing or aren't doing.  This is wrong.  Agile has a very well defined set of processes, but since the term seems to lend itself to statements like "We need to add some agility,"  it is working at a disadvantage.&lt;br /&gt;&lt;br /&gt;The primary goal of agile development is continuous, sustainable development.  If this is not possible in your current environment, ask yourself why not?  A primary area for improvement is the build/deploy/test environment cycle.  If it takes hours to build, deploy, and coordinate testing, then you've reduced the amount of time available to do anything useful.  Some important points to consider:&lt;br /&gt;&lt;bl&gt;&lt;br /&gt;&lt;li&gt;How many steps does it take to go from build to running system?  If it's very many, re-examine all the functionality that &lt;a href="http://ant.apache.org"&gt;Ant&lt;/a&gt; provides.&lt;br /&gt;&lt;li&gt;Do multiple versions of the system potentially interfere with each other?  If so, figure out a way to run multiple versions in isolation.  As an additional point, can multiple versions of the same software co-exist on the same server or in the same environment?  If I need to care what you are doing, that's going to take time to rectify.&lt;br /&gt;&lt;li&gt;Can I build and test multiple branches without interfering with a previous build?  To reiterate the previous point, if it takes time to reconfigure and set up to test a fix or enhancement, that's time that can't be used for coding.&lt;br /&gt;&lt;/bl&gt;&lt;br /&gt;&lt;br /&gt;Given the capabilities of a tool like Ant, there's no reason that a complete, executing system cannot be produced out of every build.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-3479284496449460629?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/3479284496449460629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=3479284496449460629' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/3479284496449460629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/3479284496449460629'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/07/agility-101-refactor-your-build.html' title='Agility 101:  Refactor Your Build'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-7375286433185655094</id><published>2008-06-24T06:58:00.000-07:00</published><updated>2008-06-24T07:24:18.498-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Improve Product, Not Process</title><content type='html'>Believing that process improvement will improve the product is like believing spending more time looking at the map before taking a trip will prevent you from running into a traffic jam along the way.  Process improvement creates paint-by-numbers, it creates fast food.  Which is fine if that's your goal, but don't expect anything other than paint-by-numbers or fast food.  Otherwise, we're treading into Einstein's definition of insanity "Doing the same thing over and over and expecting different results."&lt;br /&gt;&lt;br /&gt;If you feel you must improve your process, plan your process for change.  There are too many uncontrollable variables to have any expectation of a successful delivery with a single waterfall method.  So plan your process for more frequent changes, more frequent reviews, and more frequent releases.  Hmm, this sounds like agile (without a capital A).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-7375286433185655094?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/7375286433185655094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=7375286433185655094' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/7375286433185655094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/7375286433185655094'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/06/improve-product-not-process.html' title='Improve Product, Not Process'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-1941531128543005776</id><published>2008-06-17T07:25:00.000-07:00</published><updated>2008-06-17T07:41:20.465-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Just Because You Can, Doesn't Mean You Should</title><content type='html'>A note on the Agile adage "Do the Simplest Thing That Could Possibly Work. (DTSTTCPW)"  DTSTTCPW does not mean "Do the Easiest Thing," or put another way "Just Because You Can, Doesn't Mean You Should." (Hey look, a title!)  There's a file line between those two ideas, because the Simplest Thing to one person isn't necessarily the Simplest Thing for everyone else involved.  Reducto ad absurdum example:  suppose someone keeps the requirements in a Word doc on their desktop.  Anyone who wants to know what they have to do has to go look at that one person's desktop.  Now that's surely the Simplest Thing in this case, but that is definitely &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; the Simplest Thing for everyone.&lt;br /&gt;&lt;br /&gt;So, as usual, we have a problem.  How do we figure out the Simplest Thing when it comes to organization and communication?  Here's some guidelines:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;if you have to search for it, it's not in the right place&lt;/li&gt;&lt;li&gt;if you have to use different tools, you don't have the right tool&lt;/li&gt;&lt;li&gt;if you have to ask, it's not documented well enough&lt;/li&gt;&lt;li&gt;if you have to change the process to get something done, the process needs to change&lt;/li&gt;&lt;/ul&gt;The first point will stop the practice of "Put it on the data server" in a unnavigable directory structure that combines software, business development, schedule, test, birthday lists, and everything else under the sun.  Do you have a number of bookmarks and shortcuts to help you navigate your data drive?  So do I.  This problem can be traced back to the problem that the project is not focused on the Product, but more on everything else that goes into the Product.  If the data is not related to the person who has to wade through it, get rid of it (or at least put it somewhere else).  Sourceforge once again comes up as the model.  All the documentation related to the Product is stored there.  Want to use it?  Read the documentation.  Want to see the bugs?  Look in the tracker.  Want to help?  Download the source for Subversion or CVS.  It's a very simple idea that's very easy to overlook:  The Product is the Project (hopefully Scott McNealy will forgive me).&lt;br /&gt;&lt;br /&gt;A documentation system based on a file system just isn't effective anymore.  Sure, it works.  Much like any outdated technology still works, there's just a much better way to do it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-1941531128543005776?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/1941531128543005776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=1941531128543005776' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1941531128543005776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1941531128543005776'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/06/just-because-you-can-doesnt-mean-you.html' title='Just Because You Can, Doesn&apos;t Mean You Should'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-2201377637023968047</id><published>2008-06-10T12:03:00.000-07:00</published><updated>2008-06-10T12:32:54.164-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>The Simpsons as a Software Model</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_C03EJGDvKjw/SE7QBzexS3I/AAAAAAAAABA/3-iEJtOY8T0/s1600-h/homer-car.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp0.blogger.com/_C03EJGDvKjw/SE7QBzexS3I/AAAAAAAAABA/3-iEJtOY8T0/s400/homer-car.gif" alt="" id="BLOGGER_PHOTO_ID_5210330548331957106" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Like most things in life, The Simpsons show us the way.  Or, rather in this case, the way NOT to do something.  In  &lt;a href="http://snpp.com/episodes/7F16.html"&gt;"Oh Brother, Where Art Thou?"&lt;/a&gt; Homer gets to request all the features he wants in his dream car.  In effect, he gets to design the car himself.  You can see the result on the left.  That's like what happens if our customers get all the features they ask for. &lt;br /&gt;&lt;br /&gt;Our end product ends up looking like that.  Lots of features "stuck on" with very little concern for the overall design.  Sure, it will work, and come out as a finished product, but the true art of software comes from taking all those features and still producing a cohesive, solid design.  But, like most designs that are "customer-driven," it is way over budget (at least it's not behind schedule, as well).  Now, if you're in a market where you can continue to charge the customer to make up the budget, that's a feature, and probably a goal.  However, in the real world (and the Simpson's world as well), an ugly, poorly designed product won't sell.&lt;br /&gt;&lt;br /&gt;So how do we get from Homer's vision (which, incidentally, he was quite pleased with) to a mass-market friendly one including all the features the customer requested?  One simple step that seems to be largely overlooked is "Saying No."  I can't believe I've even got to put this down, but if the customer makes an outrageous request, saying no (and explaining what we should do instead) will cut the largest potential budget/schedule over-runners.  For example, I'm currently supporting a custom data synchronization engine for my current project.  Now, we are using a database that supports replication, but it is not available.  If we'd just said "No" (and for the record I said "No" but my managers didn't care, because they didn't want to say "No" to our customer), we would be able to use the built-in replication.  But we didn't.  C'est la vie.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-2201377637023968047?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/2201377637023968047/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=2201377637023968047' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2201377637023968047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2201377637023968047'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/06/simpsons-as-software-model.html' title='The Simpsons as a Software Model'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_C03EJGDvKjw/SE7QBzexS3I/AAAAAAAAABA/3-iEJtOY8T0/s72-c/homer-car.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-37481637.post-1058478001929626094</id><published>2008-06-05T10:12:00.000-07:00</published><updated>2008-06-05T13:13:12.279-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>A Software Fable</title><content type='html'>Gather 'round, kids.  It's story time.  There's so few fables written nowadays, and few of them would apply to software (if you read between the lines).  So here goes.&lt;br /&gt;&lt;br /&gt;Once upon a time, there were two groups of engineers out for a walk.  They came upon a creek, and, being engineers, decided to dam the creek.  The first group set to work immediately measuring the depth and width of the creek, calculating flow rates and how high the water would rise once dammed.  The second group looked at the creek and started throwing rocks into it.  The first group, having taken all their measurements, set off to carve a rock big enough to block the creek.  They left the second group still throwing rocks into the creek.&lt;br /&gt;&lt;br /&gt;Time passed, and the second group came back with their huge rock.  But unfortunately for them, the rain had turned the creek into a raging river and their rock was still not big enough!  Or it would have been a raging river if it was flowing.  To their surprise, they saw a dam built out of the rocks that the second group had been throwing!  The first group was amazed that something so big had been build by so many little rocks.  They went and asked the second group how they did it.  The second group said "Some of us looked for more rocks to put in a pile, and the rest of us threw the rocks from the pile onto the dam.  So while you were measuring and calculating, we were already solving the problem.  If anything goes wrong with the dam, we just need to throw more rocks.  If it rains more, we just need to throw more rocks.  You need to carve a whole new rock."&lt;br /&gt;&lt;br /&gt;Many morals apply to this story:  do the simplest thing that could possibly work, don't over-engineer the solution.  But the one I like is this:  if you leave engineers in the woods for too long, this kind of thing is bound to happen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-1058478001929626094?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/1058478001929626094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=1058478001929626094' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1058478001929626094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1058478001929626094'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/06/software-fable.html' title='A Software Fable'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-797804805015239390</id><published>2008-06-02T09:05:00.001-07:00</published><updated>2008-06-02T10:06:42.465-07:00</updated><title type='text'>Ghost Town</title><content type='html'>No, not the blog.  I know I missed a week due to The Big Release deadline on Friday.  I do this as a hobby, and comment about my real job.  So if I miss a week, my loyal readers (of which as far as I know there aren't any), will just have go without.&lt;br /&gt;&lt;br /&gt;That business aside, I started wondering about the New Developer Problem, or more specifically, the worst-case version of it.  "What if everyone here quit/disappeared/died/otherwise didn't work here any more?"  Maybe I'm on too much of an Indiana Jones train of thought lately, but I see it like an archeology expedition.  Some guys in fedoras pry open the door to our dusty office and see a bunch of dusty cubes.  They sit down and fire up the boxes.  Would they&lt;br /&gt;&lt;ul&gt;&lt;li&gt;be able to figure out what we were working on?&lt;/li&gt;&lt;li&gt;be able to continue on with what we were doing?&lt;/li&gt;&lt;/ul&gt;The first task is possible.  Assuming they can get user logins (Dr. Jones would probably Post-It surf around to find user names and passwords), they can probably click enough desktop files and folders to get an idea of what was going on.  But does that combination of information contained in SDFs, schedules, budget figures, requirements, etc. actually describe any of what was going on?  If you found a document in Egypt that said "June 1, 2500 B.C - build ground floor," would you be able to ascertain that you were looking at requirements for the Pyramids?  Because that's what our artifacts tell the outside observer:  not much.&lt;br /&gt;&lt;br /&gt;The second task is much more daunting.  Even if Dr. Jones was able to figure out what we were making, the first question would be "Where is it?" followed by "How do I make it work?" and "How do I fix it if it breaks?"  Can he find the answers to those questions buried in all the process-mandated documentation?  Maybe it's possible, but in my experience, it's unlikely.  Most of my projects have been treated as one big project, rather than a large number of small projects.  So all the documentation was (is) created with respect to the whole project, and didn't reflect the individual pieces of the system.  That's like trying to understand the internet by reading the HTML and HTTP specs.  Yes, you'll understand what it does, but how it does it is totally ignored.&lt;br /&gt;&lt;br /&gt;Now imagine Dr. Jones's expedition into a open-source development model software facility (adverb chain ahoy!).  He walks in, clicks the browser icon on the desktop (hopefully the only icon there), and the browser goes to the project home page.  Now he can see the project roadmap, open bugs, read documentation, and download code and start making changes and fixes.  With that kind of organization based on the product, you don't need to be an Indiana Jones.  Even Marcus Brody could find his way around that project, and he got lost in his own museum (supposedly).&lt;br /&gt;&lt;br /&gt;Most of this problem comes from each group involved doing the easiest thing for them.  For testers, they create Word docs.  For systems engineers, they create Rational UML.  For software engineers, they create code.  But all those things add up to create documentation focused on whatever each group finds important.  The documentation needs to be correlated to the end product, and should be stored in a common place that can show the correlation of the documentation to the product, i.e. a project website.  Sure, software can be built in many ways, but you are at risk if you project depends on "project experts" or "domain specialists."  If there are areas that aren't immediately understandable, that's an area for improvement of documentation or refactoring.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-797804805015239390?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/797804805015239390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=797804805015239390' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/797804805015239390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/797804805015239390'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/06/ghost-town.html' title='Ghost Town'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-8810042051500718145</id><published>2008-05-14T06:30:00.000-07:00</published><updated>2008-05-14T07:25:27.931-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Setting the Bar Low</title><content type='html'>I work in a company that is primarily concerned with doing just enough to get the next contract.  That is a demotivation for any employee who wants to keep up with technology, or branch out into a new area of development.  The problem with that mindset is that it is difficult to convince anyone that any change is a good idea.  You will be met with answers such as "It worked fine (we delivered something on time), why change?" and more simply "That's the way we do it."&lt;br /&gt;&lt;br /&gt;That's a perfectly fine mindset if you are working on an assembly line.  But, as I've stated repeatedly, treating software as simply production is to do disservice to it.  More importantly, the company will lose their top developers who would quickly tire of doing the same thing over and over.  But this is not change just for the sake of change.  Rather, it is change for product improvement.  Doing it better, and/or faster.  Take the old vi argument.  Sure, you can develop software in vi, but I can do it much faster with Netbeans or Eclipse.  But the metrics are already skewed toward the development rate with vi, so I've now got free time on my hands.  What do to with it?  I'd like to work on something else, investigate something new, or otherwise improve the product in development, deployment, organization, or maintenance.  But I'm told I can't, because "There's no budget" or "You're not authorized."  So we keep on happily cranking out buggy whips (no pun intended).&lt;br /&gt;&lt;br /&gt;Einstein's old adage "Insanity is doing the same thing over and over and expecting different results" is well understood in a large company.  The side of it that's not noticed is the side that wants to keep talented developers, but doesn't realize that we're really just doing the same thing over and over.  What's really needed is to totally throw out the existing schedule and really challenge the developers.  Don't give me three months to do a task, give me three weeks, or three days.  You will get a radically different solution, simply by being prevented from solving the problem the same old way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-8810042051500718145?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/8810042051500718145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=8810042051500718145' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/8810042051500718145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/8810042051500718145'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/05/setting-bar-low.html' title='Setting the Bar Low'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-1052807074660385609</id><published>2008-04-21T09:02:00.001-07:00</published><updated>2008-04-21T09:15:54.123-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>K.I.S.S Applies to Process As Well</title><content type='html'>K.I.S.S. (Keep It Simple, Stupid, not the 70's band) is a tenet of agile software development.  But it should also apply to all facets of development and not be limited to just writing code.  If you've got to go to one server to get requirements, another one to view design documents, a third to build your code, and a fourth to view problem reports, odds are one or more of those systems will be out of date.  "One server to rule them all" is a much more maintainable approach and ultimately a more useful approach for everyone involved.&lt;br /&gt;&lt;br /&gt;There are a number of great sites organized like this, but SourceForge is probably the largest.  One project page contains all the necessary elements for the lifecycle of the project:  code, documentation, support forums, bug/feature tracking, and release downloads.  A user, a developer, and a manager would all access the same site.  This is, as always, by necessity.  In a distributed development environment, every developer has to have all the necessary information available to them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-1052807074660385609?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/1052807074660385609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=1052807074660385609' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1052807074660385609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1052807074660385609'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/04/kiss-applies-to-process-as-well.html' title='K.I.S.S Applies to Process As Well'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-1851408702026300971</id><published>2008-04-01T07:11:00.000-07:00</published><updated>2008-04-01T07:57:53.386-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>The Problem with the Office</title><content type='html'>No, not Microsoft Office.  Not the TV show.  I mean the place where you work.  You know, your cube.  The problem isn't exactly with the office, but rather with having office-mates around.  Specifically, the problem is the availability of those people.  You know, Bob the database guy, Phil the systems guy, or Jill the tester.  If you have a question, you go ask them.  If they have a question, they come ask you.  What's the problem with that, you ask?  The problem is that the resolution to that question is only known to you two.  The problem is that if anyone &lt;span style="font-weight: bold;"&gt;else &lt;/span&gt;wants to know what the answer is, they have to ask one of you.  That's job security, to some people.&lt;br /&gt;&lt;br /&gt;When an open-source developer has a question, or has to make a decision, there's usually no one there to ask.  So the developer has to go the project mailing list, or forum, or website, and ask the question to the group.  Then anyone else can see the answer.  If anyone else thinks the question is very important, it can be added to the documentation, FAQ, wiki, or whatever.  That way, the documentation represents what anyone really needs to know about the project.&lt;br /&gt;&lt;br /&gt;This problem is reflected in the "learning curve" for business projects.  Some companies try to overcome this shortcoming by mentoring, or shadowing, or other methods for effectively "picking someone's brain."  But all they are doing in ingraining the mindset that some &lt;span style="font-weight: bold;"&gt;person &lt;/span&gt;knows the answer and will give it to you if you ask.  This is a dangerous process, because it creates many single points of failure.  What if Bob the database guy gets hit by a bus?  Who else knows how to run the database?  If he'd written it down, then someone else will be able to take over.  Overcoming the job security mentality is a tough task.  But, assuming that no one will work at the same job for their whole career, a repository of information is absolutely necessary.&lt;br /&gt;&lt;br /&gt;Your coworkers may be great people, but stick to talking to them about non-work issues.  If it's about the project, create a record of it.  If you really like process, create a process to review all the wiki entries, problem reports, and mailing list entries for review for possible inclusion into the formal documentation.  But, above all else, write it down!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-1851408702026300971?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/1851408702026300971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=1851408702026300971' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1851408702026300971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1851408702026300971'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/04/problem-with-office.html' title='The Problem with the Office'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-1655872750975258385</id><published>2008-03-10T06:49:00.000-07:00</published><updated>2008-03-10T08:01:20.468-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Government Software, An Oxymoron</title><content type='html'>Or "Software by Earl Scheib:  I Can Build that System for $49.99"&lt;br /&gt;I can't wait for Google to start a Federal Systems group.  Until they (or someone else with their deep pockets and development methodology) get involved, the rest of us will continue with status quo.  It is unfortunately not in our company's best interests to improve the way we develop software.  In fact, poor software process is encouraged because it allows budget and schedule over-runs, otherwise known as Cost Plus and Follow-On Work.&lt;br /&gt;&lt;br /&gt;Both sides are at fault for this, but ultimately the blame has to fall on the developer side.  The client is only asking for what they want, as they always do.  The problem lies with the development staff not explaining that they are making unreasonable requests.  Furthermore, allowing the client to determine the technology to create the system will most likely not utilize the most optimal architecture for the problem.  Which leads to more Follow-On Work.  Perfect: the client gets what they want:  a convoluted, inefficient system, and we get more money to fix our mistakes later!&lt;br /&gt;&lt;br /&gt;Honestly, I can't wait for Google's first meeting with govvies where they say "You'll get your software when it's ready" and watch multiple General's heads explode.  I don't have any idea if Google is crazy enough to enter this arena, but if they do, they will dominate it.  Why?  Because the existing competition is some combination of lazy and inept.  Or, we are happy doing whatever crazy job the customer thinks up next.&lt;br /&gt;&lt;br /&gt;I can't believe that the Form-A-Committee-to-Investigate-A-Commission world of the government works as closely as they do with the Long-Haired-Free-Thought world of software development.  I know they've had in-house staffs before outsourcing the work, and I think that's pretty good evidence that they don't understand how to do it.  But rather than say "Build me my system and give it to me when it's ready" they still want to have control over the process, but have success at the end.  Remember Einstein's definition on insanity?&lt;br /&gt;&lt;br /&gt;So why Google?  They've got the money to make it work, but more importantly they've got the influence to break the model.  Get government's hand off the software except deciding what they want and making sure it works, and you get a better product.  Come to think of it, "Get government's hands off... and you get a better product" is a more succinct explanation anyway.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-1655872750975258385?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/1655872750975258385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=1655872750975258385' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1655872750975258385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1655872750975258385'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/03/government-software-oxymoron.html' title='Government Software, An Oxymoron'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-5577518813358373825</id><published>2008-03-03T07:01:00.000-08:00</published><updated>2008-03-03T07:32:12.197-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Keep It Small</title><content type='html'>One of the largest (no pun intended) problems with building government software is too much knowledge at project inception.  For the most part, we are rebuilding or adding onto an existing system.  Therefore, we think we know where we want the end product will be, and think we know all the problems we will encounter along the way.  As Murphy's adage states, that is a recipe for disaster, or at least schedule slip.  By not building the system as a progression, but rather taking it as a monolithic task, the environment for innovation is decreased (to put it as nicely as possible).  Like a used car, if the system works perfectly now, why are we rebuilding it?&lt;br /&gt;&lt;br /&gt;The fallacy that "We built this before, so we know what it does" should never be applied to a system redesign.  The problem with it is that it does not address all the other things done under the covers to create the end result.  The existing system should not be used as a model for the new one, but rather the functionality the existing system attempts to provide should be recreated in the new one.  Or more simply put:  look at what it does, not how it does it.&lt;br /&gt;&lt;br /&gt;This problem results from the XP concept of &lt;a href="http://c2.com/cgi/wiki?BigDesignUpFront"&gt;Big Design Up Front&lt;/a&gt;.  Simply put, it's taking too big of a bite that results in a system that's too complex to be understood, tested or extended.  Yes, it sounds like the paradox "Can God Create a Rock So Big He Can't Move It?" and, when applied to software, quickly becomes "Can People Create a System So Big They Can't Understand It?"  I'm sure you'll agree the answer is yes, and very quickly.  In fact, the greater task is preventing that from happening.&lt;br /&gt;&lt;br /&gt;So how do we resolve the problem of Big Design Up Front?  Stop thinking about it.  Take the known pieces of the system, design them such that they can produce query-able, re-usable output (XML Web Services or EJBs in this era), and build it.  Define the architecture and the data flows, but keep your hands off the system components.  There's enough to do to define or redefine what the users are doing, or better, what they want to do.&lt;br /&gt;&lt;br /&gt;I propose the Rule of One:  if the problem can't be defined, described, and agreed upon in one hour, it is too complex.  Most people would groan at a meeting that is scheduled for more than one hour.  Therefore, one hour is quite enough time to organize an approach and discuss the issues with that approach.  That quickly leads into &lt;a href="http://c2.com/cgi/wiki?DoTheSimplestThingThatCouldPossiblyWork"&gt;The Simplest Thing That Could Possibly Work&lt;/a&gt; .  Additional issues can be addressed in other iterations, but to get the ball rolling requires a quick, basic action.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-5577518813358373825?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/5577518813358373825/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=5577518813358373825' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5577518813358373825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5577518813358373825'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/03/keep-it-small.html' title='Keep It Small'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-2408357634238583129</id><published>2008-02-08T11:55:00.000-08:00</published><updated>2008-02-18T08:07:28.882-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Happy Birthday, Open Source Software</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Bruce_Perens"&gt;Bruce Perens&lt;/a&gt; wrote an article noting that &lt;a href="http://perens.com/works/articles/State8Feb2008/"&gt;today is the 10th anniversary of the Open Source Initiative&lt;/a&gt;.  As discussed, on &lt;a href="http://linux.slashdot.org/article.pl?sid=08/02/08/174250"&gt;slashdot&lt;/a&gt;, this doesn't necessarily mean ten years of open, collaborative software development, but rather ten years of promoting open software as a viable option to closed, proprietary software.&lt;br /&gt;&lt;br /&gt;Today's post is not to discuss the pros and cons of open versus closed software development (Lord knows there's enough of that without me getting involved.  See &lt;a href="http://slashdot.org/"&gt;slashdot&lt;/a&gt; again.  I'm much more interested in open source development as a model for general software development, and what it offers that closed development does not.  Specifically, how can the open-source model create so much (MySQL, Firefox, OpenOffice, Apache, etc. etc.) with so little (development staff, management, time, money, etc. etc)?&lt;br /&gt;&lt;br /&gt;Knowing that the development staff won't be available forces open source to make a number of decisions about project organization.  Because there's no full-time staff, all the assignments have to be given out in a way that is verifiable, discreet, and in isolation.  Every developer knows where their piece fits into the application, and all the application information is available and up-to-date.  The project has to be self-contained, easy to set-up and document progress.  See &lt;a href="http://mozilla.org/developer"&gt;Mozilla.org&lt;/a&gt;'s development site for a great model of how to keep the staff informed simply.&lt;br /&gt;&lt;br /&gt;Knowing that the staff won't be available requires the use of a software version control system that allows disconnected operation.  While not crucial, this model allows the developer to work in isolation until they are ready to submit the changes for approval.  This allows the product to be more stable for longer periods of time while development is ongoing, and requires the use of a branching/merging policy to handle bugfixes and new feature development.&lt;br /&gt;&lt;br /&gt;Because the development staff may change at any time, code reviews are given a higher priority.  There's little room for the attitude that "He did good work last time, so it can slide."  Everything has to be reviewed, documented and tested long before hitting the main baseline.  Again, this keeps the stable release as stable as possible and removes many opportunities for error.&lt;br /&gt;&lt;br /&gt;Open software development follow the model "Give them the tools they need and get out of the way."  Innovation and creativity can flow freely in an environment like this, at lower cost with higher productivity.  But corporate development is stuck in a Catch-22:  managers won't go for a "radical" change like this, since it would put them out of a job.  So even though us lowly developers know there is a better way, we won't be allowed to use it.  And that's very sad.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-2408357634238583129?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/2408357634238583129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=2408357634238583129' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2408357634238583129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/2408357634238583129'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/02/happy-birthday-open-source-software.html' title='Happy Birthday, Open Source Software'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-558296734231130655</id><published>2008-02-05T08:21:00.000-08:00</published><updated>2008-02-18T08:07:18.375-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>Making Programming Boring</title><content type='html'>Back to software stuff, a day late again.&lt;br /&gt;&lt;br /&gt;My company is working very hard to make programming boring.  Maybe boring is too strong of a word, but certainly mundane, simple, and straightforward.  But, in the usual double-whammy of bad idea and impossibility, this is a move in the wrong direction.&lt;br /&gt;&lt;br /&gt;The problem lies in identifying and defining the task.  If the task is so tightly defined that no innovation can take place, then the project is bound to stagnate.  While there are circumstances where a tight definition of requirements is both desired and necessary, most situations would dictate that you development staff knows more than you do about the domain of the problem to be solved.  Joy's law states that "Most intelligent people work somewhere else", which is really a corollary to "50% of the people are below average."  That simple fact can be used to prove that both the designer and programmer are average at best.  But it also says that there may be someone in the staff who does "think outside the box," which is only possible if the box is not closed on all sides.&lt;br /&gt;&lt;br /&gt;Programming is not brick-laying, or assembly-line work.  People may mistake the "Cathedral and Bazaar" analogy as indicating that the work must either be done by skilled craftsmen or by "workers."   Software is neither a blank canvas nor a paint-by-number.  It is somewhere in between, and each absolute end is used very infrequently.  The innovative work done by a company like Google was either designed or created by a few, very smart people and then passed to less-smart (again, invoking Joy's Law) people to implement or use and expand upon.&lt;br /&gt;&lt;br /&gt;Innovation is what created the software technology we have today, and to try to over-engineer the design and implementation to the point of stifling innovation will lead to a loss of talent who don't want to work where their ideas aren't recognized and ultimately to a loss of market share to companies that can innovate and create software more quickly, for lower cost, and taking better advantage of the existing technologies.  If all you know how to make is widgets, and all your people know about is making widgets, then you would be oblivious to anything that solves your problem better than a widget.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-558296734231130655?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/558296734231130655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=558296734231130655' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/558296734231130655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/558296734231130655'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/02/making-programming-boring.html' title='Making Programming Boring'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-6249365743217159841</id><published>2008-01-21T07:24:00.000-08:00</published><updated>2008-02-18T08:06:35.769-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>There's No Such Thing as Bottom-Up Design</title><content type='html'>Yes, I'm stealing "There Ain't No Such Thing As A Free Lunch," from Robert Heinein as the title this week.  It's catchier than "Bottom-Up Design is really Stupid and Hard to do Right."  I'm not saying that it is impossible, but only because I believe that nothing is impossible given enough time, talent and organization.  But Bottom-Up design is much more difficult to manage than Top-Down design, for a number of reasons:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Management of many incomplete services is much more time-consuming than management of a few complete services.  The ramp-up for staffing to begin defining interfaces and interactions of those interfaces is much steeper than working slowly and getting the first part working, correctly, before beginning step two.  This ramp-up smacks right into the &lt;a href="http://en.wikipedia.org/wiki/Mythical_Man_Month"&gt;Mythical Man Month&lt;/a&gt; formula that group communication equals &lt;span class="texhtml"&gt;&lt;i&gt;n&lt;/i&gt;(&lt;i&gt;n&lt;/i&gt; − 1) / 2, where n = the number of developers.  But by working slowly, the group can reach consensus one one point much quicker than making a decision on many unknowns.  As a result, much more time than is necessary is spend monitoring the progress of many, partially functioning services.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="texhtml"&gt;Bottom-Up implies Top-Down, but not vice-versa.  This one should be obvious enough to be the nail in the coffin of Bottom-Up design on its own.  Any class/function needed in a Bottom-Up design should only be created to fulfill a need.  But what defines the need?  That's right, some sort of Top-Down analysis.  But then, why perform a perfunctory analysis and stop there?  If you need to declare the situation in which you need the function, it makes sense to continue defining the situation to an implementable solution, rather than defining ALL possible situations with little effort given to the interactions of those situations.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="texhtml"&gt;Bottom-up design fails another Brooks truism.  Create a working prototype and "grow" the software iteratively.  By trying to define everything that needs to be done at once, the developer may miss out on opportunities to refactor the design.  Creating a working prototype allows the developers to focus on what IS known, rather than spending time and effort trying to define everything that isn't know yet.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;Bottom-Up design fails to design and build the system that you need now, but is more focused on the total system that you will need.  Thinking that way, the system fails to take into account the ripple effect of design changes into the defined interfaces.  Any flaws in a Bottom-Up design take more time to repair due to the cascading effect of changes across many, partially defined services.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-6249365743217159841?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/6249365743217159841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=6249365743217159841' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/6249365743217159841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/6249365743217159841'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/01/theres-no-such-thing-as-bottom-up.html' title='There&apos;s No Such Thing as Bottom-Up Design'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-1405367404574579823</id><published>2008-01-07T11:55:00.000-08:00</published><updated>2008-02-18T08:05:52.772-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>LOC is a Pointless Metric</title><content type='html'>&lt;blockquote&gt; Measuring programming progress by lines of code is like measuring aircraft building progress by weight.&lt;div&gt; &lt;/div&gt; &lt;div class="templatequotecite"&gt;—&lt;cite&gt;&lt;a href="http://en.wikipedia.org/wiki/Bill_Gates" title="Bill Gates"&gt;Bill Gates&lt;/a&gt;&lt;/cite&gt;&lt;br /&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div class="templatequotecite"&gt;&lt;br /&gt;If the head of a major company holds that opinion, what could that imply? To me, it means that you are tracking something that has no direct bearing on the end product. It's related to the product, no doubt about it, but it's a function of other factors, most notably functions or use cases, depending on if you are developing bottom-up or top-down.&lt;br /&gt;&lt;br /&gt;The pointlessness of LOC as a metric is directly related to its nebulous nature. What makes a line depends on how you measure it. Is a line truly one line in the source, or is it more like a statement? But what defines a statement? A semicolon in Java? Anything between braces? Something else? When building in assembly, each line of code actually did something to the computer. But how do you count an external library function call? It's an over-simplification to think that a line takes x amout of time to create and test, since each line is almost totally unique from the one preceding it.&lt;br /&gt;&lt;br /&gt;A LOC ain't what it used to be. How do you count lines when some of those lines are generated? And then, when your application gets refactored (you do refactor software, don't you), and your LOC goes down, then what? But there's time spent learning the tool to perform the code generation, time spent learning the tool syntax, and that time can't be accounted for until the tool is chosen and integrated.&lt;br /&gt;&lt;br /&gt;LOC is considered useful for the reasons that make it useless. You are tracking and managing one of the details of the project as if it has a bearing on the progress of the project. Imagine if my productivity was measured by the feet I walked per day. Less feet = more time at my desk = more productivity. Simple, measurable, but totally inaccurate. Simply because a LOC cannot be defined other than by convention, any use of it as a metric is debatable at best.&lt;br /&gt;&lt;br /&gt;So what? Simply, bid per high level requirement. Each requirement costs x dollars to implement, test and maintain. It's not a perfect system, but it would save time and money during analysis by not pretending to perform an estimated analysis on anything other than the functionality that has been requested.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-1405367404574579823?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/1405367404574579823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=1405367404574579823' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1405367404574579823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/1405367404574579823'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2008/01/loc-is-pointless-metric.html' title='LOC is a Pointless Metric'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-5126691935263396259</id><published>2007-12-31T12:54:00.000-08:00</published><updated>2008-02-18T08:05:19.740-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>How Burned Out Are You?</title><content type='html'>When it comes to career burnout, I've been a student for a couple years already.  During that time, I've been able to reflect on my career and learn some useful information about burning out.  There are many factors affecting burnout, most simply is working too much and not having any time left for yourself.  But it all boils down to a few simple questions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Am I as excited about my future here as I was when I started?&lt;/li&gt;&lt;li&gt;Does the situation look likely to improve in the time I'm willing to wait?&lt;/li&gt;&lt;li&gt;What aspects of this job are the most frustrating?&lt;/li&gt;&lt;li&gt;How would I like to change them?&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I like to look at burnout not as a yes/no proposition, but as a series of levels.  There are many different aspects of work which you may be tired of.  Let's look at my case as an example.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Customer:  NGA.  Typical government agency full of bureaucracy and political agendas.  Not the best environment to develop software in.&lt;/li&gt;&lt;li&gt;Project:  GeoScout.  Multi-company effort to overhaul NGA's hardware and software.  The problem is that no one understands what it does now, so it can't effectively be rebuilt.  Plus the development is hosted on a virtual server halfway across the country on a shaky network.  Need I say more?&lt;/li&gt;&lt;li&gt;Company:  Lockheed Martin.  We keep trying to make everything like making rockets, and you know what?  It doesn't work very well.  But our main job is convince our customers that we are doing a good job, so they keep hiring us.  Joy's Law is definitely in effect here, but no one seems to notice.  "We Never Forget Who We're Working For."  Yeah, not me.&lt;/li&gt;&lt;li&gt;Location:  Colorado.  Can't say too much bad about Colorado that can be said about any other big town.  So there's one aspect of my career that I can probably keep.  Although Ireland is looking very nice this time of year, or I'll have to buy a snowblower.&lt;/li&gt;&lt;li&gt;Industry:  Software Development.  Well, to be fair, government software development.   Most of my complains are with the way we're told/forced to do our jobs, when there are obviously &lt;a href="http://www.apache.org/"&gt;better ways to do development&lt;/a&gt; out there.&lt;/li&gt;&lt;/ul&gt;In assessing my burnout, I decided to make a small change first and see if it made a difference.  I still believe that I like developing software, so I wasn't ready for that big of a change yet.  I also wanted to give the company a second chance, so I merely changed projects within the same area.  It was a safe option, and allowed me to assess some of these aspects from a second perspective.  I still haven't reached a permanent decision yet, but I've got a lot better view of the situation now.  I'm planning one more effort here, then I'm on my way.  Email the CTO?  Sure, why not?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-5126691935263396259?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/5126691935263396259/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=5126691935263396259' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5126691935263396259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5126691935263396259'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2007/12/how-burned-out-are-you.html' title='How Burned Out Are You?'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-3242150807969975619</id><published>2007-12-18T07:38:00.000-08:00</published><updated>2008-02-18T08:05:08.999-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>UML and Paralysis by Analysis</title><content type='html'>Taking a break from Government complaining and back to work.&lt;br /&gt;&lt;br /&gt;First point:  UML is &lt;a href="http://en.wikipedia.org/wiki/No_Silver_Bullet"&gt;no silver bullet&lt;/a&gt;.  It is only as good as the people producing the diagrams, and the people reading the diagrams.  If the diagrams are produced by someone who doesn't understand the problem, how can they specify how to solve the problem?  And, if they need to be specified to the implementation level, what does that say about your developers?  UML works better when used in line with Brook's original hypothesis, that software should be iteratively grown.  Build the parts that you can understand, and add (and rebuild) new parts once you have the framework done.&lt;br /&gt;&lt;br /&gt;Second point:  UML is usually done to death.  It's similar to designing a house down to the cut lengths of each board.  The additional time and effort in designing to that level is lost when an error is made.  However, the error won't be determined until elaboration or construction.  So what's the point in trying to design the interaction between all the components, none of which exist yet?  UML should only be created to describe the problem to be solved to the level that a developer can understand it and ask questions.  Using it to describe the entire application creates a waterfall model, instead of continually refining the model as the application evolves.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-3242150807969975619?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/3242150807969975619/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=3242150807969975619' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/3242150807969975619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/3242150807969975619'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2007/12/uml-and-paralysis-byanalysis.html' title='UML and Paralysis by Analysis'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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-37481637.post-5620530639819851957</id><published>2007-10-21T18:50:00.000-07:00</published><updated>2008-02-18T08:03:21.394-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software process'/><title type='text'>On Software and Reluctance to Change</title><content type='html'>Even in a large, professional, closed-source development office, open source software is held in high regard by software developers.  This is countered by management's distaste for it on the grounds that "We have no one to hold accountable if it fails."  But why does open source have this (well earned) reputation?&lt;br /&gt;&lt;br /&gt;Open source, is even more evolutionary than closed source.  Closed source has the advantage of being developed by a paid staff.  Open source developers have a much more free range of choice of related projects to support, and the very few that are well organized, well planned, and well executed will survive.  Any body can start a new web server project, but very very few will be better than Apache.  In an environment without such direct competition for developer resources, a closed source solution can flounder on for years, and the developers may not even know that there is a better way!  Think of it like those fish that have evolved to live in caves without daylight.  Those fish are the proverbial "big fish in a little pond."  But put them out in the sunlight and they'd be killed!  But they do fill their niche quite well.&lt;br /&gt;&lt;br /&gt;Open source has to have the "Wow" factor.  As an outgrowth of the first point, no developer would want to work maintenance on an end-of-life project if they didn't have to.  But closed source doesn't necessarily have that constraint.  By tying the customer into a set of technologies, the closed source project makes changing from that vendor that much more difficult.  Especially in this era of the DMCA, trying to figure out what a vendor did with your data may end up in court!  There is some of that in the open source world, but once you can see the source, reverse engineering the data becomes that much easier.&lt;br /&gt;&lt;br /&gt;Open source has a long history of being a "hobby."  This is the battleship mentality of large, closed source software developments.  What they fail to realize is that all those CMMI certifications don't have any correlation to producing a stable, complete product.  That those hobby programmers have to have more strict controls over feature development, release schedules, etc.  By its nature, open source development depends on a central core of "committers" to control all the distributed effort.  Getting that help to understand its job quickly and to perform it to specification is absolutely critical to the success of the project.  All the development processes are driven by that point.  So being able to reassign a task to anyone who wants to work it must be able to be done with a minimum of effort by the developer and the committers.&lt;br /&gt;&lt;br /&gt;If closed source is like a super computer, capable of mind-boggling levels of effort, than open source has the capability to be like Seti@Home, capable of performing to much higher levels of performance than ever imagined!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/37481637-5620530639819851957?l=stewartj76.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stewartj76.blogspot.com/feeds/5620530639819851957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=37481637&amp;postID=5620530639819851957' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5620530639819851957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/37481637/posts/default/5620530639819851957'/><link rel='alternate' type='text/html' href='http://stewartj76.blogspot.com/2007/10/on-software-and-reluctance-to-change.html' title='On Software and Reluctance to Change'/><author><name>stewartj76</name><uri>http://www.blogger.com/profile/08873949095757732052</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></feed>
