Latest from the Rocketship

We like writing about our personal experiences, our challenges and our take on programming and management. Enjoy!

LongreadsJuly 11, 2019by Natalie Kaminski

Managing a Remote Development Team

I have been managing development projects for over fifteen years, ten of which I have spent managing remote teams. Throughout these years, I have experienced many successes, but I have also had some failures which I have always tried to use as lessons to improve my management style. I would like to share some of these lessons as tips for successful management of remote development teams.
Read more
LongreadsJuly 08, 2019by Natalie Kaminski

Benefits of Custom Software

Building a custom software comes with a price tag, but the investment is often worthy. Here are the top ten reasons why.
Read more
LongreadsJuly 04, 2019by Igor Alexandrov

Deploy AnyCable with Capistrano and systemd

First of all, if you still don't know what is AnyCable than probably you never tried websockets in Rails. "WTF???" you probably will say, and you are right. Yes, we have ActionCable since Rails 5.x, but you really believe Ruby is suitable for real time web? I have bad news for you.
Read more
TILApril 22, 2019by Dmitry Sokolov

Integrate Drawer inside Stack Navigation in React Native

I wanted to use more than one navigation in a React Native app.

The documentation didn’t give a clear way to implement this.

Here is what you can do on purpose to add several types of navigation in your React Native app:




import { createStackNavigator, createDrawerNavigator } from 'react-navigation';

import * as Screens from './screens/index';

import Drawer from './components/DrawerMenu';

import getDrawerWidth from './utils/scale';



const AppStackNavigator = createStackNavigator({

  home: {

    screen: Screens.MainScreen,

  },

  about: {

    screen: Screens.AboutScreen,

  },

});



const AppNavigator = createDrawerNavigator(

  {

    home: {

       screen: AppStackNavigator,

    },

  },

  {

    contentComponent: Drawer,

    drawerWidth: getDrawerWidth,

    headerMode: 'none',

  }

);



export default AppNavigator;



LongreadsJune 28, 2019by Natalie Kaminski

What is MVP and why it is crucial to product success.

What does MVP stand for? What are the benefits of developing an MVP? How do I go about it? - these are just few questions that we get asked often by prospective clients. We have decided to write an article that answers these questions and offers a few tips on how to go about developing a successful MVP.
Read more
TILMay 15, 2019by Alexander Spitsyn

Handling IP addresses using PostgreSQL

PostgreSQL provides a inet and cidr datatypes for storing net addresses and proceed operations with them.

Host address and it's subnet can be stored with inet, while cidr can contain only network address:


select inet '192.168.0.1/24';

      inet

----------------

 192.168.0.1/24


select cidr '192.168.0.0/24'; -- valid cidr

      cidr

----------------

 192.168.0.0/24


select cidr '192.168.0.1/24'; -- invalid: cidr must not be a host address

ERROR:  invalid cidr value: "192.168.0.1/24"

LINE 1: select cidr '192.168.0.1/24';

                    ^

DETAIL:  Value has bits set to right of mask.

In case there's no number after slash in cidr address the netmask is to equal 32:


select cidr('127.0.0.1');

     cidr

--------------

 127.0.0.1/32

The value above represents a subnet address, while the same value passed to inet represents a host:


select inet('127.0.0.1');

   inet

-----------

 127.0.0.1

Checking inclusion or equality can be performed with >>= and <<= operators:


select inet '192.168.0.1/24' >>= inet '192.168.0.0'; -- returns true

select cidr '192.168.0.0/24' >>= inet '192.168.0.0/12'; -- returns false

select cidr '192.168.0.0' >>= cidr '192.168.0.0'; -- returns true

And getting a netmask by a net address can be performed with netmask:


select netmask(inet('192.168.0.0/24')); -- returns 255.255.255.0

select netmask(cidr('127.0.0.1')); -- returns 255.255.255.255

TILMay 14, 2019by Dmitry Sokolov

JS: Parsing URL

So far, I have used the indexOf operator or regular expressions to get query string values. Today I learned how to make it easier using the URLSearchParams API:




// Assuming "?post=1234&action=edit"



let urlParams = new URLSearchParams(window.location.search);



console.log(urlParams.has('post')); // true

console.log(urlParams.get('action')); // "edit"

console.log(urlParams.getAll('action')); // ["edit"]

console.log(urlParams.toString()); // "?post=1234&action=edit"

console.log(urlParams.append('active', '1')); // "?post=1234&action=edit&active=1"



Important: Does not work in IE

TILMay 01, 2019by Suhomozgy Andrey

Typeahead async requests throttling

As everybody else have some legacy code (who does not have it?), and yesterday we faced with problem.

Our internal app have search panel where users could write and get related results. But search was written with typeahead and without any throttling. So it's triggered full text search on backend side on every input change which leads to DB connection pool exhaustion.

We didn't found any ready to use solutions, so we added following fix:


$input.typeahead(

  {

    ...

  },

  {

        ...

    async: true

    source: (query, syncResults, asyncResults) ->

      href = self.href

      # Added getAsyncResults call to throttle requests:

      getAsyncResults(

        () ->

          $.ajax(

            url: href

            data:

              query: query

            dataType: 'json'

          ).success(

            (data, textStatus, jqXHR) ->

              asyncResults(data)

          )

      )

  })

where getAsyncResults defined before typeahead init:


# throttle is lodash function

getAsyncResults = _.throttle(((fn) ->

    fn()

  ), 300,

  { ... })

Would be happy if someone find this simple solution helpfull.

TILApril 23, 2019by Suhomozgy Andrey

Trick: filter falsy values out of an array?

Lets say you need to filter all falsy


0, undefined, null, false, ''(empty string), NaN

values from array.

Of course you can use following construnction:




myArray

    .map(item => {

        // ...

    })

    // Get rid of falsy values

    .filter(item => item);





Since the values we don't want aren't truthy, the filter above removes those falsy items.

Did you know there's a clearer way with Boolean?




myArray

    .map(item => {

        // ...

    })

    // Get rid of falsy values

    .filter(Boolean);





TILApril 17, 2019by Suhomozgy Andrey

Add conditional properties in JS objects

How conditionaly add properties to object?

As it turned out, it's pretty simple:




const user = { id: 1, name: 'Suhomozgy Andrey' }

const position = 'Frontend Developer'

const userWithPosition = {

  ...user,

  id: 2,

  ...(position && { position })

}



userWithPosition //=> { id: 2, name: 'Suhomozgy Andrey', position: 'Frontend Developer' }





TILMarch 28, 2019by Dmitry Voronov

Create factory with an uploaded file in Rails rspec

To create a factory with an uploaded file in Rails rspec, needs to be included ActionDispatch::TestProcess module in the rails_helper.rb file to use the #fixture_file_upload method in the factories.


# spec/rails_helper.rb

include ActionDispatch::TestProcess

In a factory, when setting the attribute value, use the method #fixture_file_upload, specifying the path and file type.


# spec/factories/import_file.rb

FactoryBot.define do

  factory :import_file, class: ImportFile do

    data { fixture_file_upload 'spec/fixtures/test_file.pdf', 'application/pdf' }

  end

end

TILMarch 20, 2019by Suhomozgy Andrey

Get most performant function

Let's say you need to determine which function is execute faster.

Write a function that take array of functions and iterates each of them a certain number of times.

Will use the difference in performance.now() values before and after to get the total time in milliseconds each iteration running.

Play with iterations argument to get more or less reliable results.


const mostPerformantFunction = (fns, iterations = 10000) => {

  const times = fns.map(fn => {

    const before = performance.now();

    for (let i = 0; i < iterations; i++) fn();

    return performance.now() - before;

  });

  console.log(times);

  return times.indexOf(Math.min(...times));

};


mostPerformantFunction([

  () => {

    [1, 2, 3, 4, 5, 6, 7, 8, 9, '10'].every(el => typeof el === 'number');

  },

  () => {

    [1, '2', 3, 4, 5, 6, 7, 8, 9, 10].every(el => typeof el === 'number');

  }

]); // 1

TILMarch 20, 2019by Alexander Blinov

How to download files with Axios

A simple example using the Blob() constructor:


export function someFunction(values) {

  return (dispatch) => {

    ...

    const method = 'GET';

    const url = 'http://go.api/download_file';

    ...

    axios

      .request({

        url,

        method,

        responseType: 'blob', //important

      })

      .then(({ data }) => {

        const downloadUrl = window.URL.createObjectURL(new Blob([data]));

        const link = document.createElement('a');

        link.href = downloadUrl;

        link.setAttribute('download', 'file.zip'); //any other extension

        document.body.appendChild(link);

        link.click();

        link.remove();

      });

  };

}

TILMarch 05, 2019by Alexander Spitsyn

How to conditionally render template in Grape resources?

Suppose you need to conditionally render some template in a given endpoint of a Grape resource. There is a env data in Grape::API class that represents Rack environment of the request. env is just a simple Ruby hash and we can pass the template name to it's api.tilt.template key to render that template:


env['api.tilt.template'] = 'foo/bar.json'

Then let's define a render method in Base resourсe:


class Base < Grape::API

  def self.inherited(subclass)

    super



    subclass.instance_eval do

      helpers do

        def render(template_name)

          env['api.tilt.template'] = template_name

        end

      end

    end

  end

end

Now we can use it in the following way:


class ContactsResource < Base

  desc 'Create contact', http_codes: [[201, 'Created']]



  post '/contacts' do

    contact = Contact.new(params[:contact])



    if contact.save

      render 'v1/contacts/show.json'

    else

      error!({ errors: contact.errors.full_messages }, 422)

    end

  end

end

TILMarch 05, 2019by Alexander Spitsyn

Append string to a route with a slash operator

If you need to append string to some route to build a path name you can use few ways:


Rails.root + 'foo/bar'

[Rails.root, 'foo/bar'].join('/')

"#{Rails.root}/foo/bar"

But also there is a Pathname#/ method, so you can append string to route using a slash:


Rails.root/'foo/bar' # => #<Pathname:/Users/alex/myproject/foo/bar>

Looks more readable!

TILFebruary 25, 2019by Arina Shmeleva

How to add a line break to PostgreSQL?

You have to insert some data into your PostgreSQL table that has line break. As a result, the cell will look like this:


First line

Second line

To use "escape sequences" in a string literal you need to use an "extended" constant. You can specify the escape character by prefixing the letter E:


UPDATE posts SET body = E'First Line\nSecond line.' WHERE id = 2701;

TILFebruary 23, 2019by Alexander Ivlev

Recompose withContext and getContext. Simple example

Very often for nested components you need to transfer some props of the parent. For example size. So, we have the Card component. It contains a Button component.


  // App.js

  <Card size="sm">

    {/* ... */}

    <div>

      {/* ... */}

      <Button size="sm" onClick={action}>Action</Button>

    </div>

  </Card>



The size for both components is set by the "size" parameter. In the example above, the parameter passed is indicated for both components. In order not to specify the size for the Button each time, you can use the Context to use the one specified for the Card. If you use recompose, it can be super easy:


  // Card.js

  import { getContext } from 'recompose';

  // ...

  export default withContext(

    { size: PropTypes.oneOf(['sm', 'md', 'lg']) },

    ({ size }) => ({ size }),

  )(Card);



  // App.js

  import Button from './Button';

  // ...

  const EnhancedButton = getContext({ size: PropTypes.oneOf(['sm', 'md', 'lg']) })(Button);

Live example

TILFebruary 20, 2019by Alexander Budchanov

AND & OR Operators Precedence

Are you still sure that && and and is the same operators? Look at this:


a = true && false

a

=> false


a = true and false

a

=> true

The same situation could be reproduced for || and or. Why? The answer lies in Ruby Operator Precedence.

The first example can be represented as:


a = (true && false)

Second:


(a = true) and false

Thanks to Igor Alexandrov

TILFebruary 20, 2019by Alexander Ivlev

Sort lines in the vim editor

Often when writing code, you need to sort the lines in alphabetical order. For example, in javascript, when importing a large number of modules, it is good practice to organize them alphabetically. Users of the vim editor can do this very simply. It is enough to select in the visual mode all the lines that need to be sorted and enter the command :sort. All rows are sorted!

TILFebruary 20, 2019by Alexander Blinov

Custom onChange in React Final Form

Let's take a case when we need to call our own function to change a state of a specific field in a form (our react final form).

Here is a way to do the exact that:

You should pass your function as a parameter and after that just call it inside of the onChange method

Example:


const FormGroupAdapter = ({ input, inputOnChange }) => {

    const inputProps = {

        ...input,

        onChange: e => {

            input.onChange(e);

            inputOnChange && inputOnChange(e);

        }

    };



    return <input {...inputProps} />;

};



const handleChange = event => {

    console.log("!!!", event.target.value);

};



const App = () => (

    <Form

        ...

        render={({ handleSubmit, reset, submitting, pristine, values }) => (

            <form onSubmit={handleSubmit}>

                <div>

                    <label>some label</label>

                    <Field

                        name="someField"

                        component={FormGroupAdapter}

                        inputOnChange={handleChange}

                    />

                </div>

                ...

            </form>

        )}

    />

);



Live example