I’m creating a thread on #softwaredesing. One tip per day.
Until no advices are left or I reach thread limit. Whatever happens in the first time.
Tip 01: Do not subclassify concrete classes.
Tip 02: Variable names should indicate role. Never type
Tip 03: Do not comment code. Write declarative methods instead.
Tip 04: Do not user NULL. It generates a lot of coupling
Tip 05: Do not refactor unless you have great coverage. Just don’t
Tipo 06: YAGNI: You are (never) going to need it. Don't over design. vic @xkcd
Tip 07: Do not create incomplete objects. They should be valid since inception.
Tip 08: Do not use Setters or Getters. They expose your internal state
Tip 09: assertons and invariants should be turned on. Even in production environments
Tip 10: favor immutability. Just a few objects should mírate. And only in an accidental way.
Tip 11: Avoid Anemic Domain Models. Objects should never be a "bunch of data". Even the smaller ones have integrity rules and design decisions to hide (i.e. Coordinates or Dates)
Favor Composition over Inheritance. Do not create deep hierarchies. No more than 2 levels.
Tip 13: Classes' Single responsibility is to create instances. So no static or virtual methods should exists but the single canonical constructor
Tip 14: If you use a static language type to Interfaces, Never to classes. If you are typing to abstract classes you are introducing coupling
Tip 15: Hidden assumpstions are our second worst enemy. Make everything explícit. Beware of his close friend and first on our list: coupling
Tip 16: If you stick to TDD then you will never have uncovered code. Yes, U will hardcode a lot at the beginning but this is definitely better than #goldplating
Tip 17: Avoid Native data types. Even if your language have first class objects and Data objects (Strings, Dates, Arrays, Numbers)
Wrap them and protect them.
No. Performance is not always an issue.
In doubt, benchmark it. Don't *guess* things
Save milliseconds or save coupling
Tip 17: Avoid using IDs.
IDs are for external references, objects should know by each other by reference, not IDs.
Retrieving a full reference graph is an accidental problem, not an essential one. In real world those problem don't exist.
So keep your models as clean as possible
Tip 18: Use real object names. Think on metaphors and find real 'not evident' objects. Figure out how a 'paper system' would exist and reflect on the role of each part.
Avoid names like: Helper, Utils, Base, Abstract, Manager etc.
Tip 20: Do not create classes/interfaces with lots of methods. Think about cohesion.
1) if the class is large, your hierarchy might be wrong (specially if it is abstract). favor composition 2) it the Interface is large use interface segregation
Tip 21: Abstract classes should have no implementation, no attributes, just protocol. Abstract protocol most often
Composition is there for us.
Traits (when available) are a second choice
Tip 22: variable names should be injected into functions as roles and should not be named according to their accidental type
Wrong
function enroll(Student $student, School ) {
Better (not quite right)
function enroll(Student $applicant, School $learningVenue) {
Tip 23: Avoid accidental coupling
Adding persistence, serialization, displaying, importing, exporting code to an object bloats its protocol and brings coupling.
Objects must not be aware of them
Keep them as far away as possible
Tip 24: Bottom up designs favor domain learning and incremental business rules discovering.
Create your objects from concrete uses cases.
Unlike other architectures we don't need a detailed blueprint of every aspect before stacking our first bricks
Tip 25: Avoid Fragil (Erratic) tests
If you can't rely on tests you will fall under the broken window syndrome.
Try to find what is erratic. If test have no control over it, refactor them.
Tests must be in full environmental control. Avoid Coupling
If impossible remove the test
Tip 26: All validations should be performed on instance creation.
If validation is complex it should be in another object (a Factory) which should have their own tests.
Don't validate on front end
It traffic is a concern you can do just basic validations (Data types) on the FE
Tip 27: Avoid settings (specially boolean)
Settings do not add value.
They add coupling and complexity
Are hard to test and bring "undesired Ifs"
They don't make systems more flexible.
300 boolean needs to test 2^300 combinations.
There are about 10^78 atoms
we are short
Tip 28: Avoid Ninja Coding and Cowboy coding
Hacking will win battles for you but you are surely going to lose the war.
Don't buy yourself coupling
Tip 29: think on objects related to contexts
The same real object might have different responsibilities and roles according to contexts.
Contexts and roles are essential in big systems
If you see the same object in different contexts with same responsibility is a #codesmell
Tip 30: DRY
Don't repeat yourself.
You can repeat once. You can repeat twice
Make things work. Cover it. Then Refactor
Repeated code is a #codesmell of a missing abstraction.
Find what is repeating (it's not just text. It's a contextual sequence of collaborations) and extract it
Tip 31: Cover your branches
IFs and elses are #CodeSmells
If you really need to use them test and cover both cases.
Don't create defensive conditions you are not ready to test now.
If you cannot test the conditions your system is too coupled to scenarios you cannot control 💩
Tip 32:Never anticipate change
Avoid Goldplating and YAGNI
Neither you nor your client can predict the future
Make things work, create good models using real world metaphors
If changes come they will surely be welcome
(Of course change always comes, but not from where U expected)
Tip 33: Favor real names over Pattern names
Patterns are good for a common language.
But they are always worse than a real world entity name.
#CodeSmell: a Strategy is almost always present with a real domain name.
Switch to BDD and put away implementative solutions
Tip 34: Do not use ids.
bind your objects using real references to real objects.
If you need to provide an external reference use a real domain ID (not a made up one) , preferably a dark key (like a GUID)
Tip 35: Fail Fast.
Create exceptions if contract is violated.
Never coerce or bypass issues
Don't create a Class for every exception unless behaviour is different.
Corollary: If behaviour changes related to 'data' (i.e. an error message) class should be the same.
Don't Pollute
Tip 36: Do not use graphic tools to design
Most tools show attributes too early.
Graphic tools don't compile or execute
Focus on behaviour, protocols and interfaces.
Code don't lie.
Tests are your friends
Tip 37: Always subclassify by domain (essential) relationships.
Never subclassify for implementation reasons.
Don't create accidental hierarchies.
Look for Nature Taxonomies
Most languages give you only one subclassification axis.
When in doubt , favor composition
Tip 38: Prefer composition over traits
Traits are hard to test and bring more coupling that composing objects
Tip 39: Choose awful names for classes
Nobody (Even You) knows what a class represent until adding its protocol and its relationships.
Put a meaningless: TOBERENAMEDAccount.
After some days (and tests) make a rename
Choosing a name at first glance and keeping it is a #codesmell
Tip 40: Don't worry about performance (yet)
Making performance changes over a Good model covered with tests is easy.
Just follow this algorithm
-Don't assume anything
-Benchmark
-Fix Pareto
Making functional changes on premature optimization models is near imposible d/t coupling
Tip 41: WET
Write everything Twice
Don't generalize with two examples.
You can ask yourself "Haven't I written this before?" two times, but never three.
Tip 42: avoid repeated code
Repeated collaboration patterns are hard to maintain, debug etc
Too many people talk about repeated code, which is very easy to find using regex and linters.
Repeated design decisions are harder to find. Aim at there, instead !
Tip 43: Avoid using test doubles
Test Doubles are to bypass real objects because tests needs to be in full control. For example it is better to mock real database.
But mocking domain objects is discouraged since we should test real interactions to avoid false safety
Tip 44: Favor polymorphism on interfaces over Subclassing
Using NullObject Pattern is better for NullObject to be in a completely different hierarchy than RealObject
Use interfaces when possible.
If you add a new responsibility to the real object, add to the interface
Tip 45: Make explicit calls to subclasses
Do not use metaprogramming to traverse subclasses.
This dark references avoid refactoring and generate hidden coupling.
Make the list explicit. so you can also mock it and have full control on tests
Tip 46: Use mutation testing
Mutation testing talks a lot about your quality and a bit about your model.
A small (mutated) change should break a few tests.
If it breaks a lot of them your system is too coupled.
Even if you use a language where 'primitive types' like strings, arrays & numbers are not real objects wrap them as much as possible
You can reify the 'name' object which is not just a string or the 'money' object which is not a number
try it
Tip 48: Mocking and Test doubles
-Never mock business logic.
--If you have a heavy calculation algorithm, use another (not a mock one)
-Mock non business if you need (Api, oauths & specially databases)
-Tests should be in full control
You can use dependency injection for that!
Tip 49: Use refactorings
Safe refactorings are made by IDEs. don't change functionality. make code clean and modular
Choose an IDE that support as many as possible
Human refactorings are more tricky. They involve changing the how without changing what
-without tests is suicide
Tip 50: Choose your stack wisely
There's no such thing as a general purpose language
Check your project lifetime.
There are different weapons for short term shippable projects and large or legacy ones.
Always consider the accidental complexity.
No silver bullet
Tip 51: Use lots of small objects
Object creation is cheap. And object destroy is also very efficient
By using lots of objects, you can make sure that each object has one job and only one job (Cohesion)
Think as human cells analogy
Human organs rely on them
Or atoms, quarks..
Tip 52: Classes should be named after real entities and following metaphors
Avoid prefixing classes with letters, types or symbols
They generate accidental coupling and don't add value
Time and objects lifecycle are intertwined.
When your design is ready always double check how will your model support their change and evolution over time.
This is an invisible axis on every design: Objects and relations evolution.
Iterators, Yields and generators are more abstract and are generally less coupled than while, for, repeats etc.
Iterators work over objects while whiles don't.
Fors are imperative.
Iterators are declarative.
Tip 62: Don't break encapsulation
Don't expose #getters.
Delegate obvious responsibilities to objects.
Wrong:
if (p.getAge() == 32 years)
Right:
if (p.isAged(32 years))
Think about Law of Demeter and avoid coupling !
Tip 63: model state
Model workflows, transitions and fsm with state pattern.
This way you will avoid ifs and favor polymorphism and honor open closed principle
Don't use strings to model state. Be respectful to your models
Tip 64: Model Strategies
Encapsulate what changes
Delegate into strategies
Unit test them
Hardcoding default strategy parameters is a #codesmell
They should be polymorphic
Don't use lambdas (closures or anonymous fn) heavily, wrap them on strategies
they deserve an object
Tip 65: Subclassing driven by Fear
If you need a small change to an existing class don't subclassify it. (Tip: 01)
Change it or refactor it
Think about Liskov
Method Overriding is a #codesmell of bad coverage, inheritance code reuse and coupling
Software is not for cowards!
• • •
Missing some Tweet in this thread? You can try to
force a refresh
Alejandro writes interesting content on software development and machine learning.
He teaches Computer Science and his content is great.
I love interacting with him.
Allen is a DDD passionate. His opinions are very strong and accurate.
I enjoy his development tips AND management and agile humor a lot.
I liked very much his courses on LinkedIn.
1 - Check your phone after a couple of hours.
2 - Keep an eye on the app with the most notifications
3 - Block them
4 - Don't fear #FOMO. Deal with it
5 - Repeat once a day.
1 - Use blocks of time without interruptions (timeboxing).
2 - My favorite is @PomodoroTech.
3 - if you come across new tasks just write them down.
4 - Don't multitask.
5 - You cannot switch until time is up.
6 - 25 minutes it's a good slice.
Solutions: 1) Refactor methods 2) Rename methods to more declarative unes 3) break methods 4) If a comment describe what a method does. Just name the method with this description