Wednesday, 14 June 2017

An introduction to Refactoring Java in IntelliJ using RestMud as an Example

TL;DR Never too late to refactor. Do it in small chunks. Protected by tests. Using IDE to refactor.

My RestMud game grew organically, I do have a fair bit of Unit testing, but I also perform more integration testing than unit testing.

The good thing about this approach is that the integration testing represents requirements i.e. in this game I should be able to do X, and my integration tests at a game engine level create test games and check conditions in there.

These tests rarely have to change when I amend my code.

The side-effect of this type of testing is that the classes don’t have to be particularly good, so I have a lot of large classes and not particularly good organisation.

I’m now refactoring the classes and organising the code to have 4 main sections:

  • Game Engine
  • Games
  • API
  • GUI

At the moment I’m concentrating on the Game Engine.

I have a large main class called MudGame and I’m splitting that into smaller classes now.

Refactoring from Map to POJO

As an example my MudGame used to have a Map for locations, and collectables and messages.

This meant that I had 4 or 5 methods for each of these collections in my MudGame, I have now only a few high level methods in Game and most of the code has moved to the Locations, or Collections object.

As I was doing this I had to make a decision, do I make a public final field, or do I create a private field, with an accessor method.

I initially chose public final and amended the code, and then changed my mind to have an accessor method.

I don’t worry too much about this because it is easy to use IntelliJ refactoring to rename and wrap fields in accessor methods.

private Map<String, MudLocation> locations = new HashMap<>();

To an object that manages locations, which contains all the code methods that were on MudGame

public final Locations gameLocations = new Locations();

I chose to make the field public initially, then I refactored using “Encapsulate as Method”:

private final Locations gameLocations = new Locations();


    public Locations getGameLocations() {
        return gameLocations;

Refactoring Methods to Inline Code

Sometimes when I have a method that is small and doesn’t really add any value because I delegate all the functionality off to another Object, I might choose to inline it:

    public MudLocationObject getLocationObject(String nounPhrase) {
        return getLocationObjects().get(nounPhrase);

When I inline this then anywhere in the code that had:

MudLocationObject locationObject = game.getLocationObject(thingId);


MudLocationObject locationObject = game.getLocationObjects().get(thingId);

Some Tips for Refactoring

  • requirement level tests should not have to change during refactoring
  • make sure you have tests before you refactor
  • don’t worry too much about naming or field/method choices during initial coding because it is easy to refactor later
  • use IDE refactoring where possible
  • when code gets ugly, get refactoring
  • refactor in small chunks, keep chipping away,
  • refactor low hanging fruit first as it makes it easy to see what comes next
  • group code together to loosely organise prior to refactoring into new classes
  • Refactor Classes to represent semantics as well as helping organising code

It’s never too late to refactor your code.

Bonus Youtube Video

See also the accompanying YouTube Video:

In the video you’ll see:

An introduction to Refactoring Java in IntelliJ with a live demo using RestMud Game. I talk you through what refactoring is, and show examples of in built refactoring functionality in IntelliJ.

  • An introduction to refactoring
  • Basic Refactoring techniques and approaches explained
  • Refactoring from fields to methods with “Encapsulate Field”
  • Run tests after each refactoring
  • Check in code to version control frequently to allow reverting if things go wrong
  • Demonstration of refactoring
  • Explanation of intermittent Unit Test Execution
  • Sometimes as we refactor we discover we are creating duplicate code. When that happens, stop and decide if the existing code is good enough.
    -Try to avoid creating code that you aren’t using yet. You have to maintain it, and there are no tests,
    a nd you probably won’t use it in the future anyway!
  • Refactoring to Inline methods to remove methods completely. Remove the method and replace invocations
    with the code in the method
  • Reflect on your refactoring. Time to stop? Good enough to checkin? More to do?

Thursday, 13 April 2017

JSoup Tip How to get raw element text with newlines in Java - Parsing HTML and XML with JSoup

TL;DR with JSoup either switch off document pretty printing or use textNodes to pull the raw text from an element.

A quick tip for JSoup.

I wanted to pull out the raw text from an HTML element and retain the \n newline characters. But HTML doesn’t care about those so JSOUP normally parses them away.

I found two ways to access them.
  • switching off pretty printing
  • using the textNodes

Switching off Pretty Printing

When you parse a document in JSoup you can switch off the prettyPrint

Document doc = Jsoup.parse(filename, "UTF-8", "");

Then when you access the html or other text in an element you can find all the \n characters in the text.

String textA = element.html();

Use the textNodes

This approach works regardless of whether you have prettyPrint on or off:

String text = "";
for(TextNode node : element.textNodes()){
    text = text + node + "\n\n";

If you accidentally use both methods then you might get confused.

I think I prefer the second approach because it works regardless.

You can find code that illustrates this on github in the file

See also the accompanying YouTube Video:

Friday, 17 March 2017

Mistakes using Java main and examples of coding without main

TL;DR A potentially contentious post where I describe how I've survived without writing a lot of Java main methods, and how learning from code that is often driven by a main method has not helped some people. I do not argue for not learning how to write main methods. I do not argue against main methods. I argue for learning them later, after you know how to code Java. I argue for learning how to use test runners and built in features of maven or other build tools to execute your @Test code.