Do Best Practices Matter?
telkins.dev
telkins.dev
Look at nutrition with a new superfood each year (pomegranate, seaweed, chia seeds, coconut oil, turmeric, ...) a new diet every couple years (keto, paleo, etc)
Did the superfood of 2018 suddenly stop having all the antioxidants "benefits" ? Or did the hype cycle burn out?
Once I learned how to zoom out I found it really difficult to work with a large number of engineers. I feel like I’m really overdue to step out of a hands on role nowadays.
I would claim that the ability to not do these is what defines a senior.
Best practices are cargo culting if they aren't adapted to the local context.
A codebase with consistent styles and patterns is easier to work on than a chaotic codebase, it would definitely make you better at shipping
And so on
It's the constant churn of dropping the current thing for the new cargo cult whenever it comes along. Cargo culting destroys consistency by constantly seeking the next new hotness
We'd have massive consistency across the software industry and yet that would be an absolutely terrible idea.
This did not make the team better at shipping something useful.
Consistency is bullshit if it doesn't help you ship something that people care about.
Consistency helps keep things more predictable and simpler to interpret and change.
It probably works for someone who came up with a practice that they don't want questioned or being held up to reason. Other than that, it's always bad.
There are practices I like. There are practices YOU like. There are practices that are demonstrably good in certain ways for certain situations.
Instead of best practices, seek responsible practice. Develop your heuristics. Try things and learn your craft.
This is the problem in a nutshell.
Someone comes up with sensible advice, and like a bad game of telephone it gets stripped down to some brain-dead phrase that gets parroted around by reflex. And it's everywhere in software. It was always things like "prefer composition over inheritance when possible" - people chose to ignore it, and go ham with sprawling inheritance trees and design patterns for different languages because of a superficial understanding of software because we optimize for all the wrong things. There's interview questions where they'll ask what are the four pillars of oop or some nonesense, and one of them will be inheritance or something and so if you're not doing it that way, it's bad practice.
The part I disagree is about the OOP. It’s not the best to write software, but very often the best way to design software which has to deal with complicated mutable state.
FinTech system running on servers probably doesn’t need mutable state much or at all: things are immutable, transactions are appended to append-only ledgers, and the mutable state is only present in external systems like SQL databases. However, it’s borderline impossible to make a videogame, rich text editor, a file system, GUI framework, or an XML DOM without some form of OOP.
I remember the first time I took a high-level programming theory course and ran into procedural languages and to that point I'd genuinely not even considered that another paradigm existed, I'd had OOP rammed down my throat in the form of C++/Java for 3 years straight.
Honestly, I don't know. I rarely find a need for it in my projects, but I'm more of a systems engineer than an application developer.
I would claim that the bigger problem is people try to encapsulate things that shouldn't be.
[1] http://staff.washington.edu/gmobus/Academics/TCES202/Moodle/...
[0] https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m...
I think Tesla is guilty of this when it comes to their manufacturing. Elon wants to do everything from first principles to remove waste, meanwhile the “old guys” designed and rolled out competitive products to mass production, while Tesla struggled for years. Experience matters, but doesn’t mean anything if the playbook keeps getting thrown out.
Rookie mistake! I'm usually very critical of OO, but this ain't it. Good OO is about delegation of behaviour. The Loan is not the payer, so no make_payment() method please. Same with create and get_offers (unless we're just talking about constructors/getters here, but I don't think that was the intent). If a Loan did have a make_payment, and get_offers: why stop there? It's also going to need calculate_interest(), persist_in_db(), renegotiate(), compare(), calculate_amortisation(), get_currency(), get_minimum_repayment(), forgive(), calculate_late_fee(), alert_late_customer(), and a hundred others to be figured out along the way. So it's good OO for a Loan to just be struct-ish (There's even a dumb word for it - "POJO"). Or, even better, just a UUID!
You can apply some SOLID cargo-culting to the above. If you put so much behaviour into Loan, you'll be forever changing it, updating it, and risking unrelated breakages, violating the Single-responsibility principle ("one reason for a class to change"). I'm not a huge fan of that particular principle (it's vague and doesn't tell you how to fix it!) but I am a fan of Dependency Inversion (which does!).
A Loan is abstract, we both know what we're describing - even though we have completely different tech stacks. If a Loan has get_offers(), those offers will need to come from somewhere, whether you're talking about other classes (OfferService? DiscountService?) or over http or via a database or something. And those are concrete (Java! JSON! Rest Calls! DB Tables!) DI says to flip the design around so that the concrete things instead know about the abstract Loan, and the Loan becomes sufficiently dumb. Then when it comes time to change interest calculations, you change only the InterestService, likewise with CurrencyConversionService, OfferService, etc. You're back to single responsibilites!
> It turns out the command structure checks all of these boxes. It's dead simple to understand. There's no layer of indirection trying to piece together OOP hierarchies. It encapsulates the business logic developers actually want to run in a single place, you don't have to figure out how to wire together a bunch of objects on your own. And testing is dead simple, it's just a function with easy to understand inputs and outputs.
If you skip the indirection and just test all your logic in a single place, you're bound to be tripped up by your dependencies. You can probably test 80% of `calculate_interest.rb` with just inputs, functions and outputs, but `make_loan_payment.rb`? There's going to be dependencies that you shouldn't invoke in a test scenario. The indirection & wiring is how you organise the code so that you can put test-doubles in the right places, and control exactly what you want to test for.
The point I was trying to convey is not that OOP is bad, it's just a tool after all and some codebases can be great, but rather there are multiple ways to structure and write code that come with different trade-offs (FP is another obvious example). Many developers don't bother to understand these tradeoffs and go deeper and deeper down the abstraction rabbit hole to the point it becomes harmful, without questioning what value they are actually getting from it, think FizzBuzzEnterpriseEdition.
Stripe realized most devs were writing code to be executed in a "lambda style" way and optimized the experience for that via Commands, which I thought was cool. I phrased it as "The OOP Myth" since I've only seen large companies follow OOP so it _was_ pretty shocking to me to see this in action.
we all spoke the same language.
now say you are lazy and your "resume" will get immediately trashed.
different culture and people.