0

I'm adding mod support for a game I'm working on. I parse a data file that looks something like this:

"requirements":
{
    "is_class": { "class": "warrior" },
    "is_in_faction": { "faction": "elves" }
}

From this data, I create a list of Requirement objects which convert the data into bound delegates via reflection. The delegate takes an object instance and the associated values as parameters. I store the list of Requirement objects in a RequirementDatabase related to the item(s) that need those requirements. This part is solved.

The aspect I'm struggling with is naming this functionality. I currently have:

RequirementDatabase.Evaluate(Object target)
{
    foreach(Requirement requirement in requirements)
    {
        if(requirement.Evaluate(target) == false)
            return false; // requirements not met
    }

    return true; // requirements met
}

I don't feel like "Evaluate", especially when being fed an object that is being evaluated, conveys the right semantics of what is happening. It would make slightly more sense the other way around: Object.Evaluate(Requirement) but I don't want the objects to be made aware of requirements.

Any advice? I'm happy to rename anything and everything here to get clear semantics.

2 Answers 2

2

I suspect that you have trouble with the name precisely because most of this function does something very generic/abstract that you happen to be using in a specific/concrete context, and these forces are nudging you in different directions regarding how to describe it. I notice this a lot. When I encounter this, I try to tease the abstract and concrete aspects apart. I describe what's happening without reference to the specific situation/concrete details, and this usually helps me do two things: (1) extract the generic part and (2) name each part individually. When I separate the two parts from each other, sensible names for both tend to come to me more easily.

First, I see "return true if 'evaluate()' returns true for all requirements". Let me replace "requirement" with "thing" (hiding details) and see what happens. "return true if 'evaluate()' returns true for all things". OK. Since I feel funny about "evaluate", let me try to replace it with something even less concrete. "return true if 'some predicate P' returns true for all things". Now I need to add back some details to avoid confusion. "return true if 'some predicate P' returns true for all things in 'some collection C'". OK. I don't think I can make this any more abstract. What remains? I just want to know whether the predicate is true for all items in the collection. IsTrueForAllItems(predicate, items), where predicate is a function that turns an item into a boolean. In a language with type parameters, I can declare this function's type without knowing the type of the items, so I can extract it completely from its current context of "requirements.

So now I extract IsTrueForAllItems() (and put it somewhere), which has a sensible-but-perhaps-clunky name, which turns RequirementDatabase.Evaluate() into a one-line function that hides most of its details. Once I hide the details of this usage of IsTrueForAllItems(), I can focus on what matters about using it that way, then find a better name for it. Since I don't know your application domain very well, I can only suggest that you might find a sensible name somewhere in what you typed in your question:

I store the list of Requirement objects in a RequirementDatabase related to the item(s) that need those requirements.

Does that trigger any ideas?

Also, when I look at the comments in your algorithm, I see "interpreting comments", which suggest names to me. Perhaps the function becomes RequirementsMetBy(predicate, requirements). Does that sound any better to you? By "interpreting comment" I mean a comment that explains how to interpret a value that doesn't adequately describe itself. I encounter these a lot when I have too many details in one place and have to explain what they mean. (It doesn't seem like you have "too many" details here, but you have the beginning of too many details here. Already you need comments to explain what role they play! It can only become more difficult to understand over time as you add code.)

Next, now that you can think about IsTrueForAllItems() without Requirement objects distracting you, you might notice that this boils down to mapping the predicate to each item in the collection, then folding the resulting boolean values with and. You might even be able to find a library to do that for you with names that you like.

Finally, if you want to reorganize the top-level function to make the API nicer, you can do that independently without having to change IsTrueForAllItems(). Similarly, if your language lets you move IsTrueForAllItems() onto a class, then you'd simply rearrange the parameters (one of the parameters becomes the receiver, either the collection or the predicate) and you can make that change safely and mechanically. It becomes easier and safer to play around with how to make the API nicer according to your taste or to fit better with the structure of the rest of the system.

0

Depending on language support you can flip the order of the objects with an extension method

static bool Matches(this Object, List<Requirement> requirements) {...}

Or you could do something similar with a new ObjectList object which is part of the Requirements library

public class ObjectList 
{
    public List<Object> Objects {get;set;}
    public List<Object> FilterBy(List<Requirement> requirements) {...}
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.