Working With Two Projects at the Same Time

While working on my clojure http server this week, I ran into an issue working with one project that relies on another library on my machine. In this case my cob spec server relied on my http server library, but every time I made a change to the http server, I had to push the changes to clojars and then pull them down on my cob spec server. This caused me to run into problems when I made a change on my server library, and my cob spec server did not pick up the new changes. After struggling with this for a few hours, I needed to find another way to do this.

While doing some research on how to work on 2 projects at the same time, I found out about the Meiningen checkouts directory. The checkouts directory symlinks to the directory of the library you want you use, and Leiningen will pull the changes you have made into your new project. Adding this to my project has simplified my workflow, and reduced the amount of errors that I have encountered because of working on two projects.

Talking it Out

One of my current assignments of apprenticeship is to do a 10 minute talk each week on the SOLID principles of software development. Talking has never been an issue for me, but doing a talk on a more technical subject has its challenges. Here are some of the things that I have run into during my talks

Grammar

Grammar has never been one of my strong suits, but one of the easiest things that you can fix during a presentation, is the grammar of your slides. Make sure that everything is spelled correctly, and that you have not made any other glaring grammatical errors. While you are doing a talk on programming, people will still try and find any holes in your presentation: even the grammar.

Code Examples

Another issue that I have run into while giving my presentations is my code examples. The first few presentations that I gave, I wrote a code example on a whiteboard. While it made sense at the time, the whiteboard examples were riddled with flaws, but they can be fixed easily. One of the easiest fixes to your code examples is to do them ahead of time and type them out. Doing this will allow you to proofread your code, and make sure that it is actually valid code by running it through an IDE. One of the other mistakes that I ran into during my presentations is that I started out writing valid code and then ended up writing pseudocode. This leads to your examples becoming convoluted and hard to follow. I now write my code examples in an IDE to make sure that it is valid, and that the code will actually work.

Other Things

Another great thing you can do to help out before your presentation, is to get set up beforehand and make sure your setup works. The first talk I gave was a mess because the screens didn't show what I wanted which resulted in me getting flustered during my talk. Lastly the best thing that you can do before a presentation is to practice practice practice. Practicing will help you become more confident in your presentation, and it will help you smooth out any bumpy points in your presentation.

hard problems

This week I have been working on refactoring my http server to be more extensible. The first iteration of my server worked, but it would have only worked well as a static file server. Since the http standard isn't just about serving static files, I had to make some major changes in the architecture of my server in order to make it more extensible. One of the resources that my mentor pointed me to was the Clojure http middleware called Ring. Ring is not an http server, but instead it is what is known as a http middleware. Its job is not to handle the socket connections or reading in the http request and writing out the response, but instead its job is to convert the http request into a program readable format, pass the request to a handler, and then take the response back to the server to be sent out.

My goal for the next iteration of my http server is to create a layer of functionality that works like ring on top of my server layer. This will allow me to create handlers that can run anything from a web app to a static file server with my server layer just focusing on inputs and outputs. While the idea sounds easy enough when I write it in a blog, the idea has been giving me some trouble implementing because it requires functions that call functions from a list, and visualizing this sort of program is very difficult. I am making some good progress, but I am still a good distance from implementing this on my own. One of the resources I have been using to help me ideate this change is reading the ring source files on Github. The changes I am making to my server will not be as robust as what ring currently is, but seeing how the Ring creators handled certain issues has given me some inspiration on how to move forward.

I am very excited for this change to be completed because it is not a simple fix, and the challenges I face in implementing this, will force me into learning even more about Clojure than ever before.

Feedback is a Gift

This week I received a code review on my http server project from my mentor and a few of the other craftsman in the office. If you have never had a code review before, it is quite an experience to go through, but there is nothing else that can help you improve as a programmer than one. The hardest part of going through a code review is being able to detach yourself from your code, and accept the constructive feedback that you are being given. When you have spent a lot of time and effort on a project, it is easy to become attached to the code you have written and believe that it is perfect, but because you have become attached to it, you are no longer open to critiques that will help you grow as a programmer.

I have been making an effort during my apprenticeship to not be attached to my code in order to accept and implement the constructive criticism that is given to me so. These are the opportunities that will help me grow my programming skills, and to become a better software professional in general. Some of the things that I learned from this code review will stick with me forever: such as making sure that the tests and program will run on more than just your machine. In the first iteration of my server, I had hardcoded paths to the files on my machine that were required in the tests. This caused the test suite to fail on everyones computer except for mine. A lesson that I took away from this was to make sure that the test suite can run on a Continuous Integration platform like TravisCI in order to make sure that the program will work on more than just my machine.

What is Java Bytecode?

In my last post I went over how the JVM works at high level, and while I brought up the term Java bytecode, I didn't get to detailed on what it is. When you run the javac compiler on your code, your human readable java source code is converted into machine readable Java bytecode. Java bytecode is the intermediate representation of a Java programs source code that the JVM uses to create code that is executable on the native system. Because it is meant to be machine readable, bytecode cannot be read by a human, but Java gives us a way to view disassembled code. Disassembled code is the human readable instructions that are used make up the java bytecode.

So what does it look like?

As an example, I am going to use a simple Java program that prints "Hello World!" to the command line.

HelloWorld.java

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

If you were to run this program through the javac compiler, you would end up with a .class file, and it is this .class file that contains the Java bytecode. Because the bytecode is unreadable in this state, you must first run the file through the javap class disassembler to get the human readable bytecode instructions. you can do this by running the following command in the command line in the directory of the compiled .class file:

$ javap -c HelloWorld.class

Running this command will give you the result:

Compiled from "HelloWorld.java"
public class com.company.HelloWorld {
  public com.company.HelloWorld();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String Hello World!
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return        
}

These are the Java bytecode instructions that the JVM executes when running the HelloWorld program, but before I get into what each one means, I will first go over how the JVM executes the bytecode. The JVM is what is called a stack-based machine, and each thread that program runs, creates a new stack that stores frames. A frame is data structure that contains an operand stack, an array of local variables, and references to the constant pool associated with the class the method resides in.

A diagram of what a frame could look like:

Java stackhttp://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/

The operand stack is where the the computation occurs, and the bytecode tells the JVM what operations to perform on the stack. Each opcode (singular operation from bytecode) performs a certain function on the operand stack, and in combination with other opcodes, performs the instructions that were defined in your original Java source code. So lets take a look back at the Java bytecode is telling the JVM to do for the HelloWorld program:

Compiled from "HelloWorld.java"
public class com.company.HelloWorld {
  public com.company.HelloWorld();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String Hello World!
       5: invokevirtual #4            // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return        
}

The above code is the disassembled code from the HelloWorld program, and it contains two methods: the default class constructor, and the main method. These methods look very different from the Java source code that you wrote because it is the human readable format of the bytecode the JVM reads. Instead of containing your source code, each method contains a list of opcodes and there position in the methods bytecode array where they are stored.

So lets take a look at what the default constructor is doing. The first opcode that is stored at position 0 in the array is aload_0, and this code tells the JVM to push the reference stored in the local variable byte array slot 0 onto the operand stack. Next, is the opcode at position 1 in the method byte array, invokespecial #1. Invokespecial #1 tells the JVM to call the constructor of its superclass (in this case Object since there is no defined superclass), and the top value of the stack is popped. Lastly the return opcode tells the JVM to pop the top value from the current operand stack, and then push it to the top of calling method's operand stack.

Next we have the main method, and it has many different opcodes. The opcode in position 0 is get static #2, and it tells the JVM to push the item in the #2 spot in the class constant array, the System.out:Ljava/io/PrintStream, onto the stack. Then the JVM moves onto the next opcode at position 3, ldc #3. This is the code to push an object from the constant pool at spot #3 onto the stack, and in this case that is the string "Hello World!." Next in position 5, the opcode invokevirtual #4 calls the method println on the object at the top of the stack, and then right behind it at position 8, return returns the result.

This was a very basic overview of how the JVM executes a simple program, but it is enough to get the gist of what is going on. I have only scratched the surface of the internals of the JVM, but I am excited to keep digging into it.

References used

Java Bytecode by Peter Haggar