
This health check is the first step toward building better software for startups. It helped me build a couple of successful MVPs, and these guidelines guide me in every tech decision.
How to execute the health check:
- Grab your dev team and book a two-hour meeting. Don't include business partners or other stakeholders; it has to be an internal meeting just for developers. If you don't have a senior leader who can lead the meeting, get an outside facilitator.
- As a team, go through every point and evaluate it on a scale from 1 to 10. Note your answers. If you are not sure what some rule means, Google it, and make sure you understand every word from the document.
- During the discussion, collect action points, especially when something scores less than 4.
- Calculate the average score, combine your action points into a single action plan, and send it to your stakeholders.
Development
General rules
- Conventions: Follow standard conventions for naming, function length, and style. Utilize a Linter to automatically enforce quality.
- Simplicity: Keep it simple stupid (KISS). Simpler is always better; reduce complexity as much as possible.
- Boy Scout Rule: Leave the campground cleaner than you found it. Continuously improve the codebase with every commit.
- Root Cause: Always find and address the root cause of a problem instead of applying quick, temporary fixes.
Design rules
- Configuration: Keep configurable data at high, abstract levels, not hardcoded in low-level components.
- Polymorphism: Prefer polymorphism over if/else or switch/case statements for more flexible and maintainable code.
- Reconfigurability: Prevent over-configurability to avoid adding unnecessary complexity to the system.
- Dependency Injection: Use dependency injection to decouple components, making them easier to manage, test, and reuse.
- Law of Demeter: A class should know only about its direct dependencies, reducing coupling between objects.
- Types: Utilize static typing where possible; avoid using generic or
types to catch errors early.any
Understandability tips
- Consistency: Be consistent in your coding style. If you do something a certain way, do all similar things in the same way.
- Explanatory Variables: Use explanatory variables to make the code more readable and self-documenting.
- Value Objects: Prefer dedicated value objects to primitive types (like strings or integers) to add meaning and constraints.
- Logical Dependency: Avoid writing methods that work correctly only depending on something else in the same class.
- Negative Conditionals: Avoid negative conditionals (
) as they are harder for the human brain to process.if (!condition)
Names rules
- Descriptive Names: Choose descriptive and unambiguous names for variables, functions, and classes.
- Meaningful Distinctions: Make meaningful distinctions in naming; avoid generic names like
ordata
.info
- Pronounceable Names: Use names that are easy to pronounce to facilitate team communication.
- Searchable Names: Use names that are easy to search for within the codebase, avoiding single-letter variables.
- Named Constants: Replace magic numbers with named constants to improve clarity and maintainability.
- No Encodings: Avoid unnecessary encodings. Don't append prefixes or type information to variable names.
Functions rules
- Small: Keep your functions small and focused on a single task.
- One Thing: Functions should do one thing and do it well.
- Descriptive Names: Use descriptive names for functions that clearly state their purpose.
- Fewer Arguments: Prefer fewer arguments in functions to make them easier to understand and test.
- Side Effects: Functions should have no side effects, or as few as possible, to prevent unexpected behavior.
- No Flag Arguments: Don't use flag arguments. Split the method into several independent methods instead.
Comments rules
- No Noise: Don't add obvious comments that just repeat what the code does.
- Remove Code: Don't comment out old code. Simply remove it, as version control has the history.
- Clarification: Use comments to provide clarification for complex or non-intuitive code.
- Warnings: Use comments to warn other developers of important consequences or to clarify a design decision.
Source code structure
- Vertical Separation: Separate different concepts vertically to improve readability.
- Close Dependencies: Dependent functions should be placed close to each other in the file.
- Similar Functions: Group functions that perform similar tasks close together.
- Downward Flow: Structure your code so it reads like a top-down narrative.
- Variable Proximity: Declare variables as close to their usage as possible.
- Short Lines: Keep lines of code reasonably short to improve readability.
- Whitespace: Use whitespace effectively to associate related elements and separate unrelated ones.
- Indentation: Never break indentation, as it is crucial for understanding the code's structure.
Objects and data structures
- Base Class Ignorance: A base class should have no knowledge of its derivative or child classes.
- Non-Static Methods: Prefer non-static methods over static ones for better testability and flexibility.
- Many Functions: It is better to have many small, specific functions than one large function with complex logic.
- Single Responsibility: Objects and data structures should have a single, well-defined purpose.
- Small: Objects and classes should be small and focused.
Code smells
- Rigidity: The software is difficult to change, where a small modification causes a cascade of other changes.
- Fragility: The software breaks in many unexpected places after a single change.
- Immobility: Parts of the code are difficult to reuse in other projects due to high coupling and risk.
- Needless Complexity: The design contains elements that are not currently useful but are included for future needs.
- Needless Repetition: The same code structure is repeated in multiple places, violating the DRY (Don't Repeat Yourself) principle.
- Opacity: The code is hard to understand, making it difficult to maintain and extend.
Testing
- Unit tests Most important functions have to be covered with unit tests
- Automated tests Most repietetive and never changing parts of the system have to be covered with automated testing
Architecture
- Documentation: Document your backend endpoints thoroughly; you will be thankful in the future (SwaggerUI, tags, examples).
- Statelessness: Design your backend to be stateless so you can quickly and easily scale it horizontally.
- Automation: Automate repetitive daily tasks. Implement CI/CD pipelines and automated linters.
- Secrets Management: Separate your secrets (API keys, passwords) from the codebase and manage them securely.
- Local Development: Ensure your infrastructure is easy to set up and run locally. Utilize tools like Docker and Docker Compose.
- Observability: Make your infrastructure observable on both the front end and back end with tools for monitoring, logging, and analytics.
- Smart Logging: Implement structured and smart logging to allow you to find the root cause of issues quickly.
- Testing: Enforce local and staging testing before any deployment to the backend. Never deploy directly to production.
- Scalability Strategies: Plan for growth with techniques like load balancing, caching layers (e.g., Redis), database optimization (e.g., indexing, sharding), and horizontal scaling to handle increased traffic without performance degradation.
- Backup and Disaster Recovery: Establish automated backups of data and configurations, along with tested recovery procedures, to minimize downtime and data loss in case of failures or disasters.
- Cost Optimization: Monitor and optimize resource usage (e.g., in cloud environments) through right-sizing, reserved instances, and auto-scaling to control expenses while maintaining efficiency.
Project Management
- Team Trust: Foster an environment where the team trusts each other, creating a feeling of shared responsibility and psychological safety.
- Daily Meetings: Execute daily standups to keep everyone aligned. If meetings are too long, separate them by function (e.g., dev and business).
- Code Review: Enforce a policy that nothing is merged into the main branch without a thorough code review by at least one other developer.
- Definition of Done: Establish clear criteria for when a task or story is truly complete, including testing, documentation, and code review requirements.
- Sprints: Stick with short, iterative sprints (e.g., 1-week) and conduct sprint planning at the beginning of each cycle.
- Tooling: Utilize specialized project management software like Jira, Asana, or Notion to track tasks and progress.
- Weekly Planning: Organize weekly planning sessions where the team is involved in estimating tasks and setting priorities.
- Velocity Tracking: Monitor team velocity over time and use historical data to improve sprint planning accuracy and workload management.
- Retrospectives: Conduct regular retrospectives (at least monthly) to reflect on what went well and what can be improved.
- Tech Debt: Strategically manage technical debt. Allow engineers to allocate time to address it or postpone non-critical fixes.
- Incident Reports: Implement a process for documenting production incidents with post-mortems to identify root causes and prevent recurrence.
- Roadmap Planning: Execute roadmap planning sessions every 1-2 months with all stakeholders to align on long-term goals.
- QA doucements: For manual QA testing all functionality has to be covered with test cases
Product Management
- Vision: The product has a clear and compelling vision that is understood and shared by the entire team.
- Strategy: There is a well-defined product strategy that outlines the target market, goals, and competitive positioning.
- Roadmap: The product roadmap is regularly updated, prioritized based on strategic goals, and transparent to all stakeholders.
- User-Centricity: The team consistently gathers and analyzes user feedback through various channels to inform product decisions.
- Customer Development: Conduct direct customer interviews and discovery sessions to deeply understand user problems before building solutions.
- Data-Informed Decisions: Key Performance Indicators (KPIs) are defined, tracked, and used to measure success and make informed choices.
- Product Analytics: Implement tools and processes for tracking user behavior, product usage patterns, and engagement metrics.
- Experimentation Framework: Establish A/B testing capabilities and feature flagging to validate hypotheses before full rollout.
- Market Awareness: The team maintains a strong understanding of the competitive landscape and emerging market trends.
- Stakeholder Alignment: There is strong alignment and communication between product, engineering, marketing, and other stakeholders.
- Go-to-Market: There is a clear and effective plan for launching new features and products to the market.
- Value Proposition: The product's value proposition is clearly articulated, understood, and communicated.
- Accessibility & Compliance: Ensure products meet accessibility standards (WCAG) and comply with relevant regulatory requirements (GDPR, etc.).
- Backlog Health: The product backlog is well-managed, estimated, and contains clear, actionable user stories.
HR
- Recruitment: There is a structured and efficient process for hiring that includes guidance for initial resume evaluation, automated self-testing and interview process.
- On-boarding: There is a standardized on-boarding process that includes company policies, processes, intro to the team, local development setup etc.
- Knowledge Sharing: Organize regular sessions for tech talks, demos, or documentation reviews to prevent knowledge silos and promote continuous learning.
- Growth-plan: Compensation and benefits packages are getting reviewed at least every year and are based on employee performance and personal growth plan.
- Performance: A clear system for performance management is in place, including regular feedback, goal setting, and career development.
- Culture: Proactive efforts are made to foster a positive and inclusive company culture that promotes high employee engagement.
- Hobbies: Outside of work activities are getting organized to build relationships between team members outside of work.
- Vacations: System of accumulated vacation or infinite day offs is implemented and team members get at least 3 weeks of day offs per year with at least 2 full week vacations.
- Exit Process: Implement a structured offboarding process including knowledge transfer, exit interviews, and feedback collection to improve retention.
- Human Risks: : Regularly evaluate human-related risks, such as burnout, phishing, key person dependencies, skill gaps, or turnover, and implement mitigation strategies like workload balancing and succession planning.
If you need any clarification or are seeking help over executing or reacting to the health check, drop me a message at yev.rachkovan@gmail.com.