 I think what Brad just said is kind of like the perfect connection between the two worlds because basically what service oriented architecture is on the system architecture level, dependency injection is in the software architecture level, and if you think about services in terms of network services, right, you can kind of think about it the same way inside one process in terms of dependency injection services, and in a very concrete way, if you have this kind of modularity, you can actually have a pure PHP implementation of a service that you use internally, service object, or that can just be a thin layer that talks to a remote service, giving you an interface or an abstraction layer where you can actually incorporate the best of both worlds. That's at least my hope. What is this? Is there? Ah! So can I just use... Yeah, arrow keys. Can I just scroll somehow? Yeah, okay. Technology. Okay, that works. So the rationale behind using dependency injection is basically the same as for service oriented architecture. You want to avoid strong coupling. You want to rely on well-defined interfaces between services on different levels. That allows development to be decoupled. That allows better testability, especially in terms of automated testing. And it makes it easier to reuse individual components. So the idea is to move the software architecture towards something where you have on the one hand service objects that are... Well, I put singletons into quotes because a true singleton can actually only exist once in a process. That's not actually what I'm aiming at, and that's actually not best practice, but a situation where you would typically have just one instance of a service. Or you could... That doesn't mean one instance of one type of service, but... Oh, I don't know. You could have two rendering services implementing the same interface for different purposes and have them coexist, something like that. So on the one hand you have service objects. On the other hand, you have rather dumb and simple value objects. And really not much in between. Of course, there's always exceptions. And it's not something that you would insist on to always be handled this way 100%, especially not during transition, especially not if you're trying to move a big complex system like MediaWiki towards more modular architecture. Yeah. In concrete terms, in the context of storage layer, this kind of corresponds to the data access object approach, which I hope to move towards with MediaWiki. Yeah. In order to avoid strong coupling, the idea is that a service object would always get whatever it needs to operate as constructor parameters. And you have some kind of service at the top that glues these services together, that wires them. So you have a top-level thing, a DI container typically, or a service locator, depending on the terminology you want to use, that knows which services use which other service implementation. So the concrete implementation is known in like one place. There actually seemed to be, there was an ROC discussion about this recently, and another one like maybe a year ago. And there seemed to be broad consensus that, yes, we want to move in that direction, but there were also a couple of open questions. One of them is, in how far should the DI container be configurable? So should extensions be free to define their own services or even override and replace or wrap existing service objects? Which would actually be very powerful, right? An extension could simply completely replace the entire storage layer of MediaWiki. And everything would then operate on the storage layer that extension provides. That makes it very powerful. Maybe scary? I don't know. I kind of like the idea. Then there's the aspect of auto wiring. So a lot of DI frameworks have the ability to automatically guess what service implementation and other service needs, just based on the interfaces that are implemented. A lot of people are worried of that. And I agree, this is very convenient until the system gets so complex that you no longer know what's going on. So I personally much prefer to explicitly say which service uses, so which service implementation uses which other implementations and when. The last question that seemed to be open is, shall we use a pre-existing third-party framework for this or should we roll around? And in my opinion, most of the existing frameworks simply do too much. We really need only very basic registry thing that can be implemented in 200, 300 lines of code. And I personally think that it's simply not worth the pain of relying on the third-party library. But that's one of the open questions still. So maybe I can get some feedback on the general idea of moving towards using service objects and using dependency injection in general. And also some feedback on these questions. Thanks. Stunned silence. So I guess maybe first just a show of hands here. How many people here feel like they understand the questions that are being put to them? Raise a show of hands here. How many people feel like, and then how many people maybe are still confused? Not willing to admit it, okay. Got sort of, okay. Okay. Yeah, of course, if you're still confused, feel free to ask questions. I will try to explain. Not particularly confused, just one of the added comments since you have an open question. So in terms of DI container, one model I've seen in the past for DI injection, particularly currently in use and flow, which is something I would recommend we try to avoid for Miduki Core, which is where you have global variables that you then import into different scopes as a singleton, rather more the contextual-based approach. I'm not sure what your thoughts on that are. I would recommend to avoid access to static variables wherever we can. We have quite a few, what I would call static entry points in MediaWiki, in particular, hook handler functions that are used by extensions typically are static functions. So they would have to access something from static, the global scope. Or from parameters. Sorry? Or from parameters. Or from parameters, yes. But in order to use that we would have to modify all the signatures, that would be painful. So at least for the backwards compatibility, my suggestion would be to keep hook handler functions very, very simple and basic, make them access like the global service locator object, get whatever they need from that, and then instantiate what or, well, use something, some service to do the actual handling. We have made very good experience with this approach in Wikidata. We use it all over the place and it works very, very well. It allows you to actually test the handler code completely independently of MediaWiki core. So I think I can at least talk to two of these three questions. So the third one, whether or not we should use or avoid frameworks for this. If you've done the surveying of the frameworks that exist in PHP for this right now, and you say they're kind of overkill or whatever, then my inclination would be to not use them. There's no point in injecting a pile of code that we only end up using a fraction of. It's just a waste, tons of overhead, if cognitive, if nothing else. My question would be on the auto wiring, though, is from my brief looking at it, the way that people in PHP tend to do auto wiring is via reflection. And I'm curious if the overhead from having to use reflection to do that auto wiring ends up negating some of the, you end up with cleaner code that's easier to introspect and to test and so forth. But have you added an overhead that's unacceptable in a production environment? That would be my biggest concern with auto wiring. Because I guess the biggest comparison would be in Java, you can do it and it's done prior to runtime versus with PHP reflection. You can't do it until runtime happens and it's kind of a pain at that point. And it happens on, well, not for every service on every request, but to some extent it would happen on every request, on every time we hit an application server. Yes. The original DIRC that we discussed a bit over a year ago suggested an auto wiring mechanism, actually implemented it by hand. And one of the major objections back then was also performance. And that's also one of my big concerns. The other big concern about auto wiring is, well, basically too much magic. You cannot actually look at the code and see what is done there. It's all kind of magically matching types somehow. So in that case, like I think from what we're saying now and then, you know, the objection that we had when we talked about this last time, my inclination would be that we would avoid auto wiring it. Like it's too magical and the performance implications are very real with reflection in PHP. So I would be inclined to avoid it. It certainly can be nice and makes for quick writing of code, but the magic gets a little scary sometimes and it can be hard to wrap your head around when you're looking at a fresh, you know, batch of code that you've never worked on before and you're kind of wondering, like, where are these things actually coming from? No, completely. I personally agree. I would also add to that we've had to remove various calls to reflection in the PHP code base over the past few months for various performance reasons. Don't use it, please. Should I go back to the ether patch so you can see what's happening? Just for clarification, having not programmed too much, I wonder if you could give a case example that might use WikiData and also with an interlingual component to those three elements. I don't think I quite got the connection between interlingual and the dependency injection bit. So can you give a case example first of dependency injection that would be apart from the interlingual question? An example. Well, if you, for instance, have a service that provides access to an underlying storage system, so something like a service that has something like, okay, get me revision X of article Y, and this service is supposed to do permission checks. Then the service would not implement these permission checks itself, and it would not instantiate whatever is needed to do the permission checks itself. It would ask the, it would simply ask in the constructor to get a service that does permission checks. And the idea is to build the entire software around this idea. One service does one thing and asks for other services for doing other things and does not know how these are implemented and should not know about it. That's the idea. That's it. Hi. My main concern is how are we actually going to get people to use this because, you know, we did title value and nothing uses it realistically. Yeah. Well, one problem with title value, or there's several problems with title values. One is that it's not a good replacement for title because it does not have the information from the page table. We would need something else to represent entries in the page table. Title value actually has a very limited use case which is basically link targets. It's just like a namespace and a title. And the services associated with it that does the parsing and link generation. Well, they are used, but they're kind of hidden because they're kind of encapsulated in compatibility methods. And there is currently no good way to expose them. With a DI framework, you would then have a hub where you can just ask for such a service. Currently, it's rather unclear how you would get a service instance. And currently, it is just, you know, if you don't have a need to use the service because you can still use the old star code and it's not aggregated or anything, well, then you don't, right? I imagine that we would start using this for providing new functionality. For instance, if we are going to implement multi-content revisions, the old compatibility stuff, like the old revision object and so on, would still exist, but you would only get the main slot. If you want to actually use more, you would have to use the new services. A couple questions, or a couple comments, I should say. So your first question about should we allow, I forget how you phrased it, but basically, should extensions be able to replace a service? Just going back to history off plug-in, which was kind of a service, really, it kind of worked, but it really didn't serve as well and it became a real bear to deal with. So I guess, yes, if we do them right, we should be able to use them well, but unfortunately I feel like we design them with kind of a rigid interface and then we realize that that interface doesn't work for us anymore. And so I don't, I guess I just caution against letting extensions depend on some interfaces like off plug-in. I'm definitely not explaining this very well. I guess I would say... Okay, you said you would, well, okay, let me, you said that it is a bad idea to have extensions rely on interfaces. What else could they rely on? Sorry, when they can replace services, I guess I feel like my personal experience with letting extensions replace a core service that then has to be relied on throughout core and other extensions has made things difficult with off plug-in. So I think I would just say I vote maybe not on that one. Yeah. Okay, I see, I understand the question. I mean, off plug-in is a pretty, the interface is not very well specified. Yeah, there were other issues there too. I don't know if it was the implementation specifically or whether it was a specific particular problem. I would just say it, I feel like that seems like a bad direction to me personally. Maybe we could have an intermediate solution where there's basically a white list of things that can be replaced by extensions. Yeah. Currently we have like a ton of hooks that allow extensions to replace all kinds of functionalities in runways, right? To me it seems like an improvement to actually have narrow interfaces with clear specifications, but yeah. I also understand that that can go wrong. Yeah. And then my second comment, I think it would be great too as we start doing this and as we're defining these interfaces, if we can document the security properties of them, I know that's been a constant thing in WikiData's. As you're going through, you're like, hey, I know I'm dealing with the service of this type. I don't know which concrete implementation I'm doing, so therefore I don't know whether this is safe or not safe because the security properties aren't documented. And that is something that I would like to figure out, whether it's like a standard documentation or whether it's finding some way to define that within the class itself. I don't know, but. Yeah. One thing that is scary in terms of security is that if you have two services, well, one service using the other service and both of them pass tests individually, but the one service and the test of the one service are misinterpreting the spec of the other one. So maybe I'm getting messages from one services to use in the other and the other service assumes they are clean HTML, but they aren't. All tests will pass, but I have an injection vector in the life system. So yes, that is an issue that we have to be very careful about. We have extensions, of course, like WikiBase or other ones that define different content types, and then within Core you have places like recent changes or maybe you have different types of changes or log entries or events, and then you want to format them in a special page, and it would be nice to be able to define a formatter for these new types that come from an extension and just to have interface in Core for that would be a lot nicer, and then extensions can implement services or add or replace maybe for just different cases. Maybe for more critical things, I don't know, maybe not so much, but there needs to be a way for... and going in the way of implementing an interface tends to be a lot nicer and easier to work with than the hook system, I think. We have this with Sirius, it has a whole bunch of hooks that we can implement in WikiBase to make it start to understand WikiBase content, but then it's like... It's not so nice. Yeah, I think this is an important point that allowing extensions to replace services means or provides an alternative to the current hook system that uses very well mushy interfaces, right? You don't have anything very concrete to rely on in terms of, I don't know, type checking or function signatures or anything. Oftentimes you just get an array that is passed as a reference and then you modify it somehow. That's kind of scary. But I also like the idea or the notion that maybe there should be a whitelist or a blacklist of stuff that extensions can replace. Could look into that, yeah. Why not? I'd like to play the devil's advocate and give a little thought exercise for replacing hooks with services that can be overridden. The model seems like a big improvement because you could, for example, enforce things like private methods and static methods and you can actually maintain state within your extensions override, so you have to either maintain state between different hook calls and it gets very messy very quickly. An example is central auth, for example, where it's quite difficult for it to maintain state between the different parts of where you override the user interface. On the other side, it also complicates things when you have multiple extensions trying to add functionality to the same thing because presumably the service override would extend the core class and do something with it and then set the global variable where it says you're using this class, you now use this class, but then only one extension can realistically do that because they would need to know about each other to know which one to extend. Yeah, you can use a decorated pattern to avoid that. All right. Is that something we then want to encourage in PHP? Yeah. Actually, I have done this in the past, so you would replace the original service object with something that actually wraps the original service object with that if you want. Cool. For dependency injection regarding using a framework, going back to the open question a little bit, I would personally think that using a library for this is probably overkill, as has been said before, but maybe for slightly different reasons, which is that I see dependency injection more as a pattern than as a framework. And by just setting function signatures and using classes that construct objects, that is basically dependency injection. You don't need a framework to do that. That gives you much more explicit interface, unless you just more easily document things. That's actually what we do in WikiData currently. We use dependency injection as a pattern. We do not use any framework, and we don't have a DI container. We have a top-level thing that has all the object, the service instantiation hard-coded. But that means that extensions can neither define their own services nor replace existing services because there is no way to get in there. It is indeed true that you can think about DI as a pattern, separately from basically the wiring framework. These are separate things, even though they are often both called dependency injection. I'd like to talk about how we move forward with these various areas. We've got the two areas that you've talked about today. Service oriented architecture and dependency injection is two long-standing debates about just how quickly we should move to them, if we should move to them, et cetera. Then additionally, we've also got... The software engineering area generally is about making our software make sense to people, especially to people with potentially a computer science background, but that doesn't necessarily need to be the case. I think it just needs to make sense. This is a system worth learning rather than something that is a perilous mess that you want to avoid. We want to be proud of the system that we're building. We want it to make sense, and we want people to be efficient in doing so. My question slash comment here is how do we keep this area moving forward? At one extreme, we could say, oh, we need a mailing list associated with just the software engineering area. On the other extreme, we can basically say, well, it'll be some fabricator's tax. It'll just basically be a nebulous group that sometimes comes together at things like this. I'm wondering, what is the right way for this? Does this feel like a coherent area of interest, number one, and then number two, if this is a coherent area, how do we keep the collective interest and attention moving forward on this issue rather than dispersing when the buses come this evening? Perhaps also, what should the role of the architecture committee be in that context? Does it have a role? Does it even make sense to have it? Greg is asking, why is the architecture committee not just driving this going forward? I think the answer, I'll speak to this, is I think part of the answer to that is that the architecture committee is overseeing whether or not the various areas are actually functioning well, but there still needs to be an area to oversee. If it's just basically, well, the architecture committee's doing it, then it sort of lets everybody kind of off the hook and say, good, the architecture committee's doing that, and then walk away. Well, from my perspective, we are kind of pushing that direction. I mean, that's why I'm standing here, right? And that's why Gabriel just stood here. But in terms of actually getting stuff done, getting stuff written, well, we need time and resources, and these are scars, right? And I think on the architectural foundations is, well, how do you measure the impact of that? It's not going to make shiny new features tomorrow. It's going to make it easier to build shiny new features in half a year, but it's hard to sell. And currently, yeah, no one in particular seems to be responsible for implementing this kind of thing. I am happy to invest time when I have it, and I have written code, for instance, for dependency injection, but, well, it has been sitting there for a couple of months now because I simply don't have time to work on it. It still helps at least, like, that we have the architecture committee and the RFC process and the meetings, so we actually do discuss them now and decisions can be made, and I don't know, I think dependency injection is one where, as Daniel has time, where people have time can get refined, where no one has serious objections, and then you can get merged or something, but we have a process for this now, and it's just as, I mean, people have the time, which is a challenge, but the process helps a lot, and I know with things that I try to tackle, like trying to refactor recent changes, or to make it work better, or search for WikiBase, and I keep running into any, or when dependency injection, or you don't have services, and then there's no nice way to register them or deal with them, and so just keep running into this, and at least that's something that I think we can get solved soon as I hope, and it just helps to have the process. So I think a big part of what's the problem here right now is, like you say, it's a resourcing thing. I don't think I'm hearing any real objection in the room to the ideas that we're talking about here. It's just a matter of who's going to sit down and write the code to do it, and without, like you're saying, nobody truly owns nebulous parts of core like this, like the wiring that just holds core together. Those are just kind of weird things that nobody truly owns it. Everybody uses it, but nobody works on it, and I wonder, since we're standing here trying to figure out how do we resource something like this, I'm wondering if the path going forward is to give the architecture committee the resources it needs to drive these sorts of things forward. These are things that I feel that the architecture committee should own, but like you say, it's a matter of hours and day, and you just can't do everything. So I'm wondering if that's an idea going forward is giving the architecture committee both the resources and the remit to go forward with these sorts of nebulous core plumbing type things that nobody really does want to own, ultimately because you're right, it doesn't lead to a shiny new feature. It's stuff that keeps the site running, though, and makes it easier for us to do our jobs going forward. Can I respond on the resources? I mean, I think one of the things that I worry about is that whenever we have any sort of hard question, we say, oh, we need to throw resources at it, as if, you know, which really means like basically make it somebody's paid job to do this thing, and that's kind of a cop-out, I think, because basically like we don't have a huge budget to do these kind of things, and so I think we have to work, we have to figure out like how to both arrive, so one of the things that I was originally asking in which sort of led us down this path was like, I was asking how do we keep this area moving forward, because I think there are things that we can be doing that don't require full-time resources, do not require like, oh well, this is somebody's job to do this, like that we can cause the aggregation to happen, but, and then furthermore, when we talk about things like dependency injection or service-oriented architecture or whatever, there is the yes, we need to move towards this, and so having, or like there's a desire to move towards this potentially, but having like, we need to also think about like, okay, given the people and time and the problems that we have now, what is the, what can we do now, I think is something we should be thinking about rather than thinking about, well, sure, if we had more resources, then we'd be able to solve this problem. Okay, maybe as a direct response, I think one of the things that we can do is try and not make the problem worse by basically having these principles in mind and trying to write code that is, in a way, compliant with it, or at least moves into the right direction. Yeah, there's still three people wanting to say something, we're kind of running out of time, I don't know, Gabriel, do you think, do you want to do the wrap-up? Shall we take more comments? I can be quick. Yeah, we'll just be quick. So I think Robla's conclusion was correct, that it is a, there's priorities and there's projects we need to get done and there's important things that need to happen. And I think that, let's be honest, there's the lion's share of the development that would probably do this, would come from the foundation or Deutschland and we just need to make it a project that a team owns for a court, whatever, like any other project proposal process that we go through. We need to elevate architecture decisions to that level, I think. If we keep them down here at this Dev Summit that not everybody comes to, where we just brush it aside as architecture stuff and it doesn't get up to the same level as flow, for instance, I think we're doing ourselves a disservice. That's it. So speaking to the resources question and also to the team autonomy question that came up in the service-oriented architecture discussion, it seems to me that we used to have a team that at least was nominally supposed to be concerned with that sort of thing, and then the giant engineering reorg of Doom was trying to do more team autonomy by building these empire verticals and killing the team that was going across the verticals so they didn't have to communicate so much with anybody outside of their reporting structure. So perhaps that's something that needs to be looked at. To answer Rob's question on how do we implement this, from personal experience, if you want to make a large change across media wiki core and extensions, you need to write a patch and drive it for a few months, find someone bold enough to plus to it and then convert a few extensions, and then minus one everyone else's patches that don't use your system. After the wrap up. There's going to be a separate general discussion for the last few minutes or no. Go. Okay. Three very quick comments. One is in addition to specifying what we should do in the future, we should also identify those things that we are doing right now that are working and that should be preserved and deserve continuing support. I have to say that I believe the RFC meetings are very useful. It's not always easy to precisely measure and indicate what the impact of each meeting is, but I think they do a lot to sort of form and mold a shared understanding of problems. And point two is I know it's ridiculous to pinpoint any single person as being somehow critical to this process, but Aaron is and he's not here because he feels kind of disengaged and it's really important to reach out to him. If you look at media wiki specifically, he's kind of dominated like the last couple of years worth of commit activity. Third and final point, I think we're a bit insular when it comes to interacting with other communities that work on large enterprise-y mature software. And I believe that we should, when planning for like next year's summit and planning for hackathons and planning for other things come. We have a good way to wrap this up. Can you just summarize it all? The magic last words? Well, I think for services we have identified quite a few issues that we've been discussing with ops, with research engineering, with others like their ownership. And I think we work together to fix those. So I think it's good to have a session to discuss those things. I don't have a magic solution about who should be responsible. I'm very doubtful of any solution that pushes it to some authority you saw this from me, especially for very cross-cutting problems that require everybody's buy-in and input. But I think the only thing I can solve that is a process that involves people and goes up and down, convinces people. In my two cents. I have to say that I'm quite happy to find that we seem to agree largely on the general direction to move in. I think that's basically my big takeaway from the session. There's concerns, there's value concerns, there's open questions. But the general direction seems to be clear and people seem to generally agree on what that direction should be. I'm quite happy about that. I guess that's it, right? Thanks.