Week 8-10 at Command Shift

For this post, I'll be covering the final project I made at the end of our JavaScript basics module. This is a project that we've been doing for a while and I decided to cover it in this post instead of spreading it over multiple ones.
I struggled with this project a lot, which was good as it highlighted areas of weakness I have and allowed me to improve. Having the tutors and others available to ask for help along the way was fantastic.
Let's dive into the project below.

Cruise Ship

The idea behind the project was to create a cruise ship that can take an itinerary of docks and docks from one to another when called.

The project also covered everything we'd learned so far with JS, Object Orientated Programming and Test Driven Development. It also introduced us to some new concepts such as:

  • Domain Modelling

  • Do Not Repeat Yourself(DRY)

  • Dependency Inversion

I'll be honest, I am still unsure about a lot of these concepts. They were a lot to wrap my head around and I had to use the walkthrough guide for a lot of this project. I also had to come to terms with the fact that it's fine to use the guides when I am stuck. The tutors have discussed problem-solving and have said never to spend too long on something on your own. Reach out after you've tried to solve it, and I did this with the walkthroughs for this project.

Domain Modelling

Domain Modelling is a concept that helped me to understand how projects start. We take a User Story, which is how someone would approach you and say, 'I would like X to do Y and to look like Z' As a developer it is down to us to pick apart the story and start to build something from it.

We start with 3 areas: Object, Method and Properties.
To show how this is written out, here's the example we were given.

As a cruise ship captain,
So I can get passengers aboard a ship,
I want a ship to have a starting port.

Our Object here is Ship and our Properties are Port. Our Method will be SetSail further down the line. The Domain model will be constantly updated throughout a project's lifecycle. This is because new features may be requested by the user.
So in summary, Domain Modelling is about being able to pick apart the Users Story and transform that into code you will use to design the project.

Figuring out how to start building projects is something I find difficult and learning about Domain Modelling gave me a way to break it down that can help me not to feel too overwhelmed by it all.

Progressing with TDD

A lot of the coding I am doing is refactoring and writing out new Tests for my projects. It's been frustrating but good to build up that muscle memory by typing everything out again and again. One concept we covered was DRY and we implemented this within our testing. Do Not Repeat Yourself(DRY) is about tidying up your code to make it more readable. The way we have implemented this in our tests is by taking the Set Up portion and reducing it. Let's see what that looks like:

it('has a starting port', () => {
  const amsterdam = new Port('Amsterdam'); //setup
  const itinerary = new Itinerary([dover]); //setup
  const ship = new Ship(itinerary); //setup

  expect(ship.currentPort).toBe(dover);
});

In each test, we would rewrite these variables again and again which isn't very DRY. In our describe block for our test, we would make another describe block nested within it. The reason for this is that we don't want the changes we will make to affect other tests. Let's look at it below:

describe('Ship', () => {
  describe('with ports and an itinerary', () => {
  });

  ...
});

Now what we would do is move all of our testing specs within the new describe block. Let's include our set-up variables in our code to dry everything up.

describe('with ports and an itinerary', () => {
  let ship;
  let amsterdam;
  let dover;
  let itinerary;

  beforeEach(() => {
    dover = new Port('Dover');
    calais = new Port('Calais');
    itinerary = new Itinerary([dover, calais]);
    ship = new Ship(itinerary);
  });

  ...
});

The variables at the top can now be accessed for each of the tests so that they can all still pass. The beforeEach() allows our variables to be declared before running the tests themselves.
Now when we create our unit tests, we can create them with the exercise and verify phases without having to constantly type out the set-up phases. We can see below a before and after of the code base once we have Dried up the code:

Before:

describe('with ports and an itinerary', () => {
  it('can be instantiated', () => {
    const port = new Port('Dover');
    const itinerary = new Itinerary([port]);
    const ship = new Ship(itinerary);

    expect(ship).toBeInstanceOf(Object);
  });

  it('has a starting port', () => {
    const dover = new Port('Dover');
    const itinerary = new Itinerary([dover]);
    const ship = new Ship(itinerary);

    expect(ship.currentPort).toBe(dover);
  });

  it('can set sail', () => {
    const dover = new Port('Dover');
    const calais = new Port('Calais');
    const itinerary = new Itinerary([dover, calais]);
    const ship = new Ship(itinerary);

    ship.setSail();

    expect(ship.currentPort).toBeFalsy();
    expect(dover.ships).not.toContain(ship);
  });

  it('gets added to port on instantiation', () => {
    const dover = new Port('Dover');
    const itinerary = new Itinerary([dover]);
    const ship = new Ship(itinerary);

    expect(dover.ships).toContain(ship);
  });
});

After:

describe('with ports and an itinerary', () => {

  let ship;
  let amsterdam;
  let dover;
  let itinerary;

  beforeEach(() => {
    dover = new Port('Dover');
    calais = new Port('Calais');
    itinerary = new Itinerary([dover, calais]);
    ship = new Ship(itinerary);
  });

  it('can be instantiated', () => {

    expect(ship).toBeInstanceOf(Object);
  });

  it('has a starting port', () => {

    expect(ship.currentPort).toBe(amsterdam);
  });

  it('can set sail', () => {

    ship.setSail();

    expect(ship.currentPort).toBeFalsy();
    expect(dover.ships).not.toContain(ship);
  });

  it('gets added to port on instantiation', () => {

    expect(dover.ships).toContain(ship);
  });
});

And that is Drying up the code!

Wrapping up

I covered a bit here about our cruise ship project and what we have touched on throughout the course. I didn't want to go too deep into it as this would've led it to being a really long piece, but i covered two topics that I thought helped me the most.

Am I an expert at JS and all the inner workings of TDD and OOP? Absolutely not, but I am a lot more confident with the basics of it all.
We have a week off of lectures and then we move on to the back-end module which I am looking forward to a lot as I have never covered anything from it.
I will be starting the leg of this course this week as I am on holiday the following week.
Thank you for reading!