My history with writing web apps is long and filled with missteps. I’ve made many mistakes and learned from them. This is an attempt to capture some things I learned the hard way.
High level first
Before anyone writes a line of code, step way back to consider the bigger picture. Sketch it out on a white board. Understand what your data looks like, and how it flows through your application. What is the best way to handle data flow as the application scales? Big, high-level questions need to be answered before you get too mired in detail to think clearly.
In the early days of my career, when all web UIs were generally terrible and everyone used relational databases, this would mostly be an exercise in schema design. Lots of thought went into fleshing out the relationships between data.
Design matters. Really matters.
Data flow and architecture are still really important. There are many more options for data storage, data delivery and managing scale. There is no single solution that works best for everyone.
We also need to put a lot of careful thought into how users will interact with our apps. Anyone who thinks this is the least important part of designing an app needs to crawl out from under whatever rock they’ve been hiding under and hand over the Oreos. Denial isn’t just a river in Egypt, Buddy. Users are more demanding, impatient and fickle than ever, and they will not spend any more time than necessary on a crappy web site.
True story: I once pulled an online investment portfolio out because my bank’s web site had a bug in their table sorting. After I submitted a thoughtfully detailed bug report I got a generic email saying they would address it “soon”. After a few months I gave up and switched to another investment platform. It’s likely that I’m more fickle and impatient than many users. Still, I don’t think this story is completely unusual.
The average 25 year old today grew up with the internet. It takes more to wow someone today, and very little to lose them. Technological problems are super fun to solve, but in the end the tech should serve the design, not the reverse.
Thoughtful design originates with user empathy, not technology. At one point I was teaching a web dev bootcamp. Students came from different backgrounds. Some struggled mightily with technical concepts. One of these students wrote a really clever game for his final project. It was simple technically, but so fun & well-designed that everyone wanted to play it. It was an idea driven concept, whereas many of the other projects were born from the desire to use a certain technology.
Different people want different things, too. First figure out who you want to love your site and get lots of user feedback early. This is where prototypes really shine. The feature you thought was super awesome might irritate your target user base. Best to discover this early and pivot!
Beware of over-architecting
The best technical decisions now are those that allow you to change your mind later. Current you doesn’t have all the information that future you will. You want to remain flexible enough to improve on past decisions and to potentially adopt new technologies as they develop. Start out with the most simple, barebones approach that you can and only add complexity as necessary.
This is especially true of your data flow. Think about it in terms of designing public transportation. That is to say, less distance, fewer stops, direct, and one way when possible. I’m looking at you, Redux. Once you go deep into that “chuck it all into the store” philosophy, it can be really hard to turn around. Redux has it’s place but don’t use it as an means for janky data flow.
Be agnostic about technology
Do unbiased research before making big technology decisions. It may be tempting to use the hot new thing. Be mindful of the pioneer tax, however. This can be particularly rough if you have a lot of newer people on your team. A tried and true solution that has stood the test of time may be best, especially when getting a larger team up to speed.
By the same token, don’t use the thing you’ve always used only because you are comfortable with it. That is the worst reason to choose a technology. You don’t get to learn anything new and it forces you to potentially pick the wrong tool for the job.
Assess your team
Technical decisions are not just about technology. A team of experienced developers learns differently from a team of newer folks. People with a few apps under their belts can get up to speed quickly and avoid major pitfalls. They will recognize patterns even if documentation is spotty.
Beginners bring great enthusiasm and a willingness to learn, but they also may need a little bit more time to get up to speed. The documentation needs to be thorough as they may not be able to infer missing details. They may also have that great idea no one has considered yet, so it’s important to give them a voice. Ideally, a team will have a mix of both.
Write tests early
Once upon a time I was on a team that hated writing tests. Our app got a lot of traction in a short time, so we worked hard to add features that our users wanted. At first this was fine, but soon enough any new feature seemed to break something else. We became afraid to touch the code too much for fear of introducing regressions. Then we became stuck at old versions of packages and stale features.
Eventually we were forced to write integration tests before handing the project over to a new team. Unfortunately, I wrote most of these tests, and I still have PTSD. The code was almost completely untestable. It was a nightmare of spaghetti badness. Please never do this to yourself.
Writing tests may seem like throwaway work at first, especially when you are unsure of requirements. However, if unit tests are written during the development process, code will be testable. It also provides a base case that things we didn’t intend to change are still working as expected.
Don’t go overboard, though. Striving for 100% test coverage isn’t the best use of time. While there is always debate over this, most experts agree that around 80% unit test coverage is best. There can be such a thing as too many tests, especially early on in development. Quality wins over quantity. Tests that focus too much on implementation details will definitely slow the team down.
Once your app has stabilized a bit, it is a good time to write integration tests that assure major functionality isn’t broken each time someone makes a change. These will become much more important than unit tests over time.
Writing a lot of different apps is a great way to see bigger patterns and spot possible pitfalls. This is why I love hack days and personal projects. You’ll make mistakes. We all do. Try to have fun learning from them and keep going! The next one will always be the best one yet, because each time you’ll get a little bit better at thinking things through before you start.
I’d love to hear your learnings and thoughts! Please share in the comments.