It looks like you're new here. If you want to get involved, click one of these buttons!
Subscribe to our Patreon, and get image uploads with no ads on the site!
Base theme by DesignModo & ported to Powered by Vanilla by Chris Ireland, modified by the "theFB" team.
Comments
I used to work on a medium-sized dev team on big, complex, pressure-y projects handling a lot of £'s worth of transactions. The team would have design meetings, code reviews, any excuse really to get in a room and try and loudly outsmart one another.
I enjoyed it at the time but, in retrospect, I'd rather piss in my own eyes than go back to it.
OOP suits some things and not others.
It's not really doing anything behind your back it just doesn't offer those raw data types.
It is a lot better than it used to be as it does have some specific libraries for doing bit twiddling and marshalling that it didn't used to.
This is a great example
So the approach you have in the first example I would say is bad separation of concerns as it's coupling implementation details in the database to the application logic. Someone might innocently change some aspect of the database and accidentally give all users admin rights without it being obvious why that should happen.
The second approach using typeOf is much better, but it's not OOP in the sense that the behaviour is external to the object. Any time you see some code doing an "if" or a "switch" on a typeof it generally means that you have procedural logic in an OOP codebase. The book "Refactoring" by Martin Fowler has some really good examples of how you can avoid this and factor it out of codebases in which you find it.
The third approach using IPerson is OOP because the behaviour is encapsulated in the object. In this case I also agree that having an interface is a good idea, but I would almost certainly make it a minimal interface to be implemented and not an abstract base class to be inherited from. I might call it something like an IApplicationOwner that just has a "getApplications" method and nothing else. This is the "Interface segregation principle" from the Bob Martin "SOLID" book.
The reason being that at some point in the future you may need to assign ownership of applications to something else (or example if you opened up a system to system API). If you have a IPerson interface then you would end up having to make an APIClient object implement an IPerson interface with loads of methods that make no sense or even worse make APIClient a subtype of Person (I've seen lots of codebases with this kind of weird stuff in it)
As other people have said there is no one right way to do it so please don't stop contributing to the thread as it seems you have lots of good stuff to add.
Seriously: If you value it, take/fetch it yourself
The other was the head designer for the whole of dev, not just my team. He lived and breathed software and would spend his evenings reading books and building PoCs which is something I've never been inclined to do myself. When working with him planning out new work he'd listen to you, and if you questioned one of his decisions would take it on board and - if you had a sensible enough objection - would bend things your way. Conversely, if you were whining for the sake of it, he'd tell you to piss off.
Last I heard they're both earning big dollars and quite right too.
Anyway, it's probably working with the pair of them that gave me the inclination to learn for myself the same way. At the moment I have a luxury few coders ever have, me included - time to think and learn. It probably won't end well, but I'm feeling sharper than I have done for a while as a result.
Focusing on two things at the moment - MS's implementation of Dependency Injection in .NET Core which a) unless I'm missing something (and it's early days to be fair) still has too much coupling in terms of one binary's necessary awareness of another, and b) far too much magic. There seems to be a bit of guesswork on the framework's behalf when it comes to injecting the concrete implementation into the constructor and that sort of thing makes me a bit itchy (it just happens, yeah? Hah not on my watch pal.). I think it might get put on the back burner fairly soon.
The other thing I'm trying to decide is what sort of form randella's repository pattern might take. That's the fun one.
It's been a while since I've enjoyed coding so that can't be too bad I guess.
Dependency injection is a tricky one.
Doing it yourself does end up in Joel Spolsky's world of Abstract Hammer Factories, but a lot of the dependency injection frameworks make me itchy with the amount of magic they do. I'm not familiar with .NET, but I'm guessing it is like Guice or Dagger from the Java world.
I really enjoyed this blog post on dependency injection and functional programming:
http://blog.ploeh.dk/2016/03/18/functional-architecture-is-ports-and-adapters/
It kind of clarified to me that when you use some of the modern best practices for OOP implementation you end up shoehorning OOP into something that increasingly looks like FP.
Some of MS's 'magic' implementation of existing ideas works very well in small doses (Generics springs to mind) but I could spend a long time on DI and not be happy with it. I may not be God's gift to programming but I've been around for long enough that I know when something's not going to help me do my job and get working software out the door quickly enough.
As for the OOP discussion, this project and the next one in the queue both deal with entities - there's no getting away from the fact that they lend themselves to OOP. This isn't just me thinking like a wizened old time-served SQL dev obsessed with his 3NF either, it's just the way they've panned out.
As long as I can get enough separation between the data and the UI I'll be happy as I have one eye on moving to mobile app dev - something that keeps getting bandied around by management but will take me to drive it. Hence the focus on the repository pattern and a generic endpoint for the UI to consume. WebAPI is current favourite.
A year ago I wouldn't have even read this thread, I was about to jack in the lot. Now I'm cheerfully talking about code with strangers on the internet. What has become of me I don't know, my 22-year-old self would be disgusted.
Anyway I'll have a look at that blog later, looks interesting.
For example if you want to test some code which requires a database connection it becomes almost impossible to have a tight test loop if you require a DB full of production data to be initialised each time. If you are using DI you just inject a DB mock and you don't even need a DB running.
DB mocking, funnily enough, is coming up in the tutorials I'm following. OK, it might not get binned just yet.
Clever bugger
@randella what is it about DI, specifically MS's 'implementation' of it, that you don't like?
Something I heard said once, and thought was quite amusing: "Can we stop saying Dependency Injection and just say passing a parameter, since that's all it really is?"
I'm a TDD enthusiast, I could easily bore you to death about it.
If it can't be prototyped in a series of bash one-liners then I start to lose interest.
On a more serious note, is it not true that a lot of this type of user/admin management logic is now commoditised and can be automated via various frameworks these days, without having to write stacks of boilerplate code?
I'd agree with that.
Dependency injection really is just passing additional parameters in which is what you would do anyway if you were using a functional approach. It's only really the need to preconfigure an object and then pass it around. In an FP context you would just use a "bind" or a lambda.
For example in Java using dependency injection you would typically do something like
public MyClass {
private final DB db;
MyClass(DB db){
this.db = db;
}
public List<User> getUserByID(int id) {
return db.getUser(id);
}
}
but if you were doing the same thing with a functional approach you would have something like this
public MyClass {
public static List<User> getUserByID(DB db, int id) {
return db.getUser(id);
}
}
No member variables and no state stored, just static functions
If you want to pass something around without having to push the DB reference around you can just bind it. (Java doesn't have an actual bind function so you have to use a lambda)
(id ) -> {MyClass.getuserByID(db,id)}
assuming "db" was in the scope of the lambda when you defined it.
So I'm sure the vendors of those application frameworks will tell you.
I've tried to write apps with CRUD generators and you get up and running quickly, but if it's a long lived project you pay for it a hundredfold over the lifetime of the project as it usually creates a mountain of technical debt.
Been looking in detail into PHP frameworks recently and while there's plenty of "ahh, that's a clever way to deal with that" I still feel eveything gets abstracted too far and if your project doesn't fit the paradigm it's hard to break out of.
Oh yeah and as for dependency stacks in JS frameworks and the tools to manage the tools - it beats me how that's got so far - but I just read about the hammer factory - hits the nail on the head, that.
I'm just starting to get into both DI and TDD and am hazy on the relationship between the two and how one can benefit the other. At first glance I'm not keen on the .NET dependency injection container - without more knowledge (I'm on my way!) it seems a bit 'black box'. It's not that I 'dislike' it, I just need to know how things work, as I'm not very good at just plugging things in.
The other thing I tend to do is overthink things and imagine they're a lot more complicated than they are. I'll get back to you.
Also apologies to the OP for dragging this so far off piste - sorry I couldn't help more with the original query!