My history with writing web apps is long and filled with missteps. Here I attempt to share lessons 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. How will it scale? Big, high-level questions need to be answered before you get too mired in detail.
Cloud architecture based on micro-services is a great way to assure that nothing gets too monolithic. Monolithic code is the enemy of change.
Careful thought around UX is important. This can be even more crucial than choosing the right stack. The need for speed is real. Users are more impatient and fickle than ever.
The average 25 year old today grew up with the internet. It takes more to wow them and very little to lose them. Technology problems are fun to solve. In the end the tech should ultimately serve design & not the reverse.
Thoughtful design originates with user empathy, not technology. Lots of user feedback early on will help avoid big missteps later. This is where prototypes shine. The feature you thought was amazing might only alienate your users. Best to discover this early, before sinking development time into it.
Once I was teaching a dev bootcamp. Students had different backgrounds. Some struggled more with technical concepts. One wrote a brilliant game for his final project. It was simple technically. His idea was great, though, and mostly centered around a well-designed UI.
As a result, everyone wanted to play his game. Many more technically complex projects didn’t get half the classroom attention his did.
Beware of over-architecting
The best technical decisions now are those that allow you to change your mind later. Current you doesn’t have the information future you will. You want to remain flexible enough to improve on past decisions and to potentially adopt new technologies. Start with the most barebones approach, only adding complexity as necessary.
This is especially true of data flow. Think about it in terms of something physical, like designing public transportation. Once you’ve over-architected it can be hard to back out. For example, many React developers immediately reach for Redux without asking themselves if they need it yet. Once you go into “chuck it all into the store” territory, it can be hard to turn around.
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, though. 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. 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. 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 experience. Senior devs who communicate well will ultimately bring more to the team than an aloof rock star. Never underestimate enthusiastic junior devs. Same for those who may have many years of experience but outdated skills. Everyone at the table has a voice.
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. We raced to add features our users wanted. Eventually, any new feature would break something else. We were afraid to touch the code too much for fear of introducing regressions. Our code base got stuck at old versions of packages and stale features.
Eventually we were forced to write integration tests before handing the project off to a new team. Unfortunately, I wrote most of these tests. I still have PTSD. The code was almost completely untestable.
Writing tests may seem like throwaway work, especially when you are unsure of requirements. However, if unit tests are written during the development process, code will be more modular and testable. Less of it may end up in the bin.
Don’t go overboard, though. Most experts agree that around 80% unit test coverage is best. Coverage percentages can be arbitrary, too. Quality wins over quantity. Tests that rely on implementation details are the enemy of velocity.
Once your app has complete MVP functionality, it’s good to write integration tests. These assure major functionality isn’t broken each time someone makes a change.
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. It’s a great sandbox. Ultimately, experience will make us all better.