web developer & system programmer

coder . cl

ramblings and thoughts on programming...


code hardening techniques

published: 23-02-2011 / updated: 23-02-2011
posted in: development, java, programming, tips
by Daniel Molina Wegener

Do you know something about Test Driven Development?, It is OK, you can reach optimal development performance using TDD, and similar methodologies. You will find yourself developing applications very quickly, but “how hard is your code?”. You can reach very high quality code only using your debugger, making tests is just not enough. Using some debugging techniques, you can find not evident bugs, and you will probably find succesfuly some bugs that can cause your application to core dump — core dump is one of the ugliest forms of application failures, I prefer to think that each application failures is not another thing than a core dump.

You can use unit tests and TDD, and double check that your algorithms are working. Also you can check your code using some static checker. Both will help to find you a little bit optimal code. This will allow you create more stable and reliable code, but not enough to be hard. When you code an aplication, you must think that the application and your code is merged within an environment, and it has dependencies. So, you need enough time to double check your code using tests and also, you need to double check your code using static checkers when they are available for your language. All is about input and output…

Your code has an input, from a service, from the user using a browser, from some data retrieval cron task, whatever, your application is subject of input errors. The typicall error is to reach null references, where your application tries to use an unallocated address space, using a reference to an object or anything related to it. The main technique against null reference, is to check the reference before you begin using it. Just to show some examples I will use Java code, I can use C++ or C code, but I prefer to use Java codes in this post:

  /***
   * Returns a list of File objects that match the given stream
   * name on the given directory.
   *
   * @param strm    Stream name.
   * @param bdir    Directory to List.
   * @return      An array of found File objects.
   */
  public static File[] getFileNamesForStream(String strm, String bdir) {
    ArrayList<File> res = new ArrayList<File>();
    if (strm == null || bdir == null) {
      return new File[0];
    }
    if (strm.trim().length() == 0 || bdir.trim().length() == 0) {
      return new File[0];
    }
    File fdir = new File(bdir);
    File[] rawdir = fdir.listFiles();
    if (rawdir == null || rawdir.length == 0) {
      return new File[0];
    }
    for (int i = 0; i < rawdir.length; i++) {
      String name = rawdir[i].getName();
      if (name.indexOf(strm) >= 0) {
        res.add(new File(bdir + File.separator + name));
      }
    }
    Collections.sort(res, new FileDateComparator());
    return (File[]) res.toArray(new File[0]);
  }

The code above does various checks. Ther first one is to check the strm and the bdir parameters to be null. If those parameters are null, the method returns an empty array — instead of returning a new null reference increasing the error probability — so the user do not process any file from the returned array, the returned object can be used transparently. Then checks for string emptyness, we cannot use empty file names, because the operating system do not allows empty file names, and again we are using a zero filled array as return object. Then we list files on the input directory bdir, and we check if there is any available file on the directory, if the directory is empty, we return a zero filled array, but never returns a null reference. The method is hardened against input and output. The example above is easy to handle, but “what happens to service enabled methods?”.

  /**
   * Initial method to handle playlist items on server startup.
   *
   * @param server      The server where to put the streams.
   */
  private void refreshPlayList(IServer server) {
    try {
      if (server == null) {
        return;
      }
      if (minutesToShift < 0 && ownServer != null) {
        synchronized (schedulerMutex) {
          minutesToShift = Long.valueOf(ownServer.
              getProperties().
              getPropertyStr("MinutesToShift", "41")).
            longValue();
        }
      }
      IVHost vhost = VHostSingleton.getInstance(server.
                         getProperties().
                         getPropertyStr("PublishToVHost", VHost.VHOST_DEFAULT));
      if (vhost == null) {
        return;
      }
      IApplication app = vhost.getApplication(server.
                         getProperties().
                         getPropertyStr("PublishToApplication", "live"));
      if (app == null) {
        return;
      }
      streamsToAdd = WowzaTools.getStreams(server.
                         getProperties().
                         getPropertyStr("StreamsToAdd", "_default_"));
      for (int si = 0; si < streamsToAdd.length; si++) {
        String streamName = streamsToAdd[si] + STREAM_SUFFIX;
        Stream stream = getStream(vhost, app, streamName);
        if (stream == null) {
          continue;
        }
        streamMap.put(streamName, stream);
        app.getAppInstance("_definst_").
          getProperties().
          setProperty(streamName, stream);
        setupStream(stream);
        IStreamActionNotify actionNotify = new
          StreamListener(app.getAppInstance("_definst_"));
        stream.addListener(actionNotify);
      }
      ScheduledItem sched = new ScheduledItem(
        new Date(System.currentTimeMillis() + 30000)
      );
      sched.start();
    } catch (Exception ex) {
      log.error(ex.getMessage());
      log.error(ex);
    }
  }

The method above is void, it do not have a return value. The first check is over the server argument, if it is a null reference, we exit from the method. Then checks for the minutesToShift and the ownServer static members, and uses a mutex to write on one of them, doing a synchronous write and doing it once. Then we check for the vhost and app variable to be null references, we exit from the method if any of them are null references. Those checks are made before using those variables. Depending on how do you handle that kind of errors, you should use an exception instead of a plain return, but it depends on how do you need to handle the error. Then, another check is done on the cycle, we check if the obtained stream is a null reference, if it is a null reference, we continue processing the loop, instead of using that null reference. On this method we depend on third party methods that can return null reference, so we must check for them, instead of being sure of their availability. If you are a good observer, you will notice that the method getPropertyStr() has a default return value when the parameter is not found, but “what happens with those methods without a default return value?”.


  public ActionForward execute(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
         throws IOException, ServletException {
    String target = "success";
    String request_arg = request.getParameter("request_arg") == null ?
                         "0" :
                         request.getParameter("request_arg");
    if (form != null) {
      NameForm nameForm = (NameForm)form;
      String name = nameForm.getName() == null ?
                    "" :
                    nameForm.getName();
    }
    if (name == null) {
      target = "failure";
    } else {
      request.setAttribute("name", name);
    }
    request.setAttribute("request_arg",
                         Integer.valueOf(request_arg));
    request.setAttribute("target", target);
    return (mapping.findForward(target));
  }

Above we have a typicall struts ActionForward method. It handles a request argument with a default value, using the ternary operator to do that. Checks for the possible null reference that can provide the request_arg parameter. The same applies to the form attribute name returned by the getName method. Using default values, can help you a lot. Null references are like a ninja waiting patiently to dismember you when are not expecting him. Again we have a method that is a little bit hardened. The same we can apply to our unit tests, we can ensure that they will not fail, for example if we have the following test:

  /**
   * Test Video Info Handling.
   */
  public void testVideoInfo1() {
    System.out.println("testVideoInfo1() Entering ->");
    String streamNames1 = "CHANNEL_TV";
    String directoryName1 = "/home/dmw/tm";
    VideoInfo[] streamsToAdd1 = WowzaTools.getInfoList(streamNames1, directoryName1);
    for (int i = 0; i < streamsToAdd1.length; i++) {
      VideoInfo current = streamsToAdd1[i];
      String msg = "Name: " + current.getVideo().getName()
        + "; Date: " + current.getTime()
        + "; Duration: " + WowzaTools.secondsToMinutes(current.getDuration());
      System.out.println(msg);
    }
    System.out.println("testVideoInfo1() Exiting >-");
  }

On this method we are testing the getInfoList() method. Since it is a testing class, it is easy enough to change the arguments passed to the getInfoList() method. We can pass null references, incorrect arguments and anything we think that can generate an error. We must not trust in the user input. Is easy to change some lines to streamNames1 = null;, streamNames1 = “xxx”;, directoryName1 = null;, directoryName1 = “/dev/null”;, or whatever can help you to detect possible failures in your code. You will be hardening your code if you can handle more errors which the typicall user can generate. Also, you must request enough time to your project manager to complete code hardening tasks and debugging sessions, which are slow, since you need to trace the code various times. Is not enough to write unit tests, you need to run your tests and debug them, and change every dependent value to ensure that your code is free of flaws. I do not know if project managers are considering code hardening or testing time, usually I just see enough time only to develop software, not to ensure that it will not fail. If you do not have enough time to do those tasks, because your project manager is not measuring that time as part of the development process, your project manager sucks…


No coments yet.

post a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>