 
					 
						
				 
				Reduce code size by ~27% (99 -> 72 LOC)
Object.assign calls from 8 down to 2
Smell #1: Call another reducer with a new action
const movies = (state = {}, action) => {
  switch(action.type) {
    case 'ADD_MOVIES_VIA_OBJECTS':
      return Object.assign({}, state, action.movies.
        reduce((movies, movieObject) => (
            Object.assign(movies,
            movie(undefined, Actions.addMovie(movieObject)))
          ), {}));
  }
};
            Smell #2: Fat reducer + Object.assign everywhere
const movieCollection = (state = {
	isLoading: false, sort: 'title', movies: {}
}, action) => {
  switch(action.type) {
    case ADD_MOVIECOLLECTION_WITH_MOVIES_LINE_BY_LINE:
      return Object.assign({}, state, {
        name: action.movieCollection.name,
        movies: movies(undefined, {
          type: 'ADD_MOVIES_LINE-BY-LINE',
          movies: action.movieCollection.movies
        })
      });
    case ADD_MOVIECOLLECTION_BY_FILE_START:
      return Object.assign({}, state, {
        name: action.movieCollection.name,
        isLoading: true
      });
  }
};
            This reducer alone 35 LOC!
(two more case statements)
Fix #1: Use reducer for every single attribute
const movieCollection = combineReducers({
  isLoading,
  sort,
  movies,
  name
});
			Fix #1: No need for Object Assign. (before)
case ADD_MOVIECOLLECTION_BY_FILE_START:
  return Object.assign({}, state, {
    name: action.movieCollection.name,
    isLoading: true
  });
			Fix #1: No need for Object Assign. (after)
case ADD_MOVIECOLLECTION_BY_FILE_START: 
  return action.movieCollection.name;
			Fix #1: Makes it perfectly clear if attributes are not used, yet.
const sort = (state = 'title', action) => {
  return state;
}
			Fix #1: Makes it perfectly clear if attributes are not used, yet. (short)
const sort = (state = 'title', action) => state;
			Fix #2: Create reducer from map
export default function createReducer(initialState, handlers) {
  return (state = initialState, action) => {
    handlers.hasOwnProperty(action.type)
      ? handlers[action.type](state, action)
      : state;
  }
}
			Fix #2: Before
const isLoading = (state = false, action) => {
  switch(action.type) {
    case ADD_MOVIECOLLECTION_BY_FILE_START:
      return true;
    case UPDATE_MOVIECOLLECTION_BY_FILE:
      return true;
    case ADD_MOVIECOLLECTION_BY_FILE_FINISHED:
      return false;
  }
  return state;
};
			Fix #2: After
const isLoading = createReducer(INITIAL_STATE.isLoading, {
  [ADD_MOVIECOLLECTION_BY_FILE_START]:    () => true,
  [UPDATE_MOVIECOLLECTION_BY_FILE]:       () => true,
  [ADD_MOVIECOLLECTION_BY_FILE_FINISHED]: () => false
});
			 
						
				
						- Slides: christophhaefner.de/events/busconf17/ 
						- Reveal.js: Source code & documentation