5

Using assimp I've created a function to load 3D models and it does everything I need and I don't plan to use another library or write something custom, however, I am curious how techniques such as abstraction and encapsulation would improve the code (if at all)

Model* loadModel(Assets& assets, const std::string& filePath) {
    Handle handle = generateHash(filePath);
    bool modelFound = (assets.textures.find(handle) == assets.textures.end());
    if (modelFound == false) {
        spdlog::info("Model has already been loaded {}", filePath);
        return assets.models[handle].get();
    }
    else {
        Assimp::Importer importer;
        importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false);

        unsigned flags = aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices |
            aiProcess_FixInfacingNormals | aiProcess_GenUVCoords | aiProcess_OptimizeMeshes;

        const aiScene* scene = importer.ReadFile(filePath, flags);

        auto model = std::make_unique<Model>();
        model->directory = filePath.substr(0, filePath.find_last_of("/\\"));
        processNode(scene->mRootNode, scene, *model);

        assets.models[handle] = std::move(model);

        spdlog::info("Model loaded");

        return assets.models[handle].get();
    }
    return nullptr;
}

if I had to take a stab at improving this I'd probably want to take the assimp logic and put into a AssimpLoader class and I assume the benefit of this is all the assimp logic is in one spot and the function doesn't rely on assimp as much meaning it would be easier to change the assimp code or replace it with another library, but I still find it confusing how it's useful or helpful it just seems like more work. Why not just rewrite the function or have a second function unless the point is you sacrifice some simplicity and in return you have something that's more modular/flexible?

0

1 Answer 1

7

the function doesn't rely on assimp as much meaning it would be easier to change the assimp code or replace it with another library, but I still find it confusing how it's useful or helpful it just seems like more work.

So, you give one really good reason right there. These techniques can help you swap out the dependencies easily. It might be a little more work now but the idea of that is like an investment. You pay now and reap the rewards later. The question is: will you need/want to do that?

There are other benefits, however. One of the main reasons I typically like to create abstractions over my dependencies is to make it easier to understand the scope of those dependencies. That is, if the only place that ever references an external library is my abstraction layer, I don't need to look anywhere else to know what I am using from that library. That absolutely helps when evaluating and/or swapping in another library but that's not all. Here are some other reasons:

  • The reality is that it's unlikely that assimp (hilarious name BTW) will never change. Even if you never need to use a different library, when a major version change comes (and it likely will if the project survives) it's often quite similar to switching to a new library.

  • Knowing what parts of a library you are using is very helpful when trying to evaluate your risk when a vulnerability is announced.

  • Often when I first start using something, I don't have an optimal approach. It's more of a "get it working" mentality. Later, when I realize I was going around the block to get to the house next door, it often helps to have that code in one spot where I can improve it.

In a nutshell, these kinds of practices are essentially preparing for the unknown. I think a lot of people have the same confusion. If you don't get any benefit now, why put in the effort. Think about it more like wearing a seatbelt. I don't put on my seatbelt because I think I am going to wreck my car. If I thought that, I wouldn't drive anywhere. I put on my seatbelt because if something goes wrong, it can greatly mitigate the negative impact of an accident (no pun intended.) This kind of planning can get tricky. Determining the amount of extra effort to apply in order to mitigate events whose likelihood and impact cannot be precisely predicted is one of the key skills of software engineering.

It can be hard to know whether you should do this and how to do it without a lot of experience. I think abstraction and encapsulation are low effort (with practice) and tend to yield high returns and are therefore usually worth it.

1
  • 1
    "Knowing what parts of a library you are using is very helpful when trying to evaluate your risk when a vulnerability is announced." — and vulnerabilities will be discovered. This helps limit the blast radius of a security issue, which is a very important concept in cyber security. This isn't an aspect of encapsulation and abstraction that I've come to fully appreciate until later in my career. Commented Jun 18 at 10:32

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.