Skip to main content

Engineering

The Engineering group manages the technical aspects of creating and sustaining digital products. At a very high level, responsibilities include but are not limited to:

  1. Code – the human-readable source code for our applications.
    Maintained by application engineers.

  2. Package definition – files and settings that describe how code should be packaged for an environment.
    Shared responsibility between both application and infrastructure/operations engineers.

  3. Infrastructure – the servers and systems that run our applications.
    Maintained by infrastructure/operations engineers.

Direction

Software is always moving forward. To keep us on the right track, our direction will be outlined annually for every fiscal year (July–June, not January–December), starting with FY 2023.

Principles

These principles are meant to capture ideas that are important to engineering at Norton rather than principles that are more generally applicable. They are aspirational rather than actionable, meaning they are principles that we should strive for and use to guide our work and decisions, rather than concrete guidelines that all engineers should follow.

1. Make it work

At the end of the day, an engineer helps people accomplish their goals with code. The details of how we engineer those solutions are important to us, as they should be, but at a high level, we've accomplished our goal if it's working for our customers.

  • Prioritize team autonomy over uniformity to avoid organizational red tape.
  • Cutting scope is never a compromise—the thing we're building can and should do less.
  • Don't be afraid to throw it away and start over.
  • Resist the delusion of reuse and focus on solving the more immediate problem.
  • The best solutions do one thing well. If we can't succinctly and clearly describe what that one thing is, we may need to rethink our design.
  • Norton engineers should never be dismissive of other peoples' problems. Engineers are seen as problem solvers—a perception we want to cultivate, not discourage. But that means we're sometimes put in the uncomfortable position of being asked to solve a problem that's not relevant to us. Rather than being dismissive, we should redirect them to the right resource, or pull in our manager if we're not sure who can help.

2. Engineer for inclusion

We should strive to make engineering more accessible to everyone because it's already hard, and we don't need to make it any harder.

  • Avoid solutions that feel like magic.
  • Write documentation that will make sense to junior developers. Even better, write code that will make sense to junior developers.
  • Be internally open by default. "Be open about as many things as possible. By making information [open], we can reduce the threshold to contribution and make collaboration easier." (Source: GitLab Values | Transparency)
    • Note: Norton is not an open core company, so open in this context means open to other Nortonians, not open to the public.
  • Abstraction layers should help other engineers understand how your design works. Conversely, abstraction layers that reduce understandability should be avoided unless performance is seriously impacted, or the design is operating in a highly constrained environment (both of these conditions are rare in Norton's world).
    • Put another way: repetitive, understandable code is usually better than DRY code that is hard to understand.
    • Related: The WET Codebase (presentation)
  • Learn in public whenever possible. One of the best things about being an engineer is that we're always learning, but that's not always transparent to other engineers or other non-engineer colleagues. Learning in public can help demystify our work, create a more inclusive work environment, and give everyone a better sense of what it is that we do.
    • Note: "public" in this sense may mean working through a problem on a call live with teammates or presenting a learning journey to the department, not necessarily creating a blog or YouTube channel.

3. Think like a designer

Software developers and DevOps engineers design systems with code and architecture. Whether intentional or not, every choice you make to name a variable or function, choose a tool, or structure a folder is a design choice. When we think more like a designer, we make those choices intentional, enabling us to build faster, write less code, and better align with non-engineering team members.

  • Start with the problem.
    • When creating technical designs, start by concisely and completely articulating the problem that the design is meant to solve. If it's difficult to articulate the problem, it will be nearly impossible to assess the solution.
  • Focus on the interface.
    • UI/UX designers build visual interfaces and experiences for end-users. We often build interfaces for other developers, such as APIs (application programming interface), CLIs (command line interface), and even a function is simply a discrete input/output interface. Thinking like a designer encourages us to think more about the needs of the people using our interfaces, which can lead to better code design and maintainability by making sure our solutions do what our users expect.
  • There is no such thing as user error.
    • Whether we're creating a microservice that's only meant to be used by one small group of Norton engineers or a frontend interface that's meant to be used by our customers, those users will almost definitely use our solutions in a way we didn't expect. Rather than responding to that by telling them that they are using it "wrong," take it as an opportunity to better understand how the solution can be improved.
    • Example: a developer used an API wrong because the documentation was somewhere they didn't look. Take this as an indicator that the documentation should be closer to the code.
    • Example: a developer used a function the wrong way, but that wasn't immediately apparent to them because the function did multiple things. Take this as an opportunity to use functional design to avoid side effects.
  • Essential reading: Design Thinking Explained

Guidelines

Guidelines are the concrete, actionable, and opinionated protocols, standards, and conventions that we should all follow whenever possible. They are meant to be lightweight, helpful, derive from our principles, and help us move in the right direction. Guidelines that don't meet these requirements should be reworked or removed.

  • Managing code – tips, standards, and expectations for how code is managed at Norton.
  • Naming conventions – naming things is hard. Let's make it a little bit easier.
  • Technical decision making [to come]
  • Technical RFCs [to come]
  • Communication [to come]
    Norton engineering should follow all Digital Product communication principles.

Practices

Engineering practices describe how we do our work. They are more conceptual than actionable—mental models for doing work, rather than concrete processes like scrum. They are subject to changes, and should always in support of broader principles and goals.

DevOps

DevOps—development operations—describes a set of practices and principles that prioritizes shared responsibility across most development-related functions, autonomous teams to reduce handoffs and bottlenecks, and process automation to reduce toil. While DevOps is also a role, all of us are involved in DevOps in some way.

The DevOps lifecycle

Just as Agile practices like scrum enable teams to work more quickly on the planning and creation stages of development, DevOps helps teams work more quickly across the entire lifecycle of a product, commonly referred to as the DevOps lifecycle.

The following graphic (source) outlines some of the common functions of the DevOps lifecycle.

An infinity symbol shows different stages of the DevOps lifecycle. Plan, create, verify, and package are within the dev loop, while monitor, configure, and release are within the ops loop. Package is in the center.

In general, Norton engineering roles are designed to tackle every stage ("responsibility") of this lifecycle, as are many roles outside of engineering.

  • The developer roles like tech lead and developer are designed to address the left-hand side of the lifecycle.
  • The infrastructure/operations roles like DevOps engineer are designed to address the right-hand side of the lifecycle.
  • The areas in the middle are where we collaborate most often with each other and with non-engineering contributors to solve problems.

Continuous delivery

Very closely related to DevOps practices, continuous delivery is "a software development discipline where you build software in such a way that the software can be released to production at any time." (Martin Fowler, 2013). Norton engineering achieves this discipline by following code standards designed for it and working closely with everyone involved in the DevOps lifecycle.

Roles

Technical Lead

  • Works with the developers to evaluate the technical options and decide the best way to turn the high-level business requirements into a technical solution
  • Creates delivery plan and scheduling for development team based on high level business project timeline
  • Collaborates with the Development Team to create task planning
  • Manages risk and any issues as they arise, collaborating with cross team as required to resolve them
  • Monitors and ensures appropriate involvement and communication between required members of the multi-disciplinary team
  • Ensures the business and technical components of the solution collectively provide a cohesive whole for the business
  • Participates in cross-functional design meetings and serves as technical point person for team
  • Works with DevOps to ensure environments are available and meet requirements (as necessary)
  • Works with Project Manager to schedule and manage deployments

Developer

  • Performs coding and configuration changes to meet the needs of the sprint and aligned with the overall architecture goals/vision/standard
  • Writes and performs unit-testing
  • Provides estimates on development work items
  • Self-organizes to determine ticket assignments
  • Collaborates with the rest of the team
  • Stays focused on sprint goals and commitments
  • Escalates roadblocks as they are encountered to the Project Manager
  • Creates and updates all relevant artifacts (tickets, technical documentation, existing unit test cases)

DevOps Engineer

  • Responsible for application delivery pipeline
  • Establishes continuous integration practices
  • Establishes continuous delivery practices
  • Monitors application and infrastructure performance
  • Communicates regularly with Development to correct issues and establish best practices
  • Involved in system architecture design

Footnotes

  1. "continuous deployment" describes the practice of automatically deploying changes to production, whereas "continuous delivery" describes the ability or capacity to deploy to production at any time. The distinction is important because we do not practice continuous deployment, though some teams may choose to do so once they are confident in their delivery capabilities.