// composer.json
{
"require": {
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99.1
"doctrine/annotations": "^1.0", // 1.12.1
"doctrine/doctrine-bundle": "^2", // 2.3.1
"doctrine/doctrine-migrations-bundle": "^3", // 3.1.1
"doctrine/orm": "^2", // 2.8.4
"knplabs/knp-time-bundle": "^1.15", // v1.16.0
"phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
"sensio/framework-extra-bundle": "^6.0", // v6.1.2
"symfony/console": "5.2.*", // v5.2.6
"symfony/dotenv": "5.2.*", // v5.2.4
"symfony/flex": "^1.9", // v1.21.6
"symfony/form": "5.2.*", // v5.2.6
"symfony/framework-bundle": "5.2.*", // v5.2.6
"symfony/http-client": "5.2.*", // v5.2.6
"symfony/mailer": "5.2.*", // v5.2.6
"symfony/property-access": "5.2.*", // v5.2.4
"symfony/property-info": "5.2.*", // v5.2.4
"symfony/security-bundle": "5.2.*", // v5.2.6
"symfony/serializer": "5.2.*", // v5.2.4
"symfony/twig-bundle": "5.2.*", // v5.2.4
"symfony/validator": "5.2.*", // v5.2.6
"symfony/webpack-encore-bundle": "^1.6", // v1.11.1
"symfony/yaml": "5.2.*", // v5.2.5
"twig/cssinliner-extra": "^3.3", // v3.3.0
"twig/extra-bundle": "^2.12|^3.0", // v3.3.0
"twig/twig": "^2.12|^3.0" // v3.3.0
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.2", // 3.4.0
"fakerphp/faker": "^1.13", // v1.14.1
"symfony/debug-bundle": "^5.2", // v5.2.4
"symfony/maker-bundle": "^1.13", // v1.30.2
"symfony/monolog-bundle": "^3.0", // v3.7.0
"symfony/stopwatch": "^5.2", // v5.2.4
"symfony/var-dumper": "^5.2", // v5.2.6
"symfony/web-profiler-bundle": "^5.2" // v5.2.6
}
}
6 Comments
ISP/OCP on too simple an example devolves to SRP, and that is entirely fine. It tells use that most cases aren't that complex, so we avoid unintentional complexity.
ISP to shine need example where two different clients need different combination of interfaces created by splitting big one. Like one client need object that implements Interface A, but other client needs one that implement Interface B, but yet another one needs Interface A and interface B. This then leads to thinking about interfaces as capabilities, and about client code using interfaces as constraints on what capabilities its input needs to provide.
Not something that will show up in every application. However if it is correct abstraction its very powerful.
OCP to shine need example that is Expression Problem or comes close to it. There we start to see that some domains require degrees of freedom and also that its responsibility of developer to eliminate those freedoms that are useless for application. However Expression Problem is something that library code must deal with.
My biggest gripe with SOLID is that its acronym. Therefore wording of each rule is set in stone forever. Therefore if we get a better replacement , we can't just replace old principle, but instead we need to introduce this murky translation. Course was awesome at shining light on that in-between meaning! Thank you.
Hey Przemysław L.
Thanks for your insight, it's very valuable. Cheers!
Ok, I should wait with my congratulations until the last chapter. I cannot agree with the takeaways you talked about. Interfaces are not only about DIP rule.
First thing I want to say it that we should learn junior developers to think about the code in more abstract way. When coding, one should not care about the implementation but the contract with an abstraction e.g. "I need any class that can count spam words. I don't care how this class does the job." and implement the high level class without caring about the concrete implementation. Then everything what has to be done is a proper container configuration. Encouraging them to inject concrete class because "it's not an option" has long term disadvantages. They are not experienced developers enough to decide if a dependency is an option.
Second thing. Interfaces are very helpful when you want to tweak dependencies based on environment. Traceable/Debuggable classes are good examples in dev env. Mocks are good examples in both dev and test environment. In test env interfaces are very helpful when you have to write stubs.
Third thing. I had many tasks when I had to tweak into/add behaviour to some existing code but I just wasn't able to because the whole process was so tighten up by the concrete classes depending on other concrete classes and so on. If I had an interface I could have done something but I had to end up with violating some rules (including my personal rule not to write bad code).
It's like a snowball. Every next bad line of code, bad design speeds the snowball up.
Hey Fabien, thanks for your feedback, you mentioned a few good points about when introducing an interface may be helpful. The key thing of SOLID is to have a set of ground rules that may guide you in designing your application. It should aid you at making a design desicion but without forcing your application to be SOLID compliant, and you should be aware of when it's better to violate a pricinple than following it.
Besides that, I'd like to say that it's better to wait for introducing an interface into your application (I'm talking about your own application's code, not about a reusable library/bundle) because everytime you add a new interface into your application it will aslo increase its complexity. So, my rule for adding interfaces is to wait until you have at least 2 different implementations for the interface I want to create. I prefer to add tests and not over-invest in my design, and later, if needed, refactor my design as much as required (an easy thing to do when you have tests covering your back).
Cheers!
Thank you for this tutorial. I wish it wasn't only 18 episodes long. I think the topics like SOLID, Design Patterns et cetera should deserve more attention. Those require focus, thinking and a lot of hours worked but the benefits are huge. It's something one has to understand. On the other side we have tools/tutorials about things a developer has to learn rather than understand and this it what I diagnose as a main problem - people get to much features out of the box and as a reason they are not forced to think. They don't learn how something works but how to use it. I see this problem a lot even with medium or senior (btw. what does it mean nowadays?) developers.
Hey Fabien,
Haha, yeah, it's always sad when the course ends :) Our mission is to explain complex things short and easy, I hope we were able to do so in this tutorial. Design Patterns deserve its own course, and we will release it someday (not specific estimations yet). This course covered only SOLID principles. For each principle in SOLID we tried to make up a good example to make it easier to understand, we didn't explain the theory only. Tutorial length is always a balance between too long tutorials where you start losing the main idea and too short where some topics may be not covered. If you think you didn't get something from this tutorial, try to rewatch it again in a while, this may help. Or, you can always ask your questions regarding the tutorial in comments below videos.
> They don't learn how something works but how to use it. I see this problem a lot even with medium or senior (btw. what does it mean nowadays?) developers.
Good tools gives you more power to complete your task simpler and faster. It also a balance. And if you're curious - you still may look at the tool's source code to see how it works behind the scene and to understand it better. Thankfully we're talking about Open Source Software and it's available to everyone. So, if you want to learn and want to know more - you can do this, nothing stops you. Anyway, you have to think about the task you have to solve, probably not all the levels as if you have a tool - low-level already was thought by the devs who designed that tool for you. But you still have to think up-level how to integrate that tool into your project and solve the task. You can refuse some low-level tools and write all that code yourself, but this way you would spend much more time on a simple task than you could. And it depends on your if it's good for you or no. If you want to learn - great, go for it. If you have some deadlines and have to make that feature work fast - probably writing it from scratch would be overkill when there's a ready-to-use solution. The downside of writing low-level things is that you at least have to test them. Usually tools are well tested and well written, because many devs are looking at the source code and constantly improving it, reporting bugs, fixing them - it's difficult to achieve when you work on that by yourself. But for better understanding and better learning - I think it would be good.
So, if you want to know more about how tools are working behind the scene - start looking at the source code, try to understand it first, then try to find bottleneck parts of the code, and if you were lucky - try to report it by creating an issue or improve it by sending a PR. In other words, you can try to become a maintainer of that tool, and I bet you will learn a lot from it.
Anyway, thank you for this feedback and your interest in SymfonyCasts tutorials!
Cheers!
"Houston: no signs of life"
Start the conversation!