5 ms·
Doing things like avoiding singletons and concrete class references (tight coupling) at all costs IS premature optimization! It's just premature architecture o
by breckinloggins 15y ago
Doing things like avoiding singletons and concrete class references (tight coupling) at all costs IS premature optimization! It's just premature architecture optimization, rather than performance optimization.
Sure, if you know ahead of time that some construct is going to be trouble, don't use it. BUT, if you're writing "Mom's Recipe Book", I don't see the point in avoiding a simple singleton DB class just because you fancy that someday you won't be able to handle the spectacular load that Mom's Recipe Book is sure to generate.
The "avoid singletons and tight coupling always" argument invariably leads to J2EE-esque code and, before you know it, you find yourself writing a DBFactoryConnectionInterfaceProxyFactory or something.
I'm not saying this advice is always bad, just that taken religiously it can lead to code that is over-engineered for the task at hand.
Lastly, let's say Mom's Recipe Book DOES become the next Twitter. What's wrong with removing the singleton then? If you are replacing one bit of boilerplate code with another, grep and replace across the project works just fine, doesn't it?
- AndrewDucker 15y agoIt's about testing. How are you going to write tests for your code when calling the SaveMyLovelyChocolateBrownieRecipe method invokes a database call? Having the database connection passed in to the RecipeSaver class means that you can pass in a fake one instead, and test it.
- breckinloggins 15y agoHow about a compromise? IDB is what gets passed to stuff. Singleton::DB implements IDB, and the PHP page code passes DB::GetInstance() to the functions that take IDB.
- AndrewDucker 15y agoYup, that works. Or the functions check to see if they've been passed something, and if not then they use the singleton. So long as you can choose when to call it with an actual database link, and when to call it with a fake one your code is all perfectly testable.
- ubernostrum 15y agoIn my world, we solve the "what if it needs to write to the DB" problem by... having a DB. Seriously, creating a test database as part of the test run, and populating it from fixtures and letting the code interact with it the way it will in production is actually very, very simple. This is, essentially, the YAGNI principle; sure, in theory I can come up with a use case where that code needs to talk to something that isn't a database, but A) it's not going to happen in real life and B) re-architecting everything in the name of that possibility is premature architecture astronautics that will cost much more time and effort than just saying "we aren't gonna need that" and moving on.
- hello_moto 15y agoIt's not just DB. What about 3rd-party Web Services (Facebook, Amazon, etc). Also, can you run the whole thing in your continuous integration build? Setting up Database to run on a CI server sometime is problematic (depending on how you setup your CI, if you're using Amazon EC2 instances...). Rails solved this problem to some extend by using SQLite but one needs to install + configure SQLite for various machines. Speed is another thing. The more you write tests that hits the DB, your automation-test will take a performance hit and you'll have to do something eventually. What if you have caching by utilizing some sort of caching server? that needs to be installed and configured as well. What if the only way to test the code is to deploy it to the server and write raw HTTP GET/POST because those are the only entry point? In 2011, where there are better tools and known practice, I don't think we should labelled some of these practices as YAGNI and Premature Optimization. First of all, it's not YAGNI if you have to refactor or write another framework, tools, or some sort of patches in order to have an acceptable build time. Second, it's not Premature Optimization if the tools, the libraries, and the environment provide you with ways to implement them in no time. I think the excuse of Premature Optimization is used a lot in a context where it doesn't mean what it supposed to mean.
- deleted 15y ago[deleted]
- ubernostrum 15y agoI think the excuse of Premature Optimization is used a lot in a context where it doesn't mean what it supposed to mean. Which may be why I didn't use the phrase. In all seriousness, though, I can sit down and come up with dozens -- heck, hundreds -- of "well, what if" cases. And you know what? I don't care about 'em. I went through the phase of abstractly decoupling everything to the Nth degree because of "what if" cases. And I paid for it; I was overlooking simple and often more elegant solutions to actual problems in favor of complex solutions to hypothetical problems. Does using a real database instead of decoupled MockableWriteableDataStorageInterface mean my tests take a few extra seconds to run? Yup. Does the time I'd save running tests by writing and passing in a MockableWriteableDataStorageInterfaceImplementation outweigh the increased complexity and thus mental load of the codebase? Unlikely. And, importantly: does testing with something that isn't a real database potentially cover up bugs that only happen when I use a real database? Yup, and that happens often enough that the whole mockable thing just goes out the window right there. Anyway. I think most developers go through this phase, too, and I think it's similar to the way people spend disproportionate amounts of time worrying about dramatic but unlikely things (shark attacks, terrorists, etc.) rather than dealing with the mundane but extremely likely things right in front of them.