This post attempts to distill what I’ve learned this year trying to grow myself and the engineering organization at Weedmaps. Some of it’s probably obvious, but it’s good to take some time to reflect and focus on key learnings, since learning is ultimately our job as Engineers.
Process introduced without automation will invariably be rejected or ignored by the engineering team. If you want to change the process, create the new process, automate it, dog-food it, and then show people how and why it is better.
New engineers are the best chance to get outside perspective on the processes and programming techniques we consider canon. Listen to them and use their fresh eyes to re-examine best practices. After 90 days or so, they will have assimilated the company culture and it will be much harder to see the inefficiencies.
Clarity is key to shipping effective code that solves a business need. Being Agile doesn’t mean writing code without clarity. That clarity should show in the ticket that you are executing against. If it doesn’t, you shouldn’t do the work until you have clarity. Speed without purpose is ineffectual.
Clarity starts with the CEO and is focused down through the teams. Without effective communication of clarity down through each level of leadership, the resulting code will miss the mark. However, Clarity is not owned by leadership. If you have it, provide it to your peers. Shout it from the rooftops until mutual understanding is present among your team
Clarity and intent are important in Code as well as team dynamics. A strong type system communicates intent very clearly. Modern strongly-typed languages will make you a better engineer, and in most cases, reduce the number of bugs shipped to production. Rust, C#, Swift, Kotlin and ReasonML are great examples of a Modern languages with great Type systems. If you can’t use those, then use bolt-on type systems, they are pretty fantastic as well (Dialyzer, Flowtype, TypeScript)
Asynchronous systems are more complex and should be avoided until absolutely necessary. A common service-oriented-architecture pattern is to use an Async Message Queue. Avoid them until you have a proven reason to need one (ETL, Event Sourcing). Favor synchronous communication paradigms (HTTP) until you run into a performance problem.
Your public API will be abused, misused and mis-understood. Over document and communicate your Public interfaces to ensure they are used correctly and their effects are understood. This isn’t limited to HTTP APIs, but Libraries, Modules and Classes as well.
Object Oriented Programming OOP provide constructs like Classes and Modules that are useful to modularizing your code. Use them! However, avoid deeply nested inheritance (more than a single level), multiple inheritance (mixins, concerns). Favor Functional or Object Composition in almost all cases.
Be defensive in your code. Always assume your dependencies will fail and focus on how your application will behave in those scenarios.
Focus on doing work that is multiplicative to your teams success. Multiplicative work includes abstractions, tools and documentation that make your team (and your future self) faster and more efficient.
Initiatives, tools, and process changes will die if not championed by a single motivated individual. Never underestimate the power of a single motivated Engineer to change the entire company. Follow through until the change you want to see is complete.
Engineering for web performance is a mindset, there is no single silver-bullet. Repeated measurement and refinement is required to have a high-performing website. This work is never done, or good enough. It needs to adapt as the landscape changes.
Code Quality comes from a combination of upstream practices. Trying to analyze code for quality at Review time is usually too-little, too-late. Use the methods mentioned above (API design, Class and Module design, Strong-Types) to improve quality before it hits Peer Review.
Engineers should understand how your code reaches production. Ultimately it is your responsibility to ship code to production, and your work isn’t done until it is in production. Use the tools, documentation and people available to you to understand. Knowing this will change the way you write code and provide insights into ways to improve it.
Self-service deployments (and rollback), reliable monitoring, orchestration, Feature Flags, and a solid deprecation model are table-stakes in a Service Oriented Architecture. Without them, the increased complexity will crush the team.