What is the JVM?

Over the past two months of my apprenticeship at 8th Light, I have been exclusively working on projects that run on the Java Virtual Machine, also called the JVM. While I have been working with the JVM for 2 months, I took what it did for granted, and have finally taken the time to do some research on it.

What is the JVM?

Java code is designed to be able to be written once and run anywhere, and this is accomplished by using the JVM. The JVM is a virtual computer that runs as a software process on a computer, and it has many different implementations so it can run on a variety of computers. This allows your java code to be run on many more environments in the exact same way it works on your personal environment.

What is a Virtual Machine?

A virtual machine is defined as "a software implementation of a machine (i.e. a computer) that executes programs like a physical machine." In other terms its a computer program that acts like a computer that runs in your computer. Even though that sounds like the plot from the movie Inception, this is a very common thing in computing, and it allows you to work with a different environment or operating system than what your computer is designed to support. This is accomplished by the virtual machine by emulating the correct architecture that is needed on a different system architecture.

How Does the JVM Work?

Now that we know the JVM is a virtual computer running as a software process on your computer, how does the JVM run your java code?

When writing Java code, you first write out your source code as a .java file, but this file itself is not yet executable on the JVM. The next step is to run your code though the Java Compiler which compiles your .java files into .class files. These .class files are files that can be executed on the JVM because they have been converted from human readable java code into an intermediate language called Java bytecode. This java bytecode is the instruction set that the JVM uses to execute your program.

Once the program has been compiled into .class files, you are now able to run your program on the JVM. Once you execute your program by running

$ java -jar yourProgram.jar

This command tells the JVM that you want to run this program, and the first step in executing the program is to load the class files into memory using the class loader. Once the class loader loads the class files into memory, the JVM can then execute the bytecode that the class files contain. Execution of the bytecode is done by the JVM execution engine. The execution engine's job is to compile the intermarry bytecode into the native execution code for the machine that it is running on. This is done by two different processes Just-In-Time Compilation and Interpretation.

An interpreter works by reading, interpreting and executing bytecode instructions one by one. This process is very quick at reading single instructions, but it is slow at executing the interpreted result. This makes the interpreter useful for executing single instructions that are not used as much in the program.

The second part of the execution engine is the Just-In-Time Compiler. The JIT works by compiling code into the native execution language at runtime. Natively compiled code works much faster than interpreting the code, but it takes more time for the compiler to compile the code at the start. For this reason, only code that gets executed many times will be compiled by the JIT compiler, and code that is used less, will be run by the interpreter.

Conclusion

This was a very basic overview on how the JVM runs your java code. In the next few days I will write another blog post that goes more in depth on how the java compiler compiles your java source code into bytecode, what bytecode looks like, and how the JVM executes the bytecode.

Lesson in Deployment

Last week a craftsman 8th Light, Doug, approached me with an opportunity to deploy an application called Cyber Dojo to Amazon Web Services. This was not my first time deploying an application, and I have come to learn that each one behaves differently. I agreed to help him deploy it, and he sent me a link to the instructions that I would need to deploy the application. After going over the instructions, I felt confident that I could set it up, and then thought the famous last words "how hard could it be?"

The first step in deploying the application was to spin up a virtual machine on the Amazon cloud that had a specific rails image installed on it, and this is where I made my first mistake. Cyber Dojo depends on a system called Docker to run and contain coding exercises in a multitude of different languages, and it requires a 64 bit architecture in order to be installed. I unknowingly spun up a 32 bit image on the virtual machine instead of a 64 bit image on my first install. When I got to the next step, installing Docker, the build failed and I quickly figured out the mistake I made.

Whelp, lets try that again...

Having figured out my first error, I spun up a new machine with a 64 bit architecture, and started the install process again. Everything went smoothly up until I had to install Docker again. The installation failed again, but for a different reason. Docker had an issue with the way that they signed their package, and the build script that Cyber Dojo included would not accept the unsigned package. I was able to remedy the situation by manually installing docker and accepting the unsigned package. After getting Docker installed, the rest of the deployment went smoothly, and I had a working application deployed on Amazon Web Services.

Not out of the woods yet!

The next day Doug came to me and said that the application was running slowly, so we went to take a look at what could make the application run so slowly. Well it turns out that it was running slowly because overnight about 20 new processes were installed on the machine overnight. How on earth did that happen? Since I was using the ec2 CLI tools to access the server, I did not realize that the root password for the linux box was set to "password" by the rails image installer. This is the probably the second worst thing you can do besides not put a password on a public facing server! After rebuilding the server and making sure the root password was not "password", the server remained stable, and it was able to be used for a training class the next week.

Lessons Learned

I learned two really important lessons from deploying this app:

  1. NEVER use "password" as a password on a public facing server
  2. DO NOT allow SSH access to the root of a public facing server

Overall this was a great experience, and I look forward to working on more deployments in the future!

Dependency Inversion Principle

  • Solid into
  • what is the dependency inversion principle
  • car example in Ruby

Continuing my blog posts on the SOLID principles of software design, today I will go over the Dependency Inversion Principle. The Dependency Inversion Principle is defined as,

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.

A less technical description of the DIP is that you want to separate the application wiring code from the code that is doing the logic. In order to satisfy the DIP your program should not create its dependencies within the class the relies on it, but instead it should have the dependency it needs passed into it when it is created.

This principle is hard to understand without a code example, so lets go over how the DIP works in ruby. In this example we have a driver who needs a car in order to drive. That code looks like this:

class Driver
    def initialize()
        @car = Car.new
    end
        
    def drive_car()
        @car.drive
    end
end

class Car
    def drive()
        puts "Driving a car"
    end  
end

This example is breaking the dependency because the Driver class is creating a new instance of a car each time a driver is created. While at first it makes sense to create a car when a driver is initialized because a driver always needs a car to drive, what happens if the driver becomes a truck driver? How would the driver be able to drive a truck if it always initializes a car when created. This is when the DIP is helpful because you pass the needed dependency into the class instead of creating it on initialization.

Here is the code refactored to use the DIP:

class Driver
    def initialize(vehicle)
        @vehicle = vehicle
    end
        
    def drive_car()
        @vehicle.drive
    end
end

class Car
    def drive()
        puts "Driving a car"
    end  
end

class Truck
    def drive()
        puts "I'm driving a truck"
    end
end

Since the driver class no longer initializes a car when created, any vehicle that has a drive method can be passed into the class and can be driven by the driver.

This was a simple introduction to the Dependency Inversion Principle, but even with it simplicity, it shows the flexibility that is gained from using it. By removing the dependency from being created within the class, the class could accept any dependency that has the same methods as it expects.

Open Closed Principle

Continuing my series of blog posts on the SOLID principles of software design, this post will pick up after the Single Responsibility principle and move on to the Open Closed Principle (OCP). The OCP is described by Bob Martin as, "SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION."

Open for Extension

Open for extension at first seems like a very broad idea, but at its basic, level it means that the behavior of the module can be extended. Extension is different than modification: extension means to add on to the existing platform, while modification means to change the underlying platform. If a new requirement were to be added, being open to extension would make it an easy process to bring the new behavior into the application by extending it instead of having to modify it.

Closed to Modification

As discussed in the above paragraph, modification means that you change the underlying code of the module. The OCP states that modules should be closed to modification, so how are you supposed to make changes to your software? Following the OCP, you would make these changes by extending the module, but this begins to seem like it is a closed loop because in order to extend the program you will need to first modify it to become extensible.

How do I make my program extensible?

The best way to make your program extensible is to make an abstraction that would handle all of the different extensions to your program. This relates back to an earlier blog post I did on a refactor from a conditional to polymorphism because at the time I was unknowingly fixing my program to conform to the OCP.

This is the original un-refactored code for my make move method in my unbeatable Tic Tac Toe engine written in Java:

while (!rules.gameOver(board)){
      if (currentPlayer instanceof HumanPlayer){
            currentPlayer.selectMove();
      } else if(currentPlayer instanceof ComputerPlayer) {
             console.computerMove();
             currentPlayer.makeMove(currentPlayer.unbeatableComputer());
      }
      console.printBoard();
      switchPlayers();
}

This code is in violation of the OCP because it can not be changed without modifying the underlying code of the method. If I wanted to add a different class of player (say an animal) to the program, I would have to do something like this:

while (!rules.gameOver(board)){
       if (currentPlayer instanceof HumanPlayer){
             currentPlayer.selectMove();
       } else if(currentPlayer instanceof ComputerPlayer) {
           currentPlayer.selectMove();
       } else if (currentPlayer instanceOf AnimalPlayer) {
                        currentPlayer.selectMove();
            }
       console.printBoard();
       switchPlayers();
}

Because I directly modified the function in control of making a move, I violated the OCP because I modified instead of extended, so how can I fix this by extending instead of modifying?

Abstraction is the answer here. In order for me to be able to extend the types of players indefinitely, I have to create an abstract interface that all types of players must implement. This is the design of the final function:

UML2

while (!rules.gameOver(board)){
      currentPlayer.selectMove();
      console.printBoard();
      switchPlayers();
}

Takeaway

In order to be in compliance with the OCP, your program needs to be able to create extendable interfaces that can add behavior without the need to modify the source.

Single Responsibility Principle

Over the past few days I have been doing research on the SOLID principles software development and how to utilize them in my code. The 'S' in SOLID stand for the Single Responsibility Principle, and this will be the focus of this blog post.

Single Responsibility Principle

The Single Responsibility Principle (SRP) states that every part of the program (class, function, variable) should only have one responsibility. In this context a responsibility is defined as a reason to change, so the principle can be simplified to: every part of the program should only have one reason to change.

When a part of the software is only focused on a single responsibility, it makes the program much more adaptable to changing requirements. Say you have a program that creates and prints a report of names to the console that works perfectly in its current state. Here is a very simple example of the program:

def report_names
    names = [Jake, Jim, Jill, Bob]
    print names
end

This simplistic program does exactly what you think it would do, but what if one day you wanted to format the names as JSON or HTML? If you were to keep the same structure of the program, you would need to create a reportnamesJSON or a similar method for HTML. This would cause extra work because you would be duplicating the code that gathers the names each time. This is a violation of the SRP because the function does more than one thing, and it has more than one reason to change. These reasons are that it is collecting the names, and printing the names as well. A solution that would work better in this case would look something like this:

class NameGatherer
    def report_names
        names = [Jake, Jim, Jill, Bob]
    end
end

class Printer
    def to_console(names)
        print names
    end
    
    def to_json(names)
        #convert to JSON names
    end
end

This program splits the responsibilities between two classes, and it no longer violates the SRP. The purpose of the SRP is to make the program easier to update when requirements change, and to prevent code from breaking other functionaility of the program.