what are the dependents for professional development?
Today was full of reading and understanding, at least attempting to understand - I can hear Yoda in the background saying “Don’t try, DO”. OK, OK! I was doing to understand. My topic for understanding was Dependency Injection. This is a pattern in software development AND web development AND software engineering in which dependencies… are… um… injected… into - but seriously. Dependency Injection (DI) is a pattern in which a object/library/service/etc that is needed for another object/library/service/etc is passed into that object/library/service/etc. I’m not sure it’s the most accurate definition, nor the most correct.
To compared DI to other patterns, it is different to a dependency being “found” or “built” by dependent. I’m not exactly sure how the import/require functionality works in modern day JavaScript but it could be that when a JS library/file, otherwise known as a module, is imported/required into another JS file that module is told where it’s located. When JS builds the file then all the imported modules are wrapped up together. I’ve got a feeling this isn’t DI as DI involves passing the dependencies a dependent needs to run into it.
Anyway, I think I’m butchering the definition. Check out this metaphor on our beloved Stack Overflow; it’s a much better explanation of DI concept. I couldn’t explain it to a 5 y.o like this, so yes, currently I don’t fully understand what it’s all about. I read these articles to help me understand this and some of this article by Martin Fowler, because it was more theoretical than I wanted at the time. They helped, but I feel like I’ve got a conceptual understanding but not a technical understanding.
On that note I found this library to implement DI. There were a few other libraries I found, but I went with this because it was used by a lot of projects (16.5k), had a lot of contributors (71), was updated somewhat recently (3 months from the date of publication), and was used by a bunch of different companies many of which are quite large. Also, the imported library is only 40.9k in size (I know this thanks to Import Cost, a useful library that displays the size of the import in the file).
On the downside compared to the other libraries there seemed to be more code to write to get DI to work. But that wasn’t such a big issue for me. It’s more important for a library to be well supported and used by a lot of projects. I don’t want a library to stop being maintained because there’s not enough people using it.
It was pretty straight forward to get DI set-up with this library. I followed the instructions and got it working pretty quickly. I found this way of creating the dependencies to be much clearer. I read in the README for this DI library an insightful way to look at DI compared to Modules. I’m not sure if I was reading the paragraph correctly as the grammar was a bit confusing. But my take away from it was use DI for implementation that’s not dependent on third-party libraries. I guess for implementation that has been coded by the developer instead of imported from a third-party library. It makes sense, but I’m not sure if that’s an accurate way to look at either way of using dependencies.
In my situation I used DI to inject the database class into the datasources class, the datasource class into the server class, and I’ll use it to inject the authorisation class into the server class. Originally I thought it’d be a way to solve the issue I was having with the logger function. I wanted to pass the lambda event and context into the logger class to used certain attributes of either of these when the logger function is called. Upon implementation I realised DI couldn’t help with that issue. But that’s okay, I still used DI and settled on, what I feel is, a bit of a messy solution to the logging issue. I’m basically passing the logger function in with the Apollo Server context. I’m currently just using it in the resolvers, but if I want to use it in the authorisation class or datasources class I’ll have to pass it through to these classes as an argument. I thought about making the context and event a global, but that didn’t seem to be a good idea.
In anycase, this is a learning process for me. I’ve a feeling DI is probably a bit of overkill for this project. But I’m keen to learn about aspect of OOP design and this is one way to learn it. This is what I feel is missing from my understanding of software development. I mentioned it in a previous blog: “Is it appropriate to use insert whatever architectural style here in this situation?”. The answer I mostly have is: “I. Don’t. Know”.
In the Martin Fowler article that I linked above the DI design pattern originated back in 2004 from the Java community when there was a “rush of lightweight containers that help to assemble components from different projects into a cohesive application”. I’m guessing there was a problem with whatever design pattern the Java community was using before the DI pattern came about. That problem was solved by DI. It’d be interesting to know what the limiting design pattern was before DI, not to mention the strengths of this design pattern and when it is most useful to follow.
This brings me to a few other questions that’ve been taking up some of my brain’s clock cycles: How do we know it is the most useful pattern to follow? Like, what’s the criteria for deciding this? Is this based on experience? Is it based on making a developer’s life easier? Is it based on concrete research with comparable measurements and results? Is comparable research even possible? I’m not really sure. I imagine it’d be exceedingly insightful to research the difference between these design patterns and at which context it is appropriate to use them.
Further on in the Martin Fowler article he writes about deciding which option to use (Service Locator vs Dependency Injection) and he points to an underlying principle: “in both cases application code is independent of the concrete implementation of the service interface”. To me this suggests that it kind of doesn’t matter which of these of these patterns but what is important is, as stated in the introduction: “The choice between them is less important than the principle of separating configuration from use”. But going back to the versus section he mentions: “The important difference between the two patterns is about how that implementation is provided to the application class”. Here he is bringing it back to the actual coding experience. I won’t going into the differences between these two patterns because my point is there IS a difference in implementation even though there isn’t really much of a difference in the design principle underlying these two methods.
This makes me wonder if the implementation is “just” a matter of personal difference? Do different personalities prefer implementing code in particular ways because it just what they like and whatever reason they come up with later on supports that like. Or do they have concrete performance reasons, ease of coding reasons, ease of understanding reasons, etc. For instance, I decided to implement a bunch of class in my lambda project when it could’ve done without it because I wanted to experiment it and there is a clearly distinction of functionality which, in turn, makes it easier for me to understand. It’s a good enough reason for me to implement classes, but what if the project gets bigger and more people get involved? What then? What would be the better design pattern to use?? I dunno!
Is this a matter of experience? Or knowledge? If I had the knowledge I’d have more options to choose between different design patterns, but I’d probably need the experience to understand when to apply them appropriately. Or is this a matter of having a mentor with more experience?
Surprise! I don’t have an answer for that. What about you, dear reader?