Archive for the ‘DDD’ Category

Linq to SQL and the Repository Pattern

Monday, September 27th, 2010

Earlier this month, I posted Entity Framework and the Repository Pattern. Mickey posted that code on GitHub, along with his own Linq to SQL implementation.

For those new to Git, here’s how you can get Mickey’s repository:

Mickey took the time to complete the story for me. I posted only enough code to make my point (which was, BTW, that the Repository Pattern takes more work than you might expect). Mikey reverse engineered the database that I used for my example, and even populated it with data from this blog. Wow!

Now let’s review his work.

Tests

image Mickey not only includes unit test (the motivation for my original post), but also integration tests. Just open the solution and hit Ctrl+R, A to run all tests. If you find that the tests don’t deploy the database file, double-click the Local.testsettings file and add the dbf to the Deployment section. I found that the tests passed before I turned on code coverage, but then I had to make this change.

I enabled code coverage and found that he achieves 92%-100% in all modules except for the generated code. The reason that it is not 100% is mostly due to the fact that my original tests didn’t add anything to the repository.

Two sets of data types

The goal of the original post was not persistence ignorance, it was testing. But persistence ignorance is often a reason for using the Repository Pattern. Mickey’s solution is not persistence ignorant, either.

If you look in the Data project, you will see NoteworthyEntitiesL2SModel.dbml and NoteworthyEntitiesEFModel.edmx. That is, he used both EF and L2S to generate models from the database. This created two separate sets of data types.

This division necessarily permeates the solution, since those generated data types are exposed from the repository. As a result, he has a separate memory provider for each data access technology. The EF memory provider expects ObjectContext and ObjectQuery. The L2S memory provider replaces those with DataContext and Table.

Both of the memory providers have unit tests. They distinguish between the two by namespace. EF and L2S use different strategies for naming associative tables, but other than that the code looks the same.

In practice, you will typically choose one data access technology, so this lack of persistence ignorance is not a problem. But if it bothers you, please look into POCO support for EF and L2S to see if there’s a way to remove the dependency upon the data access technology.

Thank you, Mickey

I am quite impressed with the effort that Mickey put into packaging this example and making it available to us. He took code that only worked on my machine and filled in the missing components so that we can all run the tests. And he took what was working for Entity Framework and ported it to Linq to SQL so that you have the choice. Now, either way you go, you can test your data services.

Thanks, man.

Entity Framework and the Repository Pattern

Thursday, September 9th, 2010

When I’ve asked how to unit test Entity Framework, the best answer was “use the Repository pattern to encapsulate your EF code” (thanks Andrew Peters). I recently asked the same thing about RIA Services. Mike Brown responded with the same advice, even going so far as to spend a couple of hours with me on Live Meeting.

Since all you gotta do is implement the Repository Pattern, it should be easy, right? Let’s take a look at a minimalist implementation.

Inject the implementation

To support unit testing, we need to be able to swap out our implementation. At the top level, the consumer of a repository begins a unit of work. So we’ll inject a unit of work factory.

public interface IUnitOfWorkFactory
{
    IUnitOfWork Begin();
}
public class NoteworthyService
{
    private IUnitOfWorkFactory _unitOfWorkFactory;

    public NoteworthyService(IUnitOfWorkFactory unitOfWorkFactory)
    {
        _unitOfWorkFactory = unitOfWorkFactory;
    }
}

Identify the repository

In DDD we create one repository per aggregate root, which is the entity from which you begin the query. In EF, entities exist in a container. So we’ll take two steps to get the repository via the container.

public interface IUnitOfWork : IDisposable
{
    IContainer<TContainer> UsingContainer<TContainer>()
        where TContainer : ObjectContext, new();
}

public interface IContainer<TContainer> : IDisposable
{
    IRepository<TEntity> GetRepository<TEntity>(Func<TContainer, ObjectQuery<TEntity>> repositorySelector)
        where TEntity : EntityObject;
}

Provide a specification

The second half of the Repository Pattern is the Specification. A specification identifies which entities to pull from the repository. In Linq, we use lambdas for that. So a repository should be able to give you back some entities when given a lambda.

public interface IRepository<TEntity>
{
    IQueryable<TEntity> GetSatisfying(Expression<Func<TEntity, bool>> specification);
    void Add(TEntity entity);
}

Query the repository

With those interfaces in place, here’s what a query looks like.

public List<Article> GetArticlesByTopic(string topicName)
{
    using (var unitOfWork = _unitOfWorkFactory.Begin())
    {
        return unitOfWork.UsingContainer<NoteworthyEntities>().GetRepository(container => container.Articles)
            .GetSatisfying(article => article.Topics.Any(topic => topic.TopicName == topicName))
            .ToList();
    }
}

Implement in memory

For unit testing, we implement the repository interfaces using in-memory lists.

public class MemoryUnitOfWorkFactory : IUnitOfWorkFactory
{
    private MemoryUnitOfWork _unitOfWork = new MemoryUnitOfWork();

    public IUnitOfWork Begin()
    {
        return _unitOfWork;
    }
}

public class MemoryUnitOfWork : IUnitOfWork
{
    private Dictionary<Type, object> _containerByType = new Dictionary<Type, object>();

    public IContainer<TContainer> UsingContainer<TContainer>()
        where TContainer : ObjectContext, new()
    {
        object container;
        if (!_containerByType.TryGetValue(typeof(TContainer), out container))
        {
            container = new MemoryContainer<TContainer>();
            _containerByType.Add(typeof(TContainer), container);
        }
        return (IContainer<TContainer>)container;
    }

    public void Dispose()
    {
    }
}

public class MemoryContainer<TContainer> : IContainer<TContainer>
    where TContainer : ObjectContext, new()
{
    private Dictionary<Type, object> _containerByType = new Dictionary<Type, object>();

    public IRepository<TEntity> GetRepository<TEntity>(Func<TContainer, ObjectQuery<TEntity>> repositorySelector)
        where TEntity : EntityObject
    {
        object container;
        if (!_containerByType.TryGetValue(typeof(TEntity), out container))
        {
            container = new MemoryRepository<TEntity>();
            _containerByType.Add(typeof(TEntity), container);
        }
        return (IRepository<TEntity>)container;
    }

    public void Dispose()
    {
    }
}

public class MemoryRepository<TEntity> : IRepository<TEntity>
    where TEntity : EntityObject
{
    private List<TEntity> _entities = new List<TEntity>();

    public IQueryable<TEntity> GetSatisfying(Expression<Func<TEntity, bool>> specification)
    {
        return _entities.Where(specification.Compile()).AsQueryable();
    }

    public void Add(TEntity entity)
    {
        _entities.Add(entity);
    }
}

And here’s what a unit test looks like.

[TestClass]
public class NoteworthyServiceTest
{
    private NoteworthyService _noteworthyService;

    [TestInitialize]
    public void Initialize()
    {
        IUnitOfWorkFactory memory = new MemoryUnitOfWorkFactory();

        IRepository<Article> articlesRepository = memory.Begin()
            .UsingContainer<NoteworthyEntities>()
            .GetRepository(container => container.Articles);
        Topic ddd = new Topic()
        {
            TopicName = "ddd"
        };
        Topic corresopndence = new Topic()
        {
            TopicName = "correspondence"
        };
        Article efRepository = new Article()
        {
            Title = "Entity Framework and the Repository Pattern"
        };
        efRepository.Topics.Add(ddd);
        Article correspondenceLaunch = new Article()
        {
            Title = "Correspondence Launch"
        };
        correspondenceLaunch.Topics.Add(corresopndence);
        Article correspondenceDDD = new Article()
        {
            Title = "Correspondence and DDD"
        };
        correspondenceDDD.Topics.Add(ddd);
        correspondenceDDD.Topics.Add(corresopndence);

        articlesRepository.Add(efRepository);
        articlesRepository.Add(correspondenceLaunch);
        articlesRepository.Add(correspondenceDDD);

        _noteworthyService = new NoteworthyService(memory);
    }

    [TestMethod]
    public void QueryReturnsArticles()
    {
        var articles = _noteworthyService.GetArticlesByTopic("ddd").ToArray();

        Assert.AreEqual("Entity Framework and the Repository Pattern", articles[0].Title);
        Assert.AreEqual("Correspondence and DDD", articles[1].Title);
    }
}

Implement with Entity Framework

Finally, we implement the real thing using Entity Framework.

public class EntityFrameworkUnitOfWorkFactory : IUnitOfWorkFactory
{
    public IUnitOfWork Begin()
    {
        return new EntityFrameworkUnitOfWork();
    }
}

public class EntityFrameworkUnitOfWork : IUnitOfWork
{
    private Dictionary<Type, IDisposable> _containerByType = new Dictionary<Type, IDisposable>();

    public IContainer<TContainer> UsingContainer<TContainer>()
        where TContainer : ObjectContext, new()
    {
        IDisposable container;
        if (!_containerByType.TryGetValue(typeof(TContainer), out container))
        {
            container = new EntityFrameworkContainer<TContainer>();
            _containerByType.Add(typeof(TContainer), container);
        }
        return (IContainer<TContainer>)container;
    }

    public void Dispose()
    {
        foreach (var container in _containerByType.Values)
            container.Dispose();
    }
}

public class EntityFrameworkContainer<TContainer> : IContainer<TContainer>
    where TContainer : ObjectContext, new()
{
    private TContainer _container;

    public EntityFrameworkContainer()
    {
        _container = new TContainer();
    }

    public IRepository<TEntity> GetRepository<TEntity>(Func<TContainer, ObjectQuery<TEntity>> repositorySelector)
        where TEntity : EntityObject
    {
        return new EntityFrameworkRepository<TContainer, TEntity>(_container, repositorySelector(_container));
    }

    public void Dispose()
    {
        _container.Dispose();
    }
}

public class EntityFrameworkRepository<TContainer, TEntity> : IRepository<TEntity>
    where TContainer : ObjectContext, new()
    where TEntity : EntityObject
{
    private TContainer _container;
    private ObjectQuery<TEntity> _objectQuery;

    public EntityFrameworkRepository(TContainer container, ObjectQuery<TEntity> objectQuery)
    {
        _container = container;
        _objectQuery = objectQuery;
    }

    public IQueryable<TEntity> GetSatisfying(Expression<Func<TEntity, bool>> specification)
    {
        return _objectQuery.Where(specification);
    }

    public void Add(TEntity entity)
    {
        _container.AddObject(_objectQuery.Name, entity);
    }
}

Analysis

This is the smallest implementation of the Repository pattern that I could come up with. It is obviously not feature complete. For example, it does not implement Delete, nor does it allow you to specify eager loading with Include. There are other implementations that are bigger, but I doubt that there could be one smaller. Even at this size, this doesn’t qualify as “all you need to do is”.

One benefit of the Repository pattern is supposed to be that it abstracts the persistence mechanism. But this implementation returns EntityObjects, which are a distinctly Entity Framework-ish data type. I could try for a POCO compliant implementation to solve that problem.

Because this implementation requires EntityObjects, it could never work with RIA Services. I would have to write a different Repository implementation to unit test my client code.

And finally, Entity Framework does some things that the in-memory repository does not. My unit tests can’t verify that I’m using EF correctly. For example, Entity Framework does eager loading if I explicitly request it. The in-memory implementation always has all navigation properties populated. Because of this difference, I can’t verify with a unit test that I have included all of the required navigations.

Conclusion

All of this leads me to conclude that the Repository pattern is not the best way to add testability to an untestable framework. The framework needs to be testable from the beginning. If Entity Framework had provided an in-memory implementation for testing, then I could test my use of EF, including eager loading.

By the way, Correspondence does in fact provide an in-memory implementation for unit testing. Please go through the lessons to see what I think a testable framework should look like.

Don’t abdicate the ubiquitous language

Friday, October 16th, 2009

The Ubiquitous Language of Domain Driven Design is a call for developers and domain experts to communicate openly, instead of erecting false barriers of obfuscation. It admonishes developers not to put pattern names or technical terms into the domain model.

Yet it also does not suggest that developers should abdicate the language to the domain experts. Imprecise language cannot be tolerated. When a domain expert uses it, it is the developers' duty to correct it.

The following four-letter words are indicators of imprecise language:

  • Type
  • State/Status
  • Code
  • Text

Type
When a domain expert uses the term "type", they are trying to classify objects in a meaningful way. Work items, for example, can either be bugs or enhancements. Orders can be purchase orders, quotes, or returns.

Domain experts will often model type as an attribute of a single entity. The behavior of that entity is sometimes dependent upon this "type" attribute. Entities of one type are treated differently than entities of another type, but only in certain situations. Pricing is run on purchase orders and quotes, for example, but not on returns.

When a developer sees the word "type", they immediately attach some assumptions to it. An entity can only be an instance of one concrete type. Its type is determined at the time of creation and cannot change during its lifetime. Type determines the attributes and behaviors of the object. These are not the assumptions that the domain expert means to imply. A work item may be entered as a bug, but later determined to be an enhancement. The work item type can change. If we modeled this domain using a static type system, such a change would be impossible.

It would be more useful to identify the reason that objects have different "types". A work item is either a bug or an enhancement because of the feature set it affects: existing features or new features. Orders are purchase orders, quotes, or returns because of their intent. Let's use the more precise terms "feature set" and "intent", and not the overloaded term "type" to represent these attributes of an entity.

State and Status
When a domain expert uses the term "state" or "status", they are trying to express a workflow. A work item is in the "new", "fixed", or "closed" state. An order status can be "received", "processed", or "shipped".

State and status are modeled as attributes of an entity. But they are in truth events in the workflow. As an entity moves through a workflow, the intent is not so much to modify that entity. Rather, it is to gather information about the entity. This is a concept discussed by Greg Young in Unshackle Your Domain. The events should themselves be part of the domain model.

States are only meaningful within a context. But entities are often found at the intersection of several contexts. An entity can be in several states simultaneously, depending upon what question is being asked. But if "state" is an attribute of an entity, it can have only one value. This can lead to a combinatorial explosion of states that attempt to simultaneously represent two or more contexts.

It would be more useful to identify the events that can occur within a workflow, and ask questions in terms of that history.

Code
When a domain expert uses the term "code", they are usually calling out an implementation detail about how a problem is currently solved. Our ordering system currently has a "signal code" attached to a product. This three-letter code is used to signal the system that special processing needs to take place.

For example, one signal code indicates that the product is a controlled substance, and therefore requires DEA license validation. Another signal code indicates that the product is drop shipped, so different inventory behavior is applied.

The problem with codes is that they are already entrenched. It is hard to convince a domain expert that there is a problem. Telling them that codes represent different dimensions is too abstract. But if you give them a concrete example, they already have an answer for it.

"What if a product is both a controlled substance and drop shipped?"

"Are you crazy! We don't drop ship controlled substances!"

It would be more useful to identify the dimensions along which entities vary and make those independent attributes. A product has licensing requirements, and also has an inventory strategy. Interactions among those various dimensions can be captured as business rules.

Text
Unless the domain is specifically about books, the term "text" is often used to represent a note to be displayed in a specific place. A customer service representative can enter "footer text" when placing an order, which appears on the footer of the invoice.

These notes are important to capture, as the primary purpose of any system is to facilitate communication among its users. But the notes should be named according to their purpose, not according to where they appear. Formats change over time, and are not an appropriate concept for the domain model. Our "footer text" for example no longer appears on the footer of the invoice. It would be more useful to call it "invoice instructions".

The four-letter words listed here are just the most egregious examples of imprecise language. There are many other examples that could be cited. As a developer, it is your job to ask questions when you see them. You need more information about what these terms mean in context. If you have to ask a domain expert to elaborate, then they have not chosen a precise term. Once they do elaborate, suggest that they use that term instead.

Merit vs. Credit

Thursday, October 15th, 2009

Domain Driven Design (DDD) advocates for a ubiquitous language. This is more than just a fancy way of saying that developers and domain experts should use the same words. It's more than a glossary or a dictionary.

I've fallen victim to the hubris of making up my own language that is "better" than the business'. It's a personality flaw that I fight constantly. The worst example occurred when I designed a frequent diner program for a prior employer. The business called points earned "credit". I insisted that the correct term was "merit". "Credit" is for accounting systems (like our gift card program). "Merit" is something you accrue for which you are eventually rewarded.

I debated the issue at length with the business analyst. She understood my position, but informed me that our users use the term "credit". She performed an experiment in which some potential customers were shown specs with "credit" and others with "merit". The "credit" group had fewer misunderstandings than the "merit" group. Even in the face of scientific evidence, I stood my ground. "Merit" was right, and they just needed to be educated.

The debate continued. People lined up behind The Architect claiming that "merit" was technically correct and semantically concise. Other people lined up behind The Business Analyst claiming that "credit" made more sense and did not conflict with other definitions in other contexts.

In the end, we resolved that all of the functional specifications and end user documentation would use the term "credit", while all of the technical documentation and code would use "merit". The user interface code was a mess, since it had to display "credit" but read the value from the "merit" property. For years afterward, I received questions from new developers about what was "merit" and what was "credit" and what they had to do with each other.

In this, I was wrong. My continued insistence on imposing my own language added no value. I created a situation which only bred confusion. I was correct only in proposing a new term and in soliciting additional feedback. But once the term "credit" was corroborated by our customers, I should have ended my crusade for the sake of ubiquitous language.

DDD to English dictionary

Thursday, February 5th, 2009

With apologies to Eric Evans.

What it means

  • Ubiquitous Language - Glossary
  • Unit of Work - Transaction
  • Repository - Data access component
  • Specification - Where clause
  • Service - Static method
  • Aggregate - Hierarchy
  • Intention-Revealing Interfaces - Good names
  • Anticorruption Layer - Contract

What it could mean, but doesn't

  • Ubiquitous Language - The phenomenon that development teams pick one programming language and stick with it
  • Unit of Work - The detail of your estimates: to the hour, day, or week
  • Repository - Source control
  • Specification - Requirements document
  • Service - RPC over HTTP
  • Aggregate - A filled-in diamond on a UML diagram
  • Intention-Revealing Interfaces - Ports 80 and 25
  • Anticorruption Layer - CRC

Domain Driven Design: we’re doing it wrong

Wednesday, February 4th, 2009

Several people have recommended the book Domain Driven Design by Eric Evans. I've heard it referenced on podcasts and in blogs. My technical manager informed me when I first started on my current project that the architecture was partially based on this book. It takes a while for a message to seep in, but I finally decided it was time to pick up this book.

When I saw the book cover, I was surprised. No, not by the retro cheesiness of the graphics, colors, and fonts. I was surprised because I recognized it. I had had this book on my shelf for over two years.

I bought this book from Amazon because it was paired with Software Factories. I started reading DDD shortly after finishing SF, but gave up before even getting through the preface. I found Evan's style unnecessarily verbose and obfuscated.

So the book languished on my shelf for over two years before I made the discovery that an important sub-discipline within my industry was passing me by, simply because of my disdain for one man's writing style. So I forced myself to wade through his awkward word choice, parabolic explanations, and prolonged narratives to extract the meat of the subject. And I'm glad I did.

It turns out, we're doing DDD wrong.

What is Domain Driven Design
The point of Domain Driven Design is to put all of the domain knowledge into a rich object layer. This layer captures the essential information about the problem domain, the relationships among those objects, and the responsibilities of those objects. If the domain is commerce, as it is in our system, then you have domain objects for products, orders, and shopping carts. The methods of these objects capture business knowledge, like inventory rules and regulatory restrictions.

This is very similar to the old Rumbaugh OOA&D thinking that my career started out with. We as an industry have come to think of that "look for the nouns" guidance as naive. Programs that run on computers need objects that represent computer ideas. So we have objects for windows, database connections, proxies, and sockets. If you follow the Gang of Four as I do, you'll write objects like factories, visitors, and strategies. Nouns from the real world have a hard time coexisting with these technical concepts in today's object oriented programs.

But Evans provides some guidance that allows us to draw from both of these views of objects. The domain objects are isolated from the technical objects. Patterns like Repository/Specification and Unit of Work hydrate domain objects without coupling them to persistence technology. Evans shows us how to take a set of objects that a domain expert would understand, and use them in a modern software application.

The advantage of Domain Driven Design is that domain objects become a medium of communication. Programmers and experts can talk about the domain by using the source code. Or at least, the classes and methods in the source code. If the source code does not accurately reflect the knowledge of the domain expert, then the source code is wrong. Using Evans' guidance and patterns, the domain model can be quickly refactored as developers learn more about the problem domain.

Unfortunately, the way that we have been applying Evans' guidance and patterns on our eCommerce system has made it more difficult to refactor the domain, and left us with a fairly rigid system. Here are some of the big mistakes we made.

Layered architecture does not mean tiered architecture
Evans recommends a layered architecture:

  • presentation
  • application
  • domain
  • infrastructure

The presentation layer handles UI, the application layer implements features, the domain layer captures business knowledge, and the infrastructure layer lends low-level support. This approach isolates the domain objects from technical concerns like storage and presentation. It allows the solution to be implemented in the language of the domain, instead of forcing the domain to implement those features.

Our approach was to separate these concerns into physical tiers. These tiers could be deployed to different servers in the datacenter for the benefits of security and scalability. Imagine my surprise when I get to page 114, where Evans says, "This could be a strong argument if the code actually got deployed on different servers. Usually it does not." I wasn't surprised because he told me something I didn't know; I was surprised because I knew and hadn't objected.

The fact is, we aren't going to need quite so many tiers. Yes, we are separating the presentation tier because it is hosted in SharePoint and resides in the DMZ. But besides that, the other layers -- not tiers -- can benefit from being in the same process and not being forced across machine boundaries.

SOA's "services" are not DDD's "services"
We architected our eCommerce application to be service oriented. The benefits are that isolated services are reusable and independently versionable. These are significant goals of this project, as we are building not just an eCommerce application, but a platform for all commerce in the company.

Domain Driven Design also talks about services. But a DDD service is an operation that doesn't belong to just one object. A service is still a domain concept, in that it captures domain knowledge, but it isn't an instance method on a domain object. We've exposed our services as WCF web services, when it may have been more appropriate to simply expose them as static methods in the domain layer. Only those services that external systems would want to consume should be published through WCF.

Entity Framework's "entities" are not DDD's "entities"
Evans' guidance is strongly informed by the difference between entities -- objects whose identity is important -- and value objects -- whose identity is not. His patterns talk about how to carefully rehydrate entities such that their in-memory identity matches their persistent identity (where it is important to do so). Above all, entities are first-class domain objects.

Before I joined the project, linq to SQL was rejected because it does not play well with rich domain objects. Certainly, a linq query pulls data from a record set and puts it into objects, but it does nothing to respect the identity of those objects. If you run two queries, it will happily construct two objects to represent the same ID.

The decision was made to use the Entity Framework, then in beta. The idea was that EF entities were partial classes, so domain logic could be added. The framework would handle persistence, and our code could take over from there.

As it turned out, Entity Framework is no better than linq to SQL for our purpose. The primary concern of the entity model is the mapping between record sets and objects. The entity model exists in a limbo between a good object model and a good relational model. Domain objects are, first and foremost, objects. If they have to compromise to conform to good relational design, then they fail to be good domain objects.

On the other hand, either EF or linq to SQL would make a good memento. Linq to SQL favors anonymous types, while EF favors its flavor of entity. If the persistence of domain objects handled the translation of domain objects to mementos, then either one could take it the rest of the way to the relational database.

We already had a repository and specification
The piece of advice from DDD that people most often cite is to use a pattern of Repositories and Specifications. A repository is a place to store objects when they are not in memory. A specification is a condition -- separate from the repository -- that you can use to fetch the objects you are interested in. The advantage of this pattern is that the application layer can provide the specification, the infrastructure layer the repository, and the domain objects remain blissfully unconcerned with these non-domain details.

The piece of advice that is not often cited, however, is "don't fight your frameworks" (page 157). If your framework already has a good implementation of the pattern, just use it. This is advice that we ignored to our peril.

.NET 3.5 introduced linq. Besides the language features that support linq, the core framework component is the IQueryable interface. As it happens, IQueryable is the repository/specification pattern. Any object that implements this interface is a repository. Any boolean delegate (or lambda expression) is a specification. Combine the two using the Where extension method, and you have implemented the pattern.

What we did, however, was to create generic interfaces with names like IAggregateRootRepository, ISpecification, and IUnitOfWork. In order to use these interfaces, you have to define entire classes that differ in no more than a class name and a where clause. The result is a common base class library that is difficult to learn and encumbered with Evans' poor choice of words. Our application is full of extra classes that could have been inlined as lambda expressions. We have an entire suite of unit tests dedicated to ensuring that these specification classes contain the right boolean expression.

Here's my solution
Although we are too far along in the process to make radical architectural changes, I like to keep an ideal in mind for new development and refactoring. The ideal is a simple one: encode business knowledge in rich domain objects, use mementos to persist them, build application and domain layers into a single process, and publish WCF web services only where needed.

I am not a born-again DDD convert. I apply Evens' advice only with an open and skeptical mind. But where I see his book brandished as justification for poor decisions, I dig deeper to find what he really meant. Yes, it takes a lot of digging, given his choice of obscure terms for otherwise well-known concepts, but there is value to be found.