Sunday, October 27, 2019

Refactoring toward deeper insight

Success developing useful models comes down to three points:

  1. Sophisticated domain models are achievable and worth the trouble.
  2. They are seldom developed except through an iterative process of refactoring, including close involvement of the domain experts with developers interested in learning about the domain.
  3. They may call for sophisticated design skills to implement and to use effectively.
Eric Evans, "Refactoring Toward Deeper Insight", in Domain-Driven Design: Tackling Complexity in the Heart of Software, 188.

Managing projects

Doesn't agile software development get rid of the need for project management? No. Agile software development is a great way to think about work because it forces you to focus on breaking tasks down into smaller chuncks, planning those smaller chuncks out, and delivering value incrementally instead of all at once. None of this means that you don't need to understand how to do project management. You'll have projects that for whatever reason can't be completed in a single sprint, or even two small sprints. You'll need to estimate project length for your management team, and give some detail on why you believe things will take that long. There are some projects, usually described by words like infrastructure, platform, or system, that require architecture or significant advanced planning. When faced with this kind of project, which includes many unknowns and relatively hard deadlines, you will find it doesn't fit so well into the standard agile process.

Project management isn't something that needs to happen in detail for every single effort, and it's overused in some organizations. I don't even like hiring project managers because they often act as a crutch for engineers to use instead of learning to think through their future work and ask real questions about what they're doing and why, and their presence means that you have more waterfall-style projects instead of an agile process. Still, project management has to happen, and as tech lead, you should be doing it when it is needed, especially for deeply technical projects.

Ultimately, the value of planning isn't that you execute the plan perfectly, that you catch every detail beforehand, or that you predict the future; it's that you enforce the self-discipline to think about project in some depth before diving in and seeing what happens. A degree of forethought, in places where you can reasonably make predictions and plans, is the goal. The plan itself, however accurate it turns out, is less important than spending time on the act of planning.

Camille Fournier, "Tech Lead", in The Manager's Path: A Guide for Tech Leaders Navigating Growth and Change, chapter 3.

Sunday, October 13, 2019

Repositories

The goal of domain-driven design is to create better software by focusing on a model of the domain rather than the technology. By the time a developer has constructed an SQL query, passed it to a query service in the infrastructure layer, obtained a result set of table rows, pulled the necessary information out, and passed it to a constructor or FACTORY, the model focus is gone. It becomes natural to think of objects as containers for the data that the queries provide, and the whole design shifts toward a data-processing style. The details of the technology vary, but the problem remains that the client is dealing with technology, rather than model concepts.

Therefore:

For each type of object that needs global access, create an object that can provide the illusion of an in-memory collection of all objects of that type. Set up access through a well-known global interface. Provide methods to add and remove objects, which will encapsulate the actual insertion or removal of data in the data store. Provide methods that select objects based on some criteria and return fully instantiated objects or collections of objects whose attribute values meet the criteria, thereby encapsulating the actual storage and query technology. Provide REPOSITORIES only for AGGREGATE roots that actually need direct access. Keep the client focused on the model, delegating all object storage and access to the REPOSITORIES.

REPOSITORIES have many advantages, including the following:

  • They present clients with a simple model for obtaining persistent objects and managing their life cycle.
  • They decouple application and domain design from persistence technology, multiple database strategies, or even multiple data sources.
  • They communicate design decisions about object access.
  • They allow easy substitution of a dummy implementation, for use in testing (typically using an in-memory collection).

Working within your frameworks

In general, don't fight your frameworks. Seek ways to keep the fundamentals of domain-driven design and let go of the specifics when the framework is antagonistic. Look for affinities between the concepts of domain-driven design and the concepts in the framework. This is assuming that you have no choice but to use the framework. [...] If you have the freedom, choose frameworks, or parts of frameworks, that are harmonious with the style of design you want to use.

The relationship with FACTORIES

A FACTORY handles the beginning of an object's life; a REPOSITORY helps manage the middle and the end.

[...] In this domain-driven view of the design, FACTORIES and REPOSITORIES have distinct responsibilities. The FACTORY makes new objects; the REPOSITORY finds old objects. The client of a REPOSITORY should be given the illusion that the objects are in memory. The object may have to be reconstituted (yes, a new instance may be created), but it is the same conceptual object, still in the middle of its life cycle.

These two views can be reconciled by making the REPOSITORY delegate object creation to a FACTORY, which (in theory, though seldom in practice) could also be used to create objects from scratch.

This clear separation also helps by unloading all responsibility for persistence from the FACTORIES. A FACTORY's job is to instantiate a potentially complex object from data. If the product is a new object, the client will know this and can add it to the REPOSITORY, which will encapsulate the storage of the object in the database.

One other case that drives people to combine FACTORY and REPOSITORY is the desire for "find or create" functionality, in which a client can describe an object it wants and, if no such object is found, will be given a newly created one. This function should be avoided. It is a minor convenience at best. A lot of cases in which it seems useful go away when ENTITIES and VALUE OBJECTS are distinguished. A client that wants a VALUE OBJECT can go straight to a FACTORY and ask for a new one. Usually, the distinction between a new object and an existing object is important in the domain, and a framework that transparently combines them will actually muddle the situation.

Designing objects for relational databases

  • When the database is being viewed as an object store, don't let the data model and the object model diverge far, regardless of the powers of the mapping tools. Sacrifice some richness of object relationships to keep close to the relational model. Compromise some formal relational standards, such as normalization, if it helps simplify the object mapping.
  • Processes outside the object system should not access such an object store. They could violate the invariants enforced by the objects. Also, their access will lock in the data model so that it is hard to change when the objects are refactored.
Eric Evans, "The Life Cycle of a Domain Object", in Domain-Driven Design: Tackling Complexity in the Heart of Software, 148-160.

Thursday, October 10, 2019

Mentoring

Tips for the manager of a mentor

If the mentor does a good job, her productivity may slow down some during the mentoring period. If you've got an engineer involved in a time-sensitive project, you may not want to push him into mentoring at the same time. Because this is an additional responsibility, treat it as you would any other important additional responsibility you might hand out. Look for someone that you believe can succeed in the role, and who wants to distinguish herself beyond her coding ability.

[...] Because the outcome can be hard to quantitatively measure, emotional labor is often dismissed as less important work than writing software. It's assumed to be something that should just be provided without financial recognition. I'm not suggesting that you should pay people extra money to serve as mentors, but they need to be recognized for the work they put in, and the mentor should be treated as a first-class citizen with respect to other responsibilities the person might have. As I said before, plan for it, and provide the mentor the time to do the job right.

Key takeaways for the mentor: listen and speak their language

Senior engineers can develop bad habits, and one of the worst is the tendency to lecture and debate with anyone who does not understand them or who disagrees with what they are saying. To work successfully with a newcomer or a more junior teammate, you must be able to listen and communicate in a way that person can understand, even if you have to try several times to get it right. Software development is a team sport in most companies, and teams have to communicate effectively to get anything done.

Camille Fournier, "Mentoring", in The Manager's Path: A Guide for Tech Leaders Navigating Growth and Change, chapter 2.