What gets in the way of doing great work?
You are either not properly motivated to achieve great work or you simply do not know how.
An engineering manager’s duty is to set their team up for success.
I first had my first opportunity to embark on this journey to grow as a manager at Wayfair on the Design Services team. We were working on an amazing product so we were never short on motivation.
To ensure that we were all on the road to do great work, I wanted to focus on defining how we would achieve great work as a team. It started with establishing our core values.
Values are the things that you believe are important in the way you work. Here are some things we value when we are collaborating and coding.
To build the best experience for our users, we will always make decisions that align with the best practices and patterns for our platform. We should avoid the pressure to copy how other platforms (iOS, mobile web) implement a feature if it does not provide a good Android experience.
Writing documents, emails, slack messages, code reviews, etc are things we do daily. Making sure the written content is easily readable and understandable is important!
The code we write will always have a reach greater than we initially imagine. The codebase changes over time and we need to be mindful about how we write code to make it easier for other people now or later to interact with it.
Writing perfect code is a myth. The idea of perfect code will guide us in a direction rather than a destination.
Requirements change over time which means code might have to change too. We should do our best to design and write our software in a way where minimal changes in existing code are needed when new features are planned.
Feedback is a gift
The act of giving feedback requires a lot of thought and empathy and should be received with the same consideration. Feedback is a gift with the opportunity to grow and you are encouraged to present that gift to others whether is through pull request reviews, peer reviews, or conversation.
With our values established, we can talk about the details around how we can align with contributing better software.
Rooted in SOLID
- Single Responsibility Principle
- Open-closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
Uncle Bob’s 5 principles are amazing principles to align with for writing outstanding code.
Use Nullability Wisely
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. […] This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years — Tony Hoare
The most common crashes in the Java platform are Null Pointer Exceptions so by eliminating or avoiding nullable objects, we inherently make our app more stable.
The truth is that the concept of null is not a mistake, but Java’s type-system, that considers null to be a member of every type, is.
Embrace null in your API design. Null is your friend with Kotlin. There is no reason to fear it and no reason to work around it with “null object” pattern or wrappers, let alone with exceptions. Proper use of nulls in your APIs results in more readable and safer code, free from boilerplate. — Roman Elizarov
On the other hand, there is a compelling argument of how and when to use nulls to complement your code design. Be very mindful of your null use cases.
All race conditions, deadlock conditions, and concurrent update problems are due to mutable variables. — Uncle Bob
Immutable data helps us be mindful of areas where data can change and areas where it doesn’t need to be changed. The extra awareness helps us avoid defects in the code. An additional benefit is that immutable data is thread-safe.
Use Meaningful Names
If you want your code to be easy to write, make it easy to read — Uncle Bob
We should be able to glance at a class or method name and be able to get a good idea of its purpose.
Methods should sound like actions.
We should avoid naming classes and variables too broadly. Words like “Data” or “Manager” should be avoided.
If you are in a situation where you are repeating code, try and refactor it so you are instead reusing code. Follow the DRY principle.
Fight Software Rot
“Leave the campground cleaner than you found it.” — Boy Scouts of America
Leave the codebase cleaner than when you got there. When you modify an area of code and have the opportunity to improve its quality without too much of a time commitment, do it. Fix Broken Windows.
Master Inheritance vs Composition
Use inheritance when objects share from a common set of data and behaviors. Too much inheritance will make a set of classes hard to understand.
Use composition when encapsulating behavior that can be used by multiple unrelated classes. Too much abstraction can make classes opaque and cumbersome.
Figuring out the right use cases and balance is important.
Write Unit Tests
There are many reasons to write tests. Unit tests give you an additional perspective on how well your classes are designed based on how easy it is to test it. They can tell you if new code changes break existing requirements and how well your code adhered to the open-closed principle. Unit tests inspire confidence in your code.
Coding by Convenience is a Pitfall
Sometimes objects can be reused in different parts of the application. Most of the time, this may be the wrong thing to do. An example would be if I have a database model that fits the requirements of representing the view, I can reuse that model class. This may not be desirable because your view will have a dependency on the database layer and will be directly affected by changes in the database model. It would be a better option to have two separate but similar models in this case.
This is the framework for how the Design Services Android team achieve great work. If you are on a team where you’re not sure how to do the same, work together to define your own standards and guidelines.
Big thanks to the DS team and Julie Zhou & her book The Making of a Manager.