How to become a better programmer ?
Design principles I : kiss, dry, tda, soc, yagni
When I started programming I was happy that my program was compiling and was working as I expected it to work, but as I wrote more and more code over time I’ve started to appreciate design patterns.
Design patterns not only make my code better, more readable and easier to maintain, but also save me a lot, and I mean A LOT of debugging hours.
That is why I wanted to share some with you.
This design patterns originated from so called “gang of four”, authors of a “DesignPatterns Book”. They introduced this principles that are extremely useful especially in object-oriented programming.
Probably you are already using all that, but it is always good to refresh your knowledge.
All code examples are in TypeScript.
KISS : Keep it simple stupid
The main concept of this pattern is to keep as simple code as possible.
That means each method, class, interface should be names as clear as possible and also logic inside functions, method etc. should be clear and simple as it can be.
Example of how KISS does NOT look like:
In this example we have code that is telling us nothing.
Class name, methods name are not written properly.
Body of a method is a mess with a lot of
if and not maintainable.
After using KISS principle, it does look like this:
As you can in above code there is KISS principle.
This is scalable solution: we can have multiple countries and add new discount region with ease only modified a
discountRegions property in a country class.
Thanks to the interface we can also make sure that each new country have the required properties.
Payment class has also methods that are named after what they do and thanks to that structure we optimised code to have only one if.
And that is kiss: clean, simple code.
DRY : Do not repeat yourself
This concept is advising us to divide code that does the same thing to small parts.
Sometimes we have multiple lines of code basically doing the same: like filter by array with specified criteria, adding some things to object etc.
Usually good practice is to get rid of it.
Example of not good DRY code is:
In this example we have multiple added days with basically the same code to the class. We can avoid that by creating a method that is doing for that. Also with manually typing day name multiple times we are extending possibility of an error.
Example of proper class with good DRY code:
In this example instead of typing manually each day we have implement
enum with predefined day names and also introduced
Day class. Thanks to that we can extend it to add more features to this class in the future, like
getDaylightTime . Also we’ve implement
addDay method to
Week class which are doing pretty the same thing, but now if anything changes we have to update only one place in code instead of seven.
That is a DRY principle.
TDA: Tell don’t ask
This principle suggest that we should write code in a way that object behave rather then in what state they are in.
This can avoid unnecessary dependencies between classes and thanks to that have more maintainable code. It is strongly related to code encapsulation.
Example of code with no TDA principle:
As we can see
UserService access many times to
User object properties, especially when updating
User.tokens what if will we have that in many parts of our program and will want to change logic how it works?
Also take a look at validators: all logic how it should behave is inside a method, but we should make it more scalable and reusable.
Below is an example how to do it.
Example with TDA:
At first sight it may seems like there is over-complexity and more code that is the need to be.
However, in a long shot thanks of a encapsulated and independent validator we can use it many times in many generic situations.
User class are only used inside of it,
UserService is calling up level method to access it. Thanks to that we have all logic in one place, so when we will want to use
User class somewhere else, program will behave as we expect it.
SoC: Separation of Concerns
This principle is telling us to separate responsibility of a single class to this class and this class only. Objects should not share what they do.
Each class should be unique and separated from the rest.
Example of code without SoC:
AccountService that is responsible for multiple things: logging, validating and operation of users balance. Also
TDA is not implemented.
We should separate validation and create external logger to use in future in other modules.
Example of proper SoC:
We now have separate state and functionality of each class: Validators, User, AcocuntService and LoggerService.
Thanks to SoC we can use this separately in many different modules in our application.
Also, that code is easier to maintain, because of fewer places that logic exists.
YAGNI: You ain’t gonna need it
That principle is not telling us how to do something in code directly, but rather how to code effectively.
In general it says that we should code only things that are required from us in this particular moment.
For example: when we will have to do validation of email and password field, we shouldn’t do validation of name, because we may never need it.
It is really as
TDD : we write test only for micro feature and write minimal code required to work on that.
`YAGNI` is trying to save us time and focus on most important things in our sprint.
That’s all folks.
I hope that thanks to that article you learnt something or remind some things you already know. :)