Tsaukpaetra's Injection Dependency


  • Notification Spam Recipient

    (Jeffed from the Status thread)

    Edit for @DogsB: something about warthogs.


  • Notification Spam Recipient

    Status: Getting lost in the weeds about all this magic Dependency Injection shit.

    The "example skeleton" app has millions of tiny classes that magically get shit like database instances and response instances transformation instances and what the fuck happened to a consistent and simple flow of logic?!?


  • Banned

    @Tsaukpaetra said in The Official Status Thread:

    The "example skeleton" app has millions of tiny classes that magically get shit like database instances and response instances transformation instances and what the fuck happened to a consistent and simple flow of logic?!?

    Yep, that sounds about right for DI.


  • 🚽 Regular

    @Tsaukpaetra I'm coming from the opposite side of the spectrum.

    Our main program has zero dependency injection and it's all a bunch of tightly-knit God Objects, making it hard to substitute parts or run them in isolation. I've been working on stuff like trying to make configuration not necessarily come from a database, or at least not specifically the database where the working data is stored!

    Not 100% true anymore. The bits I wrote anew do have dependency injection, insofar as "the Frobiculator constructor takes a FrobiculatorContext object with all the dependencies it needs to do its job hiding behind interfaces" counts as dependency injection. Dependencies are still hardcoded to specific implementation types, but at least they are done so outside Frobiculator.


  • Discourse touched me in a no-no place

    @Tsaukpaetra said in The Official Status Thread:

    Getting lost in the weeds about all this magic Dependency Injection shit.

    Java+Spring or something even nastier?


  • Notification Spam Recipient

    @dkf said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    Getting lost in the weeds about all this magic Dependency Injection shit.

    Java+Spring or something even nastier?

    PHP


  • BINNED

    @Tsaukpaetra said in The Official Status Thread:

    Status: Getting lost in the weeds about all this magic Dependency Injection shit.

    The "example skeleton" app has millions of tiny classes that magically get shit like database instances and response instances transformation instances and what the fuck happened to a consistent and simple flow of logic?!?

    What is the point of all that stuff, aside from making code impossible to read?

    I’m clearly not doing things enterprise-y enough.


  • Discourse touched me in a no-no place

    @Tsaukpaetra said in The Official Status Thread:

    @dkf said in The Official Status Thread:

    Java+Spring or something even nastier?

    PHP

    May Codethulhu have mercy on your soul.

    (Some of the software I work with uses a homebrew dependency injection system written in Python. It's nasty and complicated and confusing to most tools and very slow, even by Python standards. I didn't write it, and one of my colleagues has been busy stripping it out for the past couple of months.)


  • 🚽 Regular

    @dkf At least it's not like Python has an unnecessarily complex type model, right??


  • Discourse touched me in a no-no place

    @topspin said in The Official Status Thread:

    What is the point of all that stuff, aside from making code impossible to read?

    Done right, it isn't difficult to read. But you have to think in terms of swimming on the surface of the sea instead of diving deep. You know that there are entities out there that do certain tasks that you need, but you don't need to know their exact identities or how they're built; you're just given them (because you ask for them) and use them as required.


  • Notification Spam Recipient

    @dkf said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    @dkf said in The Official Status Thread:

    Java+Spring or something even nastier?

    PHP

    May Codethulhu have mercy on your soul.

    (Some of the software I work with uses a homebrew dependency injection system written in Python. It's nasty and complicated and confusing to most tools and very slow, even by Python standards. I didn't write it, and one of my colleagues has been busy stripping it out for the past couple of months.)

    It hasn't claimed me yet! I'm trying to understand enough about it to maybe possibly apply it to my conversion of PHP 5.0 code to the latest stable.

    In my case, I'm not seeing the benefit of three classes that just pass data to one another (calling effectively the same method down the chain). The concerns really aren't that separate, yo!


  • Notification Spam Recipient

    @Tsaukpaetra said in The Official Status Thread:

    @dkf said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    @dkf said in The Official Status Thread:

    Java+Spring or something even nastier?

    PHP

    May Codethulhu have mercy on your soul.

    (Some of the software I work with uses a homebrew dependency injection system written in Python. It's nasty and complicated and confusing to most tools and very slow, even by Python standards. I didn't write it, and one of my colleagues has been busy stripping it out for the past couple of months.)

    It hasn't claimed me yet! I'm trying to understand enough about it to maybe possibly apply it to my conversion of PHP 5.0 code to the latest stable.

    In my case, I'm not seeing the benefit of three classes that just pass data to one another (calling effectively the same method down the chain). The concerns really aren't that separate, yo!

    Controller -> Service -> DAO is what I typically see in spring apps. With an interface in front of each one. Do you have the exact same name down the stack? How deep does it go?

    I'm kind of curious now.


  • Notification Spam Recipient

    @DogsB said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    @dkf said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    @dkf said in The Official Status Thread:

    Java+Spring or something even nastier?

    PHP

    May Codethulhu have mercy on your soul.

    (Some of the software I work with uses a homebrew dependency injection system written in Python. It's nasty and complicated and confusing to most tools and very slow, even by Python standards. I didn't write it, and one of my colleagues has been busy stripping it out for the past couple of months.)

    It hasn't claimed me yet! I'm trying to understand enough about it to maybe possibly apply it to my conversion of PHP 5.0 code to the latest stable.

    In my case, I'm not seeing the benefit of three classes that just pass data to one another (calling effectively the same method down the chain). The concerns really aren't that separate, yo!

    Controller -> Service -> DAO is what I typically see in spring apps. With an interface in front of each one. Do you have the exact same name down the stack? How deep does it go?

    I'm kind of curious now.

    I don't have anything yet. I 've been following this example:

    From what I understand, at minimum to (for example) create a user, you need a container factory that builds the container which adds the routes, one of which is the user create action which calls the user creator service which calls the user repository which calls the query factory which returns the row to the above which returns the primary key to the above which calls the responder to write the header for JSon and json_encode an array containing the given primary key.

    😖

    I mean, I'm all for simplifying code and reducing repetitive boilerplate, but this seems a bit... much.


  • Notification Spam Recipient

    @Tsaukpaetra said in The Official Status Thread:

    From what I understand, at minimum to (for example) create a user, you need a container factory that builds the container which adds the routes, one of which is the user create action which calls the user creator service which calls the user repository which calls the query factory

    Seems perfectly fine to me.

    which returns the row to the above which returns the primary key to the above which calls the responder to write the header for JSon and json_encode an array containing the given primary key.

    Implementation details.


  • Banned

    @Tsaukpaetra it starts making more sense when you have 300 routes and 40 services. Every solution to problems that only happen in large projects is going to look ridiculous outside large projects.


  • Discourse touched me in a no-no place

    @DogsB said in The Official Status Thread:

    Controller -> Service -> DAO is what I typically see in spring apps.

    It all depends on how much complexity there is, and what you're doing with security and so on. For example, if you're using annotations to put non-trivial security checks on methods, the actual object that the caller works with is not the same as the object that you write; instead, it's actually a proxy that applies the security constraints and calls through to the underlying “real” method at the right time. If you don't have an interface, proxies are done using a pretty nasty runtime code generation system that I've always found to be more trouble than it's worth, but if there's an interface then the proxies are trivially easy. But mostly you don't have to think about that stuff, and that's where Spring's nice; yes, there's some really ghastly stuff under the covers, but you're really not supposed to look there. Especially with the help of @Bean-annotated methods, you can avoid a lot of complexity, but it is only in a complicated application that Spring really helps a lot. (Of course, all but the most trivial of web applications reach that complexity threshold.)

    If you ever deal with OSGi, that goes even more fully in on the whole business with proxies; it's very strict on what is visible and what isn't.



  • The main reason for all this is to decouple things logically, of course.

    Having a user repository binding is meant, in theory, to not depend on the actual one but so that you could switch between a real one and a mock one.

    And this sort of thinking does apply further up the stack - your container (with all the knowledge of DI bindings) isn’t necessarily the same in all cases, the obvious example is prod vs CI (real vs mock everything), but I have built things like an app with separate containers for “user front end” vs “admin backend” vs “command line” where each of these are different ways into the application with different needs that other parts of the application might care about.


  • Notification Spam Recipient

    @Arantor said in The Official Status Thread:

    The main reason for all this is to decouple things logically, of course.

    Having a user repository binding is meant, in theory, to not depend on the actual one but so that you could switch between a real one and a mock one.

    And this sort of thinking does apply further up the stack - your container (with all the knowledge of DI bindings) isn’t necessarily the same in all cases, the obvious example is prod vs CI (real vs mock everything), but I have built things like an app with separate containers for “user front end” vs “admin backend” vs “command line” where each of these are different ways into the application with different needs that other parts of the application might care about.

    Yeah, at this point the only difference between "mock" "dev" and "prod" are what database name on localhost it's supposed to talk to.

    I'm having difficulty concieving how you would possibly configure a "container" to have a "user frontend" and "admin backend" without having those things be separate in the code anyways. Or am I missing something?

    To me it sounds like DI gives you magic objects you don't know what's in side of them, that you know what's inside of them because you know you call things and get things, but that they're somehow replaceable with other things that are them but could not be them but should be are, and so it works?

    If an object knows what it needs to work, why does it not just get those objects it knows it needs to work to work?

    I'm just trying to not explode the scope of this rewrite. At present, everything that is done flows through discrete php scripts arranged in a controller-like pattern that handle a bunch of actions in each controller.

    So far I've splatted the database into a table-per-class layout , and I was already planning on splatting all the actions in each controller into classes in a similar way, so the only thing further I need to do (I guess?) is to splat each of those action classes into an action/service/response class for everything?

    Man, and here I thought I would be done come end of January...


  • Banned

    @Tsaukpaetra said in The Official Status Thread:

    @Arantor said in The Official Status Thread:

    The main reason for all this is to decouple things logically, of course.

    Having a user repository binding is meant, in theory, to not depend on the actual one but so that you could switch between a real one and a mock one.

    And this sort of thinking does apply further up the stack - your container (with all the knowledge of DI bindings) isn’t necessarily the same in all cases, the obvious example is prod vs CI (real vs mock everything), but I have built things like an app with separate containers for “user front end” vs “admin backend” vs “command line” where each of these are different ways into the application with different needs that other parts of the application might care about.

    Yeah, at this point the only difference between "mock" "dev" and "prod" are what database name on localhost it's supposed to talk to.

    You're doing mocks wrong.



  • Hey! No kink mock-shaming!


  • Notification Spam Recipient

    @Gąska said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    @Arantor said in The Official Status Thread:

    The main reason for all this is to decouple things logically, of course.

    Having a user repository binding is meant, in theory, to not depend on the actual one but so that you could switch between a real one and a mock one.

    And this sort of thinking does apply further up the stack - your container (with all the knowledge of DI bindings) isn’t necessarily the same in all cases, the obvious example is prod vs CI (real vs mock everything), but I have built things like an app with separate containers for “user front end” vs “admin backend” vs “command line” where each of these are different ways into the application with different needs that other parts of the application might care about.

    Yeah, at this point the only difference between "mock" "dev" and "prod" are what database name on localhost it's supposed to talk to.

    You're doing mocks wrong.

    I'm not actually doing mocks at all, they're represented by a json documents that get side-loaded into a temporary database. :mlp_shrug:

    Considering they don't actually exist at all in the current iteration, the fact I'm even considering this at all is magic in itself.


  • Notification Spam Recipient

    @Tsaukpaetra said in The Official Status Thread:

    I'm having difficulty concieving how you would possibly configure a "container" to have a "user frontend" and "admin backend" without having those things be separate in the code anyways. Or am I missing something?

    Different implementations are of course separate in code. But no matter how many times they are used in the project, you can switch between them by changing a single thing: registration in container.


  • Notification Spam Recipient

    @MrL said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    I'm having difficulty concieving how you would possibly configure a "container" to have a "user frontend" and "admin backend" without having those things be separate in the code anyways. Or am I missing something?

    Different implementations are of course separate in code. But no matter how many times they are used in the project, you can switch between them by changing a single thing: registration in container.

    I... guess? I feel like I'm still not getting it, but for now I have to pretend to do actual work and push digital papers around for a few hours...


  • I survived the hour long Uno hand

    @topspin said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    Status: Getting lost in the weeds about all this magic Dependency Injection shit.

    The "example skeleton" app has millions of tiny classes that magically get shit like database instances and response instances transformation instances and what the fuck happened to a consistent and simple flow of logic?!?

    What is the point of all that stuff, aside from making code impossible to read?

    I’m clearly not doing things enterprise-y enough.

    The main objective is to have all of your classes treat each other as separate "micro"services that interact with each other via a published API (the Interface), so that you have a clean separation of concerns for Unit Testing and so that your unit tests work easily with mocking frameworks to be able to quickly substitute fake functions for the public API parts of the dependency class.

    If you're not doing multiple implementations of the same Interface (most generally, unit testing with a mocking framework), it's not worth the time and headache. If you are doing unit testing, it's amazingly worth the hassle because it lets the mocking framework handle all the gory details of faking out the cross-class calls so you don't wind up with large amounts of repeated boilerplate in trying to make sure that your BusinessLogicContainer class doesn't really call the back end database in DatabaseConnectionContext when you're exercising the container class.

    E.g.:

    public class BusinessLogicContainer(IDatabaseConnectionContext context)
    {
        _context = context;
    }
    
    public bool OnUpdateDatabase(ImportantUserInformation userInfo)
    {
        var existingUser = _context.Users.FirstOrDefault(u => u.Id == userInfo.Id)
        if (existingUser != null) 
        {
            existingUser.FirstName = userInfo.FirstName;
            existingUser.LastName = userInfo.LastName;
        }
        else 
        {
            _context.Users.Add(userInfo);
        }
        _context.SaveChanges();
    }
    

    With DI and a mocking framework, your test basically becomes:

    [TestMethod]
    public void WhenUserDoesNotExist_AddsTheUserAndSavesChanges()
    {
        var context = Mock<IDatabaseConnectionContext>();
        var businessLogicContainer = new BusinessLogicContainer(context.Object);
        var newUser = new ImportantUserInformation { Id = 666, FirstName = "Satan", LastName = "Incarnate" };
        businessLogicContainer.OnUpdateDatabase(newUser);
        context.Verify(c => c.Users.Add(newUser), Times.Once);
        context.Verify(c => c.SaveChanges(), Times.Once);
    }
    

    But it doesn't actually hit the back end database, so you don't have Satan in your user database because of the tests.


  • 🚽 Regular

    @Tsaukpaetra said in The Official Status Thread:

    To me it sounds like DI gives you magic objects you don't know what's in side of them

    Not knowing what's inside them is a good thing. Single responsibility principle. You do know what they do, for a given interface type, but not how they do it.

    @Tsaukpaetra said in The Official Status Thread:

    If an object knows what it needs to work, why does it not just get those objects it knows it needs to work to work?

    Because then you fall into the place I am, where I want to stop using ADO with handwritten SQL and substitute it with an ORM (doesn't matter which; it shouldn't matter which, so I can change my mind later), but every time some thing wants to do a database operation it creates an instance of that class that uses ADO. Or, somewhat worse, calls a static method on it.

    Or I want some piece of code to be able to download data from two different external systems for two separate clients, but I can't because again the part that starts the downloads strongly refers to a particular implementation.


  • Notification Spam Recipient

    @Tsaukpaetra said in The Official Status Thread:

    @MrL said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    I'm having difficulty concieving how you would possibly configure a "container" to have a "user frontend" and "admin backend" without having those things be separate in the code anyways. Or am I missing something?

    Different implementations are of course separate in code. But no matter how many times they are used in the project, you can switch between them by changing a single thing: registration in container.

    I... guess? I feel like I'm still not getting it, but for now I have to pretend to do actual work and push digital papers around for a few hours...

    Two real life examples:

    1. We have different authentication facilities on dev, preprod and prod. So we have three implementations of IAuthorizationService, which is registered with different implementation depending on environment.
    2. For local debugging purposes we have a separate container registration. You switch to it and all external dependencies are mocked, authentication tokens don't expire, etc.

  • Notification Spam Recipient

    @izzion said in The Official Status Thread:

    because of the tests.

    Ah. Yeah. I haven't even begun to ponder how motherfucking testing frameworks are supposed to happen. Maybe this will be the Year of the Unit Test?


  • 🚽 Regular

    @izzion said in The Official Status Thread:

    If you're not doing multiple implementations of the same Interface (most generally, unit testing with a mocking framework), it's not worth the time and headache.

    It is worth the time if you just want to fake it till you make it.


  • Notification Spam Recipient

    @Zecc said in The Official Status Thread:

    @Tsaukpaetra said in The Official Status Thread:

    If an object knows what it needs to work, why does it not just get those objects it knows it needs to work to work?

    Because then you fall into the place I am, where I want to stop using ADO with handwritten SQL and substitute it with an ORM (doesn't matter which; it shouldn't matter which, so I can change my mind later), but every time some thing wants to do a database operation it creates an instance of that class that uses ADO. Or, somewhat worse, calls a static method on it.

    That's.... exactly what I'm doing. So it sounds like I haven't taken the rewrite goals far enough then?


  • 🚽 Regular

    @Tsaukpaetra Like in all things software development, it's about tradeoffs. Increasing the number of independent "microservices" does raise complexity. You just need to find the sweet spot.

    If there are parts of the codebase you don't imagine will ever change, then by all means hardcode them. But it's nice to have options.


  • Considered Harmful

    ⛳ for :kneeling_warthog: to :doing_it_wrong: to "Tsaukpaetra's Injection Dependency"


  • Notification Spam Recipient

    @Applied-Mediocrity said in The Official Status Thread:

    ⛳ for :kneeling_warthog: to :doing_it_wrong: to "Tsaukpaetra's Injection Dependency"

    I was seriously considering it!


  • 🚽 Regular

    But... but... we've just reached post 121 000.


  • Notification Spam Recipient

    @Zecc said in The Official Status Thread:

    But... but... we've just reached post 121 000.

    Need to rollback so we can have another shot at a more meaningful post. 🐠


  • 🚽 Regular

    Yeah, all right. I'm going to move it. Everyone hold on to your hats.


  • I survived the hour long Uno hand

    @Zecc said in The Official Status Thread:

    Yeah, all right. I'm going to move it. Everyone hold on to your hats.

    /giphy hold onto your butt


  • Considered Harmful

    @Tsaukpaetra said in Tsaukpaetra's Injection Dependency:

    I was seriously considering it!

    And I was just mocking you (all) 🐠


  • Banned

    @MrL said in Tsaukpaetra's Injection Dependency:

    For local debugging purposes we have a separate container registration. You switch to it and all external dependencies are mocked

    Stubbed. :pendant:


  • Notification Spam Recipient

    @Gąska said in Tsaukpaetra's Injection Dependency:

    @MrL said in Tsaukpaetra's Injection Dependency:

    For local debugging purposes we have a separate container registration. You switch to it and all external dependencies are mocked

    Stubbed. :pendant:

    That too.


  • I survived the hour long Uno hand

    @Applied-Mediocrity said in Tsaukpaetra's Injection Dependency:

    @Tsaukpaetra said in Tsaukpaetra's Injection Dependency:

    I was seriously considering it!

    And I was just mocking you (all) 🐠

    public interface IWTDWTFPoster
    {
        public ShitPost DoPostGarage(bool isCaffinated = false);
        public BadPun DoPostPunThread(bool isCafinated = false);
        public Updoot DoViewLikesThread();
    }
    

  • 🚽 Regular

    I've changed the first post's owner to be @Tsaukpaetra.
    It had already been upvoted/read by @Tsaukpaetra.

    Did the universe implode? It just says it was upvoted by @DogsB now.


  • Notification Spam Recipient

    @Zecc When it said something about warthogs it amused me.

    Thanks @Tsaukpaetra


  • Notification Spam Recipient

    @Zecc said in Tsaukpaetra's Injection Dependency:

    If there are parts of the codebase you don't imagine will ever change, then by all means hardcode them. But it's nice to have options.

    I'm thinking the exact opposite effect: If there is ever a need to change something, it necessarily needs to change in 5x the places it used to need changing in.



  • @Arantor said in Tsaukpaetra's Injection Dependency:

    The main reason for all this is to decouple things logically, of course.

    Having a user repository binding is meant, in theory, to not depend on the actual one but so that you could switch between a real one and a mock one.

    And this sort of thinking does apply further up the stack - your container (with all the knowledge of DI bindings) isn’t necessarily the same in all cases, the obvious example is prod vs CI (real vs mock everything), but I have built things like an app with separate containers for “user front end” vs “admin backend” vs “command line” where each of these are different ways into the application with different needs that other parts of the application might care about.

    It also prevents you from trying to spy/rely on internals of the services you're requesting (or at least makes you think about which methods / properties you really need to expose instead of making everything public)


  • 🚽 Regular

    @Tsaukpaetra said in Tsaukpaetra's Injection Dependency:

    @Zecc said in Tsaukpaetra's Injection Dependency:

    If there are parts of the codebase you don't imagine will ever change, then by all means hardcode them. But it's nice to have options.

    I'm thinking the exact opposite effect: If there is ever a need to change something, it necessarily needs to change in 5x the places it used to need changing in.

    Then the concerns aren't separated properly; which, don't get me wrong, some times happens because reality has a tendency to be more complex than theory.

    But if you need to change something in 5x the places it used to need changing in, then that probably means there are 5x the places your change potentially affects when compared to what you originally thought.



  • @Tsaukpaetra said in Tsaukpaetra's Injection Dependency:

    I'm having difficulty concieving how you would possibly configure a "container" to have a "user frontend" and "admin backend" without having those things be separate in the code anyways. Or am I missing something?

    A little.

    So, during application bootstrap we load the container appropriate to the situation (user, admin, console, whatever).

    There are some common services defined in the container, e.g. the database connection details are the same so my DB factory spits out the same object.

    There are some bindings that are explicitly not the same, e.g, session so user session cannot pollute admin session and vice versa.

    But whether it’s actual code, or code as configuration, you still have a thing that says “when the code asks for a thing of type XyzInterface, you are going to give them ConcreteXyz”

    That’s really all DI is: if a constructor wants an object conforming to a given interface, what is the configuration necessary to construct an object of that interface in this context. That way you can build a DB object that mocks your real DB out and just define this in test DI config vs real DI config.


  • Notification Spam Recipient

    @Arantor said in Tsaukpaetra's Injection Dependency:

    There are some bindings that are explicitly not the same, e.g, session so user session cannot pollute admin session and vice versa.

    Interesting. In my reimplementation, the only difference between a user and admin session is that the admin session has a permissions blob (signed/verified) that will trigger some extra logic to tell them what things they have access to (and is what's checked against when they attempt to access said admin things).

    Of course, I fully expect someone to come along and say my concerns need to be more separated I guess...



  • @Tsaukpaetra I think it really depends on your security model.

    The one I inherited literally used the same session and just required the user to reauthenticate every hour they stayed in the admin area. I decided I wanted them in separate sessions so the user could just stay logged in until they were done.


  • Considered Harmful

    I've seen mocks mentioned a few times already, but usually in the context of automated tests.

    Another time mocks are useful, is when you haven't built everything yet. Or, someone else is building the other part. I've built databound UIs with full functionality that depend on e.g. web services that didn't exist yet, using a mock implementation, and then when the implementation was ready I didn't have to do anything but rewire the dependency to the real one.
    This is also useful if you want, for example, a designer to be able to mess with the UI without a full stack application running beneath it.


  • Considered Harmful

    Consider that a higher-order function on the loan pattern is also a point on the IoC / injection spectrum. By the point of application launch an address space has been granted. In other words, unless you like assembler, one's been soaking in it ever so long.


Log in to reply