Website Links

Thursday 4 July 2019

The MVP - It isn't always what you think!

There is always something you feel you can't go live without… You develop that feature, and then you think "Well this would be really beneficial to my product too"… So how do you know when to go live? Well I am going to share with you a scenario I encountered recently when trying to determine a launch date for our product and what the MVP would look like.

Firstly, I'll describe our product fairly briefly… It is a product that connects job seekers with potential employers. When thinking about how to market our product we had to start thinking about what would attract job seekers and what would attract employers. We decided it was rather cyclical, which employers would bother to come to use our product if we didn't have an existing user base of talent? Similarly, if there are no employers to connect with why would any talent use our application?

However, we also had a tool within the product that job seekers would use… This tool was not intended to be used independently of the rest of the product. However, with some tweaks it could become a standalone application that we could use to attract talent and form a user base which we could then roll out further features and updates to.

So we refocused… We channeled our energy into perfecting that small portion of our app. That way we could start marketing and growing a user base whilst we still developed the main product in the background. We went from a feature that was barely part of our MVP to a feature that was our MVP. We did this all by thinking about how we could grow our user base and which users would be easier to attract.

When you are defining your MVP think about what it will take to get people using your product. You can then roll out additional features down the line, but you already have the recognition so it gets a bit easier. Your marketing team can start working their magic sooner, and you will learn a bit more about what the users want and what they don't want. This means it can be easier to pivot early, which can save a lot of valuable development time.

Tuesday 23 April 2019

React - Testing with Jest

This post is just a basic of how to setup for Jest testing with React. There will be more posts in the future to cover different assertion types, how to integrate Jest tests into your CI pipeline and how to use Enzyme for rendering components. By default Jest is included in React, and it will pick up tests in either the __tests__ directory or with a filename ending in .test.js. There are different advantages to each of these. I personally feel like __tests__ is better for larger projects, but this may be down to my C# background where you'll commonly have a separate project for tests. As I tend to be of the opinion that you can always grow a program overtime I tend to favour this in all cases. However, the advantage of appending .test.js to the end of your filename is that your file can reside in the same directory as the source code you're testing, which means that import statements tend to be a bit less complicated. Whatever your decision, it's supported and Jest will pick up your test cases.

By default, your React app likely has an App.test.js file which I moved and renamed to __tests__/App.js. Now I was pretty bad and didn't write any test cases for a while, and went on developing without running this test... So, when I finally ran Jest tests using the command
npm test
I found my test was failing! The first cause of failure was that when I rendered my App on index.js I had actually surrounded it in a <BrowserRouter> tag, which meant that when <App> was rendered on its own, it was missing the <BrowserRouter> surrounding the <Switch> and <Route>s. So this test actually allowed me to refactor my code into a more readable and sensible structure... And that was just the basic included test!

But my test was still failing! The error was:
TypeError: window.matchMedia is not a function
The cause of this is that Jest uses JSDom to create a browser environment, which doesn't support window.matchMedia, and I was using this in my code. After some googling, it turns out that it could be mocked out. So I created a __mocks__/matchMedia.js file with the following contents:

  window.matchMedia = jest.fn().mockImplementation(query => {
    return {
      matches: false,
      media: query,
      onchange: null,
      addListener: jest.fn(),
      removeListener: jest.fn(),
    };
  });

In my __tests__/App.js file I imported this mock and low and behold a different error! This error was about having a store, I used the "redux-mock-store" npm package to mock out my redux store and wrapping my <App> in a <Provider>, and my __tests__/App.js file ended up looking like this:

  import React from 'react';
  import ReactDOM from 'react-dom';
  import '../__mocks__/matchMedia';
  import { Provider } from 'react-redux';
  import configureMockStore from 'redux-mock-store';
  import App from '../App';

  const mockStore = configureMockStore();
  const store = mockStore({});

  describe('App', () => {
    it('renders without crashing', () => {
      const div = document.createElement('div');
      ReactDOM.render((
        <Provider store={store}>
          <App />
        </Provider>
      ), div);
    });
  });

And guess what... It PASSED!

Friday 12 April 2019

React/React Native - Higher Order Components

Higher order components is probably one of my favourite patterns that I have come across for React/React Native. It is when you pass a component to a function and it returns the component with additional functionality. This is very useful for code reuse. You may have seen this used before with the connect function provided by redux. I typically use this for auto login if a user were to navigate to a login/register page e.g.

  import React, { Component } from 'react'
  import { connect } from 'react-redux'
  import { setCurrentUser } from '../actions/index'
  import { bindActionCreators } from 'redux'

  export const withAutoLogin = (Scene) => {
    // New component that wraps our existing component and adds
    // additional functionality
    class WithAutoLogin extends Component {

      constructor(props) {
        super(props);

        // If there is a current user, navigate to home page
        if (this.props.currentUser) {
          ...  
        }
      }

      render() {
        return (
          // apply props to component
          <Scene {...this.props} />
        );
      }
    }

    // Connecting to redux
    function mapStateToProps(state) {
      return {
        currentUser: state.currentUser
      }
    }

    function mapDispatchToProps(dispatch) {
      return bindActionCreators({
        setCurrentUser: setCurrentUser
      }, dispatch);
    }

    return connect(mapStateToProps, 
                   mapDispatchToProps)(WithAutoLogin);
  }

Google Cloud Build - Automating Function Deployment

The following is how to setup a basic google cloud function deployment using google cloud build.
  1. Go to Google Cloud Build (https://console.cloud.google.com/cloud-build/triggers)
  2. Add trigger
  3. Select your source
  4. Authenticate with your source
  5. Adjust your trigger settings
  6. Under Build Configuration, select cloudbuild.yaml
  7. Add substitution variable "_NAME" and provide the name of the function you want to deploy
  8. Add a cloudbuild.yaml to your repository e.g.
    steps:
    - name: 'gcr.io/cloud-builders/gcloud'
      args: ['beta', 'functions', 'deploy', '${_NAME}', 
             '--trigger-http']
    
Note: at some point you should add additional steps for unit tests to ensure that if any unexpected behaviour occurs your build will fail and your function will not be deployed

If you have any permission issues you might need to go to Project Settings > IAM and make sure a member exists with the following roles:
  • Cloud Build Service Account
  • Cloud Build Editor
  • Cloud Functions Developer