+ +**Update (Jan 2019):** io.js has already been merged into Node.js since v4, and is now considered deprecated. Consider using nodejs instead. + ++ + + +### Homebrew formula + + + +An updated [homebrew-iojs] formula is maintained by [@aredridel] and is available with just one command. + +```bash +brew install aredridel/iojs/iojs +``` + +### Default formula + + + +As of iojs 2.0.2, Homebrew ships with its own formula for iojs. This isn't preferrable, in my opinion, since global npm packages aren't being ran properly. + +```bash +brew install iojs +brew unlink node +brew link iojs --force +``` + +If you'd like to use this anyway, simply doing `brew install iojs` is not enough. To get iojs working on [Homebrew] You will need to unlink `node` first then use `link --force` to install iojs. + +[homebrew-iojs]: https://github.com/aredridel/homebrew-iojs/blob/master/Formula/iojs.rb +[@aredridel]: https://github.com/aredridel +[homebrew]: http://brew.sh/ diff --git a/posts/2015/iojs-on-homebrew/iojs-linking.png b/posts/2015/iojs-on-homebrew/iojs-linking.png new file mode 100644 index 00000000..6c54f5c3 Binary files /dev/null and b/posts/2015/iojs-on-homebrew/iojs-linking.png differ diff --git a/posts/2015/javascript-orms-suck.md.disabled b/posts/2015/javascript-orms-suck.md.disabled new file mode 100644 index 00000000..b69bdfc6 --- /dev/null +++ b/posts/2015/javascript-orms-suck.md.disabled @@ -0,0 +1,43 @@ +--- +date: '2015-02-15' +title: JavaScript ORM's suck +tags: [JavaScript] +description: Database ORM's and JavaScript aren't a good mix. Here's why. +layout: simple +--- + +
+ +**Update (Dec 2019):** Node.js now supports [top-level await](https://v8.dev/features/top-level-await) which would solve the pain point outlined in this article. This article was written in 2015 with Node.js v0.12 in mind. + ++ +Consider this scenario: there's a strange bug in production's data that you need to inspect. In Rails, you can tell `rails console`: "show me all project IDs that are active and made by users that never logged in" like so: + +```ruby +pry(main)> User.where(last_signed_in: null) + .map { |u| u.projects.active } + .flatten + .pluck :id +``` + +This may not be the most efficient way to do it, but some situations are urgent and will call for one-offs like these. + +In Node.js, you'll probably do something like this: + +```js +> User.where({ last_signed_in: null }) + .fetch().then(function (users) { + return Promise.all(users.map(function(u){ + return u.projects.active.fetch(); + })) + }) + .then(function(projects) { + return projects.map(function(p) { + return p.id; + }); + }) + .then(console.log) +``` + +Ah, granted that promises and ES6 (fat arrows) would make this better, but still... diff --git a/posts/2015/javascript-shortcuts.md.disabled b/posts/2015/javascript-shortcuts.md.disabled new file mode 100644 index 00000000..480eaff7 --- /dev/null +++ b/posts/2015/javascript-shortcuts.md.disabled @@ -0,0 +1,29 @@ +--- +date: '2015-03-20' +title: JavaScript shortcuts using bitwise operators +description: Learn some shorter ways to write some common JavaScript expressions. +tags: [JavaScript] +layout: simple +--- + +Some common operations can be made shorter using bitwise operators. Here are some of my favorites. + +### Rounding off a number + +`Math.floor(3.5)` can be written as `3.5|0`. The [Bitwise OR](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_OR) operator will make an integer out of the number, and this construct is in fact used in [asm.js](http://asmjs.org/spec/latest/) to denote an integer. + +```js +list[list.length * Math.random() | 0] +// ...same as: +list[Math.floor(list.length * Math.random()] +``` + +### Checking for -1 + +The [Bitwise NOT](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT) operator will turn `-1` into zero. This makes substring checks with `indexOf()` a little shorter. + +```js +if (~string.indexOf("John")) { ... } +// ...same as: +if (string.indexOf("John") !== -1) { ... } +``` diff --git a/posts/2015/local-google-fonts.md.disabled b/posts/2015/local-google-fonts.md.disabled new file mode 100644 index 00000000..14adbde0 --- /dev/null +++ b/posts/2015/local-google-fonts.md.disabled @@ -0,0 +1,27 @@ +--- +date: '2015-05-18' +title: The best way to get Google Fonts offline +tags: [Misc] +layout: simple +attachments: + - local-google-fonts/skyfonts.png +description: Chances are you've downloaded a few Google fonts to your computer. Here's a better way to do it. +--- + + + +If you're doing any work creating UI mockups, chances are you've downloaded a few [Google fonts] to your computer. Doing this manually is tedious, and you wouldn't be up to date when the fonts get updated. + +[SkyFonts] is a free font syncing service that puts webfonts into your computer. It works with paid services like [fonts.com], but also offers unlimited support for Google Fonts. + +This by far is the most convenient way to get Google Fonts onto your computer. Adding new fonts is mostly a one-click affair, fonts updates are automatically pushed to your computer, and you can even conveniently install the top 50 Google Fonts. + +Monotype Skyfonts is available via [Caskroom] as `monotype-skyfonts`. + +[caskroom]: http://caskroom.io/ +[caskroom-fonts]: https://github.com/caskroom/homebrew-fonts +[google fonts]: http://www.google.com/fonts +[skyfonts]: https://skyfonts.com/ +[fonts.com]: http://www.fonts.com/ diff --git a/posts/2015/local-google-fonts/skyfonts.png b/posts/2015/local-google-fonts/skyfonts.png new file mode 100644 index 00000000..cd94d0ee Binary files /dev/null and b/posts/2015/local-google-fonts/skyfonts.png differ diff --git a/posts/2015/markdown-in-jekyll.md.disabled b/posts/2015/markdown-in-jekyll.md.disabled new file mode 100644 index 00000000..e47ff7fe --- /dev/null +++ b/posts/2015/markdown-in-jekyll.md.disabled @@ -0,0 +1,47 @@ +--- +date: '2015-05-25' +title: Markdown in Jekyll +description: Insert Markdown into any Jekyll document with this simple tag. +layout: simple +tags: [Development, Jekyll] +--- + +To add Markdown to any HTML file in Jekyll, capture it into a variable and print that variable using _markdownify_. That is: + +``` +{% capture x %} +## This is markdown + +so and so +{% endcapture %}{{ x | markdownify }} +``` + +### Using Kramdown + +You can also use [kramdown] as your Markdown processor: it supports GitHub-like code fencing and many useful Markdown extensions. + +```yaml +# _config.yml +markdown: kramdown +kramdown: + input: GFM +``` + +### Markdown in Kramdown + +If you do, there's a great alternative. Name your HTML files as `.md`, which is fine, because Markdown will ignore HTML blocks by default. You can then opt into Markdown processing via `markdown="1"`. More info on this on Kramdown's [documentation]. Hat tip to [@marksteve]. + + +```html +
I'm HTML
++ +**Update (Jan 2019):** Bower hasn't been maintained for years, and using Bower packages should now be considered a discouraged practice. + ++ +[Napa] is a package that lets you install arbitrary projects (without package.json) into `node_modules`. + +Bower packages are repos without package.json manifests. Hence, you can use Napa to use Bower packages as if they were npm packages... sort of. + +```js +{ + "scripts": { + "install": "napa" + }, + "napa": { + "hint": "chinchang/hint.css#v1.3.1", + "colorbox": "jackmoore/colorbox#1.5.9" + } +``` + +Promising idea, but I'd like to see it developed more. Some caveats as of 1.2.0: + +- not compatible with `npm shrinkwrap` +- upgrading packages are not automatic + +[napa]: https://www.npmjs.com/package/napa diff --git a/posts/2015/use-browserify-to-precompile.md.disabled b/posts/2015/use-browserify-to-precompile.md.disabled new file mode 100644 index 00000000..71e6e931 --- /dev/null +++ b/posts/2015/use-browserify-to-precompile.md.disabled @@ -0,0 +1,94 @@ +--- +date: '2015-02-14' +title: Use Browserify to precompile npm libraries +tags: [JavaScript] +description: Keep large libraries sane using Browserify. With ES6 and CoffeeScript support! +layout: simple +--- + +
+ +**Update (Jan 2019):** This article was written with an outdated version of Babel (Babel 5). Also, please consider replacing Browserify with something more recent like Rollup. + ++ +Remove the hassle in writing npm libraries in a transpiled language ([babeljs], [CoffeeScript], etc) by using browserify. + +With this technique, there's no need to maintain a full new directory of compiled files... just one pre-built `dist/` file. + +### Files + +``` +. +├─ lib +│ └─ index.js - actual entry point +├─ dist +│ └─ js2coffee.js - built package +└─ index.js - entry point (used in development) +``` + +### Install the requisite packages + +```bash +npm install --save-dev browserify babelify babel-preset-es2015 +``` + +### Make the entry point + +Put your _actual_ main entry point as, say, `./lib/index.js`. Then create an entry point `./index.js` like this for development: + +```js +require('babel/register') +module.exports = require('./lib/index') +``` + +### Set up compilation + +Set up a compliation script in the prepublish hook: + +```js +{ + "scripts": { + "prepublish": "browserify -s js2coffee --bare -t [ babelify --presets [ es2015 ] ] ./lib/index.js > dist/js2coffee.js" + } +} +``` + +For CoffeeScript support, use [coffeeify](https://github.com/jnordberg/coffeeify) for CoffeeScript (`-t [ coffeeify -x .coffee ]`). + +Options used: + +- `-s` - standalone (uses a UMD wrapper) +- `--bare` - don't stub node builtins +- `-t` - define transformations to use + +For packages targeting Node.js, use `--node --no-bundle-external`. This will disable browser-field resolution in package.json and not bundle node_modules. + +### Point the package + +Set `main` in `package.json` to the precompiled version: + +```js +{ + "main": "dist/js2coffee.js" +} +``` + +### All done + +- Every time `npm publish` is called, the pre-built version (dist/js2coffee.js) gets built +- Doing `require('js2coffee')` will point to the `dist/` version +- Doing `require('../index')` in your tests will point to the source version +- You can also do `require('js2coffee/index')` from other packages + +### Babel + +For [babeljs], I recommend using `--loose` for libraries that will target legacy IE. + +``` +-t [ babelify --loose all ] +``` + +[babeljs]: http://babeljs.io/ +[coffeescript]: http://coffeescript.org/ +[browserify]: https://github.com/substack/node-browserify diff --git a/posts/2015/use-macvim-with-lua.md.disabled b/posts/2015/use-macvim-with-lua.md.disabled new file mode 100644 index 00000000..4295fd37 --- /dev/null +++ b/posts/2015/use-macvim-with-lua.md.disabled @@ -0,0 +1,20 @@ +--- +date: '2015-04-14' +title: Speed up MacVim with Lua +description: Make your OSX Vim experience better with this simple switch. +tags: [Vim] +--- + +It's always a good idea to install [MacVim] with Lua support. [Homebrew] does not compile with Lua support by default. This gets you the benefit of a noticeably-faster [Unite.vim]. + +``` +brew install macvim --with-cscope --with-lua --override-system-vim --with-luajit --with-python3 +``` + + + +Also, the option `--override-system-vim` will allow you to use `vim` in the command line apart from the GUI... also a great idea! + +[macvim]: https://github.com/macvim-dev/macvim +[homebrew]: http://brew.sh/ +[unite.vim]: https://github.com/Shougo/unite.vim diff --git a/posts/2015/use-markdown-documentation.md.disabled b/posts/2015/use-markdown-documentation.md.disabled new file mode 100644 index 00000000..b61fd06c --- /dev/null +++ b/posts/2015/use-markdown-documentation.md.disabled @@ -0,0 +1,24 @@ +--- +date: '2015-02-19' +title: Use Markdown for documentation +tags: [Development] +description: Forget complex documentation schemes... it's really just this easy. +layout: simple +--- + +The most universal documentation "format" is a bunch of Markdown files inside a project's `doc/` directory. Here are some projects that follow that convention: + +- [io.js](https://github.com/iojs/io.js/tree/v1.x/doc/api) (and Node.js) +- [stylus](https://github.com/LearnBoost/stylus/tree/master/docs) +- [puppet](https://github.com/puppetlabs/puppet/tree/master/docs) +- [salt](https://github.com/saltstack/salt/tree/develop/doc) (uses .rst) +- [pip](https://github.com/pypa/pip/tree/develop/docs) (uses .rst) +- [npm](https://github.com/npm/npm/tree/master/doc) +- [composer](https://github.com/composer/composer/tree/master/doc) + +In my opinion, "a bunch of Markdown files" is good because: + +- It's easily viewable in GitHub +- It can be made into a Jekyll (GitHub pages) site easily +- It can be made into a Sphinx site easily +- It's a common documentation format that you can get some tools to generate to diff --git a/posts/2015/use-vendor-bundle.md.disabled b/posts/2015/use-vendor-bundle.md.disabled new file mode 100644 index 00000000..94f60a9d --- /dev/null +++ b/posts/2015/use-vendor-bundle.md.disabled @@ -0,0 +1,55 @@ +--- +date: '2015-06-22' +title: Bundle your gems inside your project +description: Here's a tip to get the most out of your Ruby development experience. +layout: simple +tags: [Ruby] +--- + +When working on a Ruby project, I always put the files in `vendor/bundle/`. This has the benefit of having a greppable index of all the gems of your project, while keeping your global gemset tidy. + +```bash +bundle install -j3 --path=vendor/bundle +``` + +You only need to do this once in your project. The `--path` setting will be persisted in your project's Bundler configuration (`.bundle/config`). + +
+ +**Update (Jan 2019):** Bower hasn't been maintained for years, and using Bower packages should now be considered a discouraged practice. + ++ +This seems pretty easy until you realize that Bower (a Node.js package) is not available in the Heroku Ruby build pack. +The gem [bower-rails](http://rubygems.org/gems/bower-rails) allows for easy Bower integration into Rails, but it won't work out of the box in Heroku. + +### Solution: add execjs + +The [Ruby buildpack](https://github.com/heroku/heroku-buildpack-ruby) has a magic behavior where if it detects the `execjs` gem, it will [bundle Node.js](https://github.com/heroku/heroku-buildpack-ruby#assets) with the build. This should make it work. + +```ruby +gem 'execjs' +``` + +### Alternative solution + +Use the [Multi buildpack](https://github.com/ddollar/heroku-buildpack-multi) to combine Ruby and Node buildpacks. + +``` +heroku config:add BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git +``` + +``` +# vim .buildpacks +https://github.com/heroku/heroku-buildpack-nodejs.git#v60 +https://github.com/heroku/heroku-buildpack-ruby.git#v127 +``` + +I recommend locking the versions (`#v60`) to ensure that you get versions that interoperate together (in case one upgrades and breaks interoperability). + +The last pack defined (Ruby in this case) is the "main" one that defines the process types (web, console, etc). diff --git a/posts/2015/using-git-merge-base.md.disabled b/posts/2015/using-git-merge-base.md.disabled new file mode 100644 index 00000000..a5166d14 --- /dev/null +++ b/posts/2015/using-git-merge-base.md.disabled @@ -0,0 +1,66 @@ +--- +date: '2015-12-10' +title: Use git merge-base for big merges +tags: [Git] +description: Use this one command to help you with big Git merges. +--- + +When trying to merge two Git branches that have diverged a lot, it's a little difficult to make sense of what happened on both sides. + +Enter [git merge-base]--a simple built-in utility to tell you where two branches diverged. It will tell you the commit where the two branches split off: + +```bash +$ git merge-base develop master +b8ac838cad3266f6a7e414181875831fd9b86ed5 +``` + + + +### Set up git tags + +This command will create a tag `_base` that will point to where they both diverged. + +```bash +git tag _base `git merge-base develop master` +``` + + + +### Inspecting changes + +You can then use `git diff`, `git log`, or [tig] to inspect changes on either side: + +```bash +# Inspect changes in Gemfile on each side +tig _base...develop -- Gemfile +tig _base...master -- Gemfile + +git diff _base...develop -- Gemfile +git diff _base...master -- Gemfile +``` + + + +### Check if both branches diverged + +You can also use the `--independent` flag which will show commits that can't be reached by any other. If it prints 2 commits, it means that there are changes on both sides. + +```bash +$ git merge-base develop master --independent +46978182cc8d90439b862e772e99a3f71889901a +8501118e0d958115caff692abda0f29ad530db4f +``` + + + +If it only prints 1, it means only one side has changes. + +```bash +$ git merge-base develop master --independent +8501118e0d958115caff692abda0f29ad530db4f +``` + + + +[git merge-base]: http://git-scm.com/docs/git-merge-base +[tig]: https://jonas.nitro.dk/tig diff --git a/posts/2017/less-cpu-on-development.md.disabled b/posts/2017/less-cpu-on-development.md.disabled new file mode 100644 index 00000000..8dfbe82a --- /dev/null +++ b/posts/2017/less-cpu-on-development.md.disabled @@ -0,0 +1,22 @@ +--- +date: '2017-07-12' +title: Make Rails (and other dev servers) use less CPU +tags: [Development, Linux] +description: Is Rails eating your CPU in development? Try this nifty trick. +layout: simple +--- + +Is Rails eating your CPU in development? Try lowering its priority using [renice(1)](http://manpages.ubuntu.com/manpages/zesty/en/man1/renice.1.html), a standard BSD utility that should be available in OS X and most Linux distributions. Here's a shell script that will automatically reset the priority to `+15` to common development processes: + +```sh +#!/usr/bin/env sh +sudo renice +15 -p $(ps ax | grep -E 'ruby|node|watchman|postgres' | grep -v grep | awk '{print $1}' | tr '\n' ' ') +``` + +Save this as `renice-dev` into one of your `bin` paths, and give it a `chmod +x renice-dev`. You can type `renice-dev` after you start your development processes to "renice" them. + +The lowest priority is `+19` (only run when nothing else is running), the default is `0`, and the highest is `-20` (makes things go very fast). + +### References + +- [Throttling processes in OS X](https://tinyapps.org/blog/mac/201107230700_throttle_process_os_x.html) _(tinyapps.org)_ diff --git a/posts/2017/life-in-side-quests.md.disabled b/posts/2017/life-in-side-quests.md.disabled new file mode 100644 index 00000000..e8b96930 --- /dev/null +++ b/posts/2017/life-in-side-quests.md.disabled @@ -0,0 +1,176 @@ +--- +date: '2017-02-19' +title: Your life is a series of side quests +tags: [Productivity] +image: images/side-quest-example.jpg +description: Video games organize tasks in quests. There's no reason this can't work in real life, too. +--- + + + +Video games tell you what to do using _quests_ or _missions_. There's no reason this can't work in real life, too. Books tell us to lead purpose-driven lives with long-term and short-term goals. Seems like a perfect way to make your life an RPG. + +## Missions + +A _mission_ is an achievable goal within 3 months or less. A mission should be broken down into sub-tasks. In other words, it's an actionable short-term goal. + + + +I prefix each mission with a projected date of completion (`1702` is 2017, February), but this is totally up to you. I do this to get a good retrospective at the end of the year of all the missions I've completed. + + + +## Keeping track + +### + + + +This system is so simple, you can use anything to keep track of it. As an Android user, I prefer using [Google Keep](https://keep.google.com). It lets me view all my missions at a glance, both ongoing and completed. + + + +There are a variety of other ways to keep track of your missions, including using plain notebooks and pens. What's important is you break your goals into manageable pieces, and give yourself a way to look back on your progress. + + diff --git a/posts/2017/life-in-side-quests/keep-missions.png b/posts/2017/life-in-side-quests/keep-missions.png new file mode 100644 index 00000000..ac4f17f4 Binary files /dev/null and b/posts/2017/life-in-side-quests/keep-missions.png differ diff --git a/posts/2017/life-in-side-quests/side-quest-example.jpg b/posts/2017/life-in-side-quests/side-quest-example.jpg new file mode 100644 index 00000000..0b67b8f3 Binary files /dev/null and b/posts/2017/life-in-side-quests/side-quest-example.jpg differ diff --git a/posts/2017/redux-side-effects.md.disabled b/posts/2017/redux-side-effects.md.disabled new file mode 100644 index 00000000..faf46984 --- /dev/null +++ b/posts/2017/redux-side-effects.md.disabled @@ -0,0 +1,155 @@ +--- +date: '2017-03-14' +title: Managing side effects in Redux +tags: [React] +layout: simple +description: Learn to manage impure side effects in a Redux store with middleware. +--- + +[Redux] is the preferred state management pattern for React apps today. Being a very "functional" library, it doesn't like side effects much. This means doing asynchronous actions in a Redux reducer is not just a bad idea, it simply won't work. + +```js +/* ✗ Warning: This won't work! */ + +function reducer (state, action) { + switch (action.type) { + case 'profile:load': + fetch('/my_profile') + .then(res => res.json()) + .then(res => { + dispatch({ + type: 'profile:set', + payload: res.body + }) + // ✗ Error: dispatch is not defined + }) + + ... +``` + +You can't modify state here in an async callback. In fact, you can't even `dispatch()` in a reducer! This won't work and is a bad idea; you break the purity of the store reducer. + +## Using Middleware + +### Middleware for side effects + +Fortunately, Redux has built-in provisions for managing side effects: [Middleware](http://redux.js.org/docs/advanced/Middleware.html)! You can write your own middleware with business logic. You don't need to use 3rd-party packages other than Redux itself. + +```js +// Redux middleware +function ProfileLoader () { + return store => dispatch => action { + // First pass them through to the reducers. + dispatch(action) + + switch (action.type) { + case 'profile:load!': + fetch('/my_profile') + .then(res => res.json()) + .then(res => dispatch({ type: 'profile:set', payload: res.body })) + .catch(err => dispatch({ type: 'profile:error', payload: err })) + } + } +} + +// Use the middleware in your store +store = createStore(reducers, {}, applyMiddleware( + ProfileLoader() +) +``` + +Redux middleware is simply a decorator for `dispatch()`. Here's an example where we extend `dispatch()` to perform certain side effects (an AJAX call, in this case) when certain actions come in. + +## Other solutions + +### Using redux-thunk + +Perhaps the most well-known solution to this is [redux-thunk](https://www.npmjs.com/package/redux-thunk), which allows you to dispatch functions ("thunks"). + +```js +// Using a function as an action via redux-thunk +store.dispatch(dispatch => { + fetch('/my_profile') + .then(res => res.json()) + .then(res => dispatch({ type: 'profile:set', payload: res.body })) + .catch(err => dispatch({ type: 'profile:error', payload: err })) +}) +``` + +However, I personally advise against this approach for a number of reasons: + +- It moves logic to your action creators, which were supposed to be very simple pieces of code. + +- It makes actions complicated, when they can just be simple JSON instructions (eg, `{ type: 'profile:load' }`). + +- It can't interact with other side effects. For instance, you can't make a side effect to send `profile:error`s to an error tracking service. Middleware can do this. + +## Naming convention + +You may have noticed I named my action `profile:load!`. This is my preferred convention of choice, where action names are simply strings, and "side effect" actions are suffixed with an exclamation mark, just as it would in Ruby or Elixir. + +## Other examples + +### Error tracker + +How about a middleware that tracks errors as they come in? + +```js +function ErrorTracker () { + return store => dispatch => action { + dispatch(action) + + switch (action.type) { + case 'profile:error': + case 'account:error': + case 'other:error': + Rollbar.track(action.payload) + } + } +} +``` + +### Ticker + +Or a middleware that sends `tick` events every second? Great for timers or for RPG's. + +```js +function Ticker (options) { + let timer + + return store => dispatch => action { + dispatch(action) + + switch (action.type) { + case 'ticker:start!': + timer = setInterval(() => { + store.dispatch({ type: 'ticker:tick', now: new Date() }) + }, options.interval) + break + + case 'ticker:stop!': + if (timer) clearInterval(timer) + timer = null + break + } + } +} +``` + +### Combining them + +And to put them all together: + +```js +store = createStore(reducers, {}, applyMiddleware( + ProfileLoader(), + ErrorTracker(), + Ticker({ interval: 1000 }) +) +``` + +## See also + +Check out [Redux on devguides.io](http://devguides.io/redux)! Devguides.io is my new pet project where I make pocket-sized explainers for web development concepts. + +[redux]: http://redux.js.org/