On the other hand, as a consultancy, we also need to start up new projects frequently and quickly, balancing up-to-date technology with production-level expertise.
This presents us with some specific challenges:
- We constantly need to help teams get started with React or Angular, typically on short notice.
- Some of our projects have short time-frames: each team can’t afford to spend time fussing with tools.
hard for newcomers to put together coherent toolchains and architectures.
- Cross-functional teams sometimes struggle to keep up with the pace of change.
As a senior developer and architect at Rangle, I often find myself asking the same three questions:
- How do we save time on tooling at the start of each new project?
- How do we make sure we keep our best practices up-to-date?
- How do we efficiently spread this technical know-how across our scrum teams and course instructors?
A Partial Solution - Documented Best Practices
In the early days of the company, we kept a lot of this knowledge in internal documentation. These efforts attempted to provide guidance for all developers on coding, architecture, and dev ops; it was maintained by our senior 'support squad' developers with input from the experiences of our scrum teams.
This helped a lot when we were a smaller company but didn't really scale well. It's too easy to simply read a document and then forget it, and each scrum team still had to put together their toolchain each time.
We found that scrum teams were solving the same problems over and over:
- How to minify and bundle for production.
- How to access APIs on other domains (CORS and proxying).
- How to run unit tests in our continuous integration system.
- How to write and run end-to-end tests in our CI system.
- How to turn on developer tools in dev mode and
disable them in production.
And at each step of this process came the slew of ever-changing decisions:
- ES6? ES5? Flow? TypeScript?
- Webpack? SystemJS? JSPM? Gulp? Grunt?
- Flux? Redux? RxJS? BaconJS?
- Inline styles? SCSS? Less? Radium? PostCSS? CSSNext?
- ... etc.
Wouldn’t it be better to just let our coders code?
A Better Solution - Standard Tech Stacks
About 6 months ago we changed our approach. We now maintain a small number of 'Standard Rangle Tech Stacks', or 'starter projects' which we use for almost all new projects.
Each of these stacks provides a fully-functional toolchain that's ready to go; letting our developers focus on delivering business value for our clients.
Production build tools are already set up: solutions for minification, bundling and serving over HTTP work out of the box.
Quality tools are already set up: standardized linter rules enforce company code conventions; unit testing toolchains are ready to go and end-to-end (E2E) testing with Selenium (using the Robot framework) is up and running.
Attention has also been given to styling and maintainable CSS.
The starters are compatible with our internal continuous integration and deployment tools to enable true Agile delivery.
Finally, these starters are actively maintained by our senior developers as new ideas prove worthwhile, and as toolchain issues are encountered and solved by our project teams.
This approach has had many benefits.
Each new project team now starts with our latest best practice thinking. Their production and debug flows are ready to go, and teams don't waste time on solved problems at the start of the project.
We can set up a scrum team with a repo and a full continuous deployment pipeline in about 10 minutes.
In addition, the starter project's sample app shows new hires “what ‘good’ looks like”: helping support squad maintain the stacks has proven to be excellent training for new hires, and gives them a bird's-eye view of all our common tools.
The standard stacks, while tuned to our business needs, are all open source (MIT license) so the community can benefit and even contribute.
You can access the latest setups from our landing page in git-hub: https://github.com/rangle/rangle-starter.
Each stack is also set up with CI and auto-deployment, currently on Heroku.
They're all set up with our favourite state-management solution: Redux. Redux is a variant of the Flux architecture which we have found significantly reduces application complexity at scale. It also boasts some first-rate developer debugging tools.
Finally, each stack has an optional, minimal NodeJS /Express HTTP server for production deployments.
All of our stacks use webpack for production minification and bundling. We have found Webpack to handle these tasks with significantly less configuration or code-writing than other tools such as JSPM, SystemJS, or gulp.
Webpack's import/loader model also makes transpilation a breeze.
Finally, all our build scripts and our NodeJS servers run on the current long-term support (LTS) version of NodeJS.
Related to transpilation, we've taken a similar approach to CSS, courtesy of
postcss. This helps us solve a couple of persistent issues that have dogged designers and developers alike since CSS was first introduced:
- The global nature of styles
- Extremely inconsistent browser support
Global CSS in a Component-Oriented World
This leads to CSS class namespace collisions, conflicting style definitions across libraries, and huge difficulty maintaining CSS code at scale.
The React community has favoured inline CSS as a solution to this, but that suffers from a couple of issues:
- It requires your designers to learn React and/or Angular
- It requires us to handle browser incompatibilities and vendor prefixing manually.
Other projects have traditionally scoped their CSS using naming conventions such as BEM, but this requires training and discipline.
CSS implementations in even major browsers are notoriously fickle. Bugs, vendor prefixes, and conflicting specifications all conspire to make manual cross-browser support a frustrating game of whack-a-mole.
This is something that should not be handled manually, but rather with CSS transformations like autoprefixer.
Having your CSS and Eating it Too
In our case we have opted for an approach to CSS based on transpilation, which is enabled by postcss and webpack. Using various build-time transformations we can
import component-specific CSS files which are:
- Transpiled from CSS4 to CSS3 using cssnext.
- Scoped to the components to which they belong
using postcss-modules-local-by-default (or
Angular 2's built-in ViewEncapsulation).
- Vendor-prefixed and targeted to minimum browser
versions using autoprefixer.
- Minified using cssnano.
All this and your designers can write component-level CSS files just as they've always done.
Our starters come with several quality tools baked in. Code linting from eslint (ES6) or tslint (TypeScript) catches common errors at build-time.
Finally, in collaboration with our BQA group we have rolled out automated end-to-end tests using a python-based selenium wrapper called Robot. We prefer Robot for its ability to let BQAs write automated tests using a natural-language syntax:
*** Test Cases *** Valid Login Open Browser To Login Page Input Username user Input Password pass Click Login Verify user is successfully logged in Username is empty - Invalid Login Open Browser To Login Page Input Password Pass Click Login Verify Username Validation Username is required.
Our starters ship with a minimal NodeJS/Express server that's set up to handle the most common production-related mistakes; thought has been given to:
- Proxying APIs to remote servers
- Proper error handling
- Basic XSS protections via HelmetJS
- Basic request logging.
However you can also deploy statically:
npm run build will compile and output the application bundle to
/dist; put this folder behind the HTTP server of your choice or upload it to Amazon S3.
Developer experience is something we take seriously, because of its benefits for productivity. Running
npm run dev for any of our starters will enable various developer tools, including:
webpack-dev-server's live reload
webpack-dev-server's hot module replacement (React only)
- Redux DevTools (via the Chrome extension)
- Support for the latest version of
Augury (Angular 2
Generally, we'll make an effort to support the earliest browsers supported by the tech stack's frameworks.
In practice, this currently means IE9+ and the last two versions of Firefox and Chrome.
- Living best-practices guides.
- Teaching tools for newcomers.
- A quick way to set up new project teams.
- A playground for experiments.
They are all open source! Discussions, contributions, bug reports and ideas are always welcome.
- The starters on GitHub
- Our Intro to Modular CSS
- Component-Oriented Architecture in Angular 2
- Atomic Design