August 25th, 2015
Do you think you have what it takes to ship great software? I’ll let you in on a secret: it’s not easy and takes a lot of effort—but it’s all skills that you can learn.
Here’s my checklist for getting software projects done, in a way that they actually ship and actually work well:
Learn how to design things for humans
It’s a skill like any other to learn: design things for humans. I don’t mean visual design (though that is part of it), I mean looking at a problem and figuring out how to create human-computer interactions that make people successful at solving the problems without having a hard time, instead of just defaulting to putting up yet another CRUD form with a few standard UI components that map to some database fields.
A good way to get started is to use other people’s software and take notes about tasks you’re trying to complete and what you actually need to do to complete them. In my email client, how many clicks do I have to make to reply to someone? How many labels do I need to read? How often do I need to switch between the mouse and keyboard? Does it help me in any way with common tasks (like “find all attachments from a specific person”)? (You’ll be surprised how hard it is to use software!).
Stick to a few languages. Master them.
If there’s a better solution in another language or environment only use it if gives you some really amazing advantage. It’s often not worth the extra effort to become proficient enough with yet another tool.
Don’t underestimate what it means for a production environments: things have to be provisioned, deployed, security-patched and monitored.
Don’t follow the hype
Use what works for you. If you’re productive in PHP, by all means, use PHP. Of course, sometimes technologies come along that actually measurably increase productivity or have other huge advantages, but it can’t be overstated how few and far between those are—perhaps one or two happen in a decade.
Additionally, don’t step into the trap of believing that because there’s many variations of a specific technology that the underlying idea is a good one. It might actually be a sign of people trying in vain to find a technological solution for the wrong high-level approach.
For example, client-side MVC, for almost any type of web application functionality, will add programming overhead (because there’s more layers and those require interfaces between them), lessen productivity (more code to write and the layers make debugging harder) and likely not actually improve the experience for users (user interface design is hard work and using client-side MVC will not magically do it for you).
Stick to a style
Just like languages, frameworks and libraries, the way you use a language seems to change like seasons. One month it’s put it all in closures and the next month your hear that closures are so passé. Reduce cognitive stress while coding and debugging so you have more time thinking about the actual problem you want to solve.
Implement that minimum viable solution
It can’t be said often enough: when writing code, don’t write anything that the code doesn’t absolutely need in order to work. Don’t anticipate how you may extend the code in the future. It never turns out that way anyway. Concentrate on code that works, and write tests instead of wasting time on too much abstraction.
Don’t forget: code is not written in stone. It’s easy to refactor or rewrite later when you do need to change or extend it and when you actually know the requirements.
Avoid complexity
For example, I don’t use CSS or HTML preprocessors like HAML or Sass (if they work for you, awesome, please use it and be productive!)—my style of coding and refining apps involves a lot of tinkering and I have an easier time if I can mess with these things on a low level (for example, just copying and pasting styles I messed with in browser development tools into a CSS file directly).
And while I like CoffeeScript a lot, I find it easier to just write JavaScript directly. The gains of slightly cleaner syntax and better language features are not enough for me to deal with extra compilation steps, more complicated development setups and debugging issues.
Coding > Configuration
Avoid pre-fabricated solutions that only solve your problem the first 80%. You’re a programmer, not a configurator.
Try tracking your time doing various jobs while programming, from thinking about how to implement a specific feature, writing outlines and todo-lists for implementation, picking tools and libraries and making prototypes with them over actual implementation, writing tests and iterating over functionality and bugs.
You’d be surprised how little time you actually spend coding versus how much time can go into picking libraries. You might save a lot of time by just sitting down and writing code from scratch instead.
Never stop learning
Perhaps the best way to stay sharp is to occasionally do side projects, open source and perhaps micro-libraries. Experiment and tinker, so you don’t lose the joy of creating things out of nothing.
What helps you write great software? Hit me up on Twitter and discuss!
December 2nd, 2014
Last Tuesday, I’ve started a little Thanksgiving charity drive to get some money together for kids in Ferguson. I couldn’t be happier that I’ve sold $1,044 worth of my book Retinafy.me with 100% of this going to Donors Choose projects in Ferguson, MO. (I’m coming up for the payment processor fees out of my own pocket, so all the $1,044 go directly to the kids!)
My wife and I are big proponents of supporting literacy—it’s the foundation on which all education, learning and communication with people that you can’t directly talk to is based. If you don’t start to read at an early age, chances are that you never get into it.
Unfortunately as a society we seem more obsessed about hate and fear than supporting those who can’t help themselves. Children are at the receiving end of racism and institutionalized blaming and shaming of minorities. No money for education but buying tanks for the police is just one of the many symptoms of this.
While it’s only a small gesture, we have to start somewhere. Consider regularly giving money and/or supporting local kids. There’s more that you can do than you can think of.
Here’s the projects fully or partially funded with the Retinafy.me purchases:
In the interest of transparency, here’s 1) the Proof of donating to Donors Choose and 2) an anonymized CSV tally of all sales from Tuesday, November 25, up to Monday, December 1.
Thanks again!
November 30th, 2014
Up to and including Monday December 1, 100% of sales of my Retina Web ebook will go to Donors Choose projects in Ferguson, MO.
These kids need our help! Thank you!
Get your copy now!
October 31st, 2014
Webfonts are the new hotness, and icon fonts even more so. There’s plenty to choose from, and Google just released an icon font that’s based on the new Android L. Icon nirvana reached?
Not really. Icon fonts have a few nasty problems that icon font makers rarely make you aware of. Here’s a few of these problems:
If you serve icons from a service, that services might randomly go down. I’ve seen this over and over again with big and small websites.
You can’t easily edit icons, and it’s hard to see what’s been updated in source code control. Webfont files are for the most part binary and changing one icon normally means the whole resulting font file is different.
There’s blurry rendering on certain browsers. Some CSS properties have to be abused (like -webkit-font-smoothing: antialiased;
) to make the icons look good. This doesn’t work in some browsers and in some browser versions.
Most importantly, when icons are in the same CSS block, or when centered in an odd-width container, you get off by half-a-pixel blurryness, which can’t be corrected. This happens on all browsers, even on the latest and greatest Firefox, Chrome and Safari (even though Safari is doing better than IE, Firefox and Chrome, I’ve seen it happen on Safari as well).
Here’s some screenshots from GitHub on IE 10, showing this issue (it also happens with other browsers, like Chrome):
In Freckle Time Tracking we had a clever setup with SVG source files (on a precise 16×16 grid) and using fontcustom
to compile fonts and doing some post-processing of the generated CSS with sed
(most to remove unwanted font variants, as you only need woff
in recent-ish browsers).
We also required to add some special headers when serving these font files so that our CDN (Amazon CloudFront) would correctly serve them.
All of this worked, but… blurryness alarm!
Even-width container:
Odd-width container:
Back to square one
Let’s take a step back and ask—what do you need from an icon? Why do icon fonts appear to be a good solution? And how can the problems be fixed?
- Icons need to be rendered pristinely and in focus.
- They should ideally be rendered the same or nearly the same on all browsers you support.
- You should be able to change the color and ideally other (CSS) properties.
- The same icon should look great on normal and retina screens; ideally you can substitute a different version for retina if you so fancy.
- It would be great if the files are text, so they work great with source code management. (Did you know that GitHub does graphical SVG diffs?)
Inline SVG to the rescue…
Here’s our current workflow:
- We’ve a bunch of SVG files in a folder, which are our icons. All of them are on a 16×16 pixel grid.
- There’s shell script that optimizes the SVG, and then generates a Rails helper and a JavaScript helper, as well as copies the optimized SVG files into
/public/images
:
#!/bin/sh
# This requires "imagemin", install via:
# npm install --global imagemin
echo "Cleaning up..."
rm -rf build
mkdir build
echo "Optimizing SVG..."
imagemin *.svg ../public/images/icons
ruby ./generate_helper.rb
-
For the optimization, we use imagemin, which will remove unnecessary stuff from the source SVG files (these are all saved in Adobe Illustrator, which likes to be on the verbose side when it comes to saving SVG).
- There’s a Ruby script that reads the optimized SVG files one by one and generates a Rails helper file with
icon_xxxxx
methods. These methods can be called from any view to insert the desired icon as inline SVG:
#!/usr/bin/env ruby
require 'json'
FILENAME = "../app/helpers/icon_helper.rb"
JAVASCRIPT_HELPER = "../public/js/icons/icons.js"
puts "Generating helper #{FILENAME}"
File.open(FILENAME, 'w') do |helper|
helper.write "module IconHelper\n\n"
Dir.glob(File.join("..","public","images","icons","*.svg")).each do |icon|
svg = File.read(icon).delete("\n").delete("\r").delete("\t")
name = icon.split('/').last.tr('-','_').gsub(/\.svg$/,'')
puts "#{name}: #{svg.size} bytes"
helper.write " def icon_#{name}\n"
helper.write " '#{svg}'\n"
helper.write " end\n\n"
end
helper.write "end"
end
puts "Generating JavaScript helper"
File.open(JAVASCRIPT_HELPER, 'w') do |helper|
Dir.glob(File.join("..","public","images","icons","*.svg")).each do |icon|
svg = File.read(icon).delete("\n").delete("\r").delete("\t")
name = icon.split('/').last.tr('-','_').gsub(/\.svg$/,'')
# we only need a few specific icons in JavaScript, so skip those we don't want
next unless name =~ /^cursor/ || name =~ /^arrow_right/
puts "(JavaScript) #{name}: #{svg.size} bytes"
helper.write "window.__icon_#{name} = #{svg.to_json};\n"
end
end
Calling on icon_xxxx
generates inline SVG as shown below:
-
The Ruby script also generates a JavaScript helper file that’s similar. We only include icons in it that we need from the few places we generate HTML in JavaScript, like our calendar widget.
-
Last but not least, the optimized files are copied into
/public/images
so you can use
them for special cases when you don’t want inline SVG but a normal image tag or a background image.
-
To set the color of an icon in CSS, just add a
fill: #abcdef;
CSS property.
Boom—problem solved. This works great on all browsers, and you don’t get any of the rendering issues that you have with icon fonts.
Actually there’s several unexpected advantages:
- It’s easier to use icons if you inject JavaScript into 3rd-party websites. We use this for the pink support widget that’s on the bottom right of Freckle’s landing page.
- If you want to do more advanced animations, like morphing an icon into an other icon, it’s pretty easy to do as you can manipulate inline SVG easily with JavaScript (and you can use CSS animations as well!)
- When you copy+paste text, the SVG is ignored so you don’t get weird extra characters in the pasted text.
- There’s no weird “flash of unstyled text”, neither is there empty spaces that are only rendered when an icon font was fully loaded.
The only downside is perhaps that your HTML will be slightly larger than it would be with an icon font, which might result in slighter longer loading and rendering times. This is offset by not having to load an icon font in the first place, however, and in my tests has not been a problem at all. A possible way to reduce the HTML size is to set data-icon
attributes on elements and have JavaScript insert the inline SVG (I’d say you’re probably better off with directly rendering tho, as running JavaScript isn’t “free” either).
Enjoy the SVG goodness!
May 16th, 2014
The Internet is awesome. Information at your fingertips and always-available help from people all over the world is one of humanity’s dreams come true. I’m not sure if the ancient philosophers included copy & pasting of code snippets in this dream, but it’s a fact of daily developer life.
It’s awesome, and it’s very convenient.
But this is not how you learn and become great at thinking for yourself, finding solutions for solving programming problems and most importantly how to be creative. Over-using sites like Stack Overflow will not make you a better developer, it will only make you very good at clicking up-vote buttons and copy & pasting.
You owe it to your brain and future self that you try to find a solution first, and not give up just because something doesn’t work the first time you try it. Especially when you don’t feel comfortable or knowledgeable, because you’re working on a new project, with a new programming language or different development environment. Humans are built for exploration and understanding by doing. Your brain will reward you for discovering things. The rewards are higher as the problem is harder (for you) to solve.
That doesn’t mean to ban forums and answer sites from your bookmarks. You can and should share your discoveries and see how others solved similar problems. You’ll probably find that there’s (hope my cats won’t hear this) more than one way to skin a cat. Sharing will likely lead to new, better ways to tackle a specific problem, and this will benefit lots of people.
All because you spent 10 minutes thinking about a problem and not just copy & pasting the first answer that somewhat works.
April 13th, 2014
Here’s some things you need to make a successful web app:
- A plan to make an application that helps real people to make their lives easier, solving a well-researched problem
- Understand human psychology
- Know how to design, both in terms of UX flow and visual design
- A marketing plan, to tell potential customers that your app solves their problem
- A text editor
- A web server
- Probably some sort of database
- A payment processor of sorts
- Good security (including well-tested backups) from the start
- A (at least basic) understanding of tax laws in your country
- A healthy dose of perseverance
And here’s some things you don’t need:
- The latest alpha of hype.js
- CSS frameworks
- Boilerplates
- reset.css
- JavaScript loaders
- The newest NoNoNoSQL database
- Distributed anything
- That cool new jQuery plugin
- A custom-designed font
- Multiple load-balanced “webscale” servers
All these things create the illusion of making things easier when in reality they create very complex dependencies and will be very hard to remove later if they don’t turn out to be the silver bullets they promise to be. This doesn’t mean these things are bad or evil. You may want some of them later, when your app grows.
Remember, keep it simple and don’t over-engineer. Solve the problems at hand, and don’t anticipate “potential” problems.
You need to wear many hats when setting out to make a successful web application: entrepreneur, psychologist, designer, programmer, marketer, accountant—but you’re not a fortune teller.
April 8th, 2014
OpenSSL had a bug for several years which allowed attackers to untraceably read all your SSL traffic and some server memory.
If you’re like me and have better things to do than reinvent the fix-wheel and you’re all like “WTFBBQ TL;DR” here’s the absolute minimum what anyone who runs a web server with SSL must do.
NO, NONE OF THESE STEPS ARE OPTIONAL.
- Update OpenSSL to 1.0.1g. This is required before you do anything else.
- Recompile anything that’s statically linked against OpenSSL. In many instances, web server software like Nginx is statically linked and must be recompiled. For example, if your Ruby is statically linked to OpenSSL, it’s recompile time!
- Reboot the server. This must be done before issuing new certificates.
- Create a new private key and CSR and get a new SSL certificate. You will need to revoke the old SSL certificate. (If you’re on Godaddy, use their “rekey” function. The old cert will be revoked automatically after 72 hours). Don’t forget to install your new cert.
- Change any server passwords. These may have been read by an attacker as they are in server memory. It’s not a bad idea to issue new server SSH hostkeys as well.
- Change any and all passwords and tokens of APIs you use. As server memory may have been compromised, an attacker could access the APIs as if they where you. Not good.
- If you’re using cookie-based sessions in Rails (or similar environments) you must switch to a new encryption secret. Your current secret may have been compromised, allowing attackers to log in as anyone to your service. Unfortunately this means all your users will have to log in again.
- Ask your users to change their passwords. As this security issue means that server memory may have been compromised as well as past traffic could be decrypted, passwords should be considered to be compromised.
Whew.
There’s an optional step, which I highly recommend while you’re at it—get your SSL configuration into shape and enable PFS and HSTS (and test it!). It just takes a minute if you’re on Nginx.
If you have anything to add, please email me directly and I’ll update this post.
April 4th, 2014
Recently we upgraded our server infrastructure for Freckle Time Tracking and in the process wanted to improve how we serve SSL.
If you don’t know much about this, it’s fine—there’s a few simple steps you can take to make your website more secure and faster loading in the process. _Important: of course, there’s no absolute security, and I make no claim that what I describe here is secure and will work for you. Use it at your own risk._
Long story short, you’ll want to get an A+ rating on the Qualsys SSL Labs test.
For that you’ll need to do the following:
- Don’t support older protocols. A lot of servers support really old and obsolete protocols. If you run a web app, your users will very likely not need support for these.
- Don’t support flawed SSL ciphers. There’s a bunch of these and you can avoid using them. Browsers support multiple different ciphers, so this is not a problem.
- Cache SSL sessions. This will improve performance.
- Turn on HTTP Strict Transport Security (HSTS). This is a special header that will tell browsers to never connect to the server via normal HTTP.
And that’s it. In order so you don’t need to research the proper settings, here’s how this looks like in form of an nginx configuration:
server {
# deferred allows for faster connections if there's
# no other servers on port 443 defined
listen 443 ssl spdy deferred;
ssl on;
ssl_certificate /etc/nginx/your-certificate.crt;
ssl_certificate_key /etc/nginx/your-private-key.key;
ssl_prefer_server_ciphers on;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS:!AES256;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_stapling on;
# tell any upstream things like unicorns that we're on https
proxy_set_header X-Forwarded-Proto 'https';
underscores_in_headers on;
location / {
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
# ...
}
# ...
}
And that’s it. Have fun with your new A+ rating on the SSL labs test.
March 30th, 2014
Our Internet isn’t big corporations doing whatever they want. Our Internet is not DRM, is not SOPA and not PIPA and not the spying on us (and everyone else). Our Internet isn’t bigots taking away human rights from people. Our Internet isn’t hiding behind PR releases.
Our Internet isn’t greed, narcissism, fear and blind hate.
Our Internet is people helping each other be excellent. It’s sharing, caring and being proud of what we humans can do if we only put our will to it. It’s about helping the unprivileged when governments fail. Our Internet is about standing up to your mistakes.
Our Internet is about love and empathy.
The only thing we have is each other.
That is all.
January 19th, 2014
There’s bunches of plugins, extensions and techniques to smoothly scroll page elements, but most of them are convoluted messes and probably do more than you need. I like “small and works well”, and it’s a good exercise for those JavaScript and DOM muscles to write a small plugin from time to time.
My goal was to have an animated “scroll to top” for the mobile version of Freckle—normally the browser would take care of that (tap status bar to scroll to top), but in a more complex layout the built-in mechanisms for this quickly fail and you’ll have to implement some of the interactions users expect (like tap status bar to scroll to top) yourself. Specifically, this is for the native app wrapper (Cordova) I use for Freckle’s upcoming mobile app. It’s hooked up so that taps on the statusbar invoke a JavaScript method.
During development of this I needed the same thing for arbitrary scroll positions as well, so “scrolltotop” is a bit of a misnomer now. Anyway, here’s the annotated code:
Often, writing your own specialized plug-in is faster than trying to understand and configure existing code. If you do, share it! 🙂