ad_google

sábado, 26 de dezembro de 2020

SOLID principles in software development




Since i started programming i always found it something difficult to do. It didn't seem natural and i lacked good practices to write the code. Most of the times I would be lost on where to start.To be honest, doing code, is an hard task and i don't believe who says otherwise. It requires a mindset. Not everyone has the reasoning to do these kind of tasks. It takes years of knowledge and experience to be good at it.

As a specie, humans give names to everything, because thats how we communicate to others about some object, concept or whatever it is.We like to categorize, to organize things, in programming we do the same with the principles we use for good code practices.What happens with these patterns is that when we identify what kind of task we have to do we will identify the pattern and apply it. 

Next i will talk about the SOLID principles, this is an acronym that we should be remembering, it comes from the early 2000.

It means the following: Single-responsability principle; Open/Closed principle; Liskov substitution principles; Inversion segregation principles; Dependency-inversion principle.

Let's now see what this fancy words mean individually.

Single-responsability principle

A class should have only one reason to change.

Why? Because having a class that does many different things, will make a mess and it will have to change frequently.

An example using a User class

class User

{

    void CreatePost(Database db, string postMessage)

    {

        try

        {

            db.Add(postMessage);

        }

        catch (Exception ex)

        {

            db.LogError("An error occured: ", ex.ToString());

            File.WriteAllText("\LocalErrors.txt", ex.ToString());

        }

    }

}


The method CreatePost() in the class User does many different things.

For example it logs the error on a file and a database if an exception occurs.

To comply with single responsability we add another class that will be responsible for logging the errors.


class Post

{

    private ErrorLogger errorLogger = new ErrorLogger();


    void CreatePost(Database db, string postMessage)

    {

        try

        {

            db.Add(postMessage);

        }

        catch (Exception ex)

        {

            errorLogger.log(ex.ToString())

        }

    }

}


class ErrorLogger

{

    void log(string error)

    {

      db.LogError("An error occured: ", error);

      File.WriteAllText("\LocalErrors.txt", error);

    }

}


Open/Closed principle

Software entities (classes, modules, funcions, etc) should be open for extension but closed for modifications.

For the code to comply with this principle, we may use inheritance and interfaces, they will enable to polymorphically substitute classes.

For example, we may want to add to different database tables a message, if we do all on the same class the following can happen:

class Post

{

    void CreatePost(Database db, string postMessage)

    {

        if (postMessage.StartsWith("#"))

        {

            db.AddAsTag(postMessage);

        }

        else

        {

            db.Add(postMessage);

        }

    }

}

What we have above is horrible, at least creating new methods would be a bit better.

Applying the principle, the class Post will be closed for modifications but open for extensions, we will have the much better code:

class Post

{

    void CreatePost(Database db, string postMessage)

    {

        db.Add(postMessage);

    }

}


class TagPost : Post

{

    override void CreatePost(Database db, string postMessage)

    {

        db.AddAsTag(postMessage);

    }

}



Liskov substitution principle

It means that subtypes must be substitutable for their base types.

By other words, instances of a class should be able easily replaced by child classes without altering the correctness of the program.

class Post

{

    void CreatePost(Database db, string postMessage)

    {

        db.Add(postMessage);

    }

}


class TagPost : Post

{

    override void CreatePost(Database db, string postMessage)

    {

        db.AddAsTag(postMessage);

    }

}


class MentionPost : Post

{

    void CreateMentionPost(Database db, string postMessage)

    {

        string user = postMessage.parseUser();


        db.NotifyUser(user);

        db.OverrideExistingMention(user, postMessage);

        base.CreatePost(db, postMessage);

    }

}


class PostHandler

{

    private database = new Database();


    void HandleNewPosts() {

        List<string> newPosts = database.getUnhandledPostsMessages();


        foreach (string postMessage in newPosts)

        {

            Post post;

            if (postMessage.StartsWith("#"))

            {

                post = new TagPost();

            }

            else if (postMessage.StartsWith("@"))

            {

                post = new MentionPost();

            }

            else {

                post = new Post();

            }

            post.CreatePost(database, postMessage);

        }

    }

}

We can observe above how the call of CreatePost() in the case of a subtype MentionPost won't do what it is supposed to do; notify the user and override existing mention. 

Since the CreatePost() method is not overriden in MentionPost the CreatePost() call will simply be delegated upwards in the class hierarchy and call CreatePost() from it's parent class.

Let's correct that mistake.

class MentionPost : Post

{

    override void CreatePost(Database db, string postMessage)

    {

        string user = postMessage.parseUser();


        NotifyUser(user);

        OverrideExistingMention(user, postMessage)

        base.CreatePost(db, postMessage);

    }


    private void NotifyUser(string user)

    {

        db.NotifyUser(user);

    }


    private void OverrideExistingMention(string user, string postMessage)

    {

        db.OverrideExistingMention(_user, postMessage);

    }

}


Interface segregation principle

Clients should not depend upon methods it does not use.

It states, that we should not add new functionality to an interface in use and instead create a new one if needed.

An example of a violation of the principle:

interface IPost

{

    void CreatePost();

}


interface IPostNew

{

    void CreatePost();

    void ReadPost();

}


In this example, we first suppose that we have only a method CreatePost() on the interface IPost, but later we had a new method ReadPost() so that the interface becomes IPostNew.

The right way to do, is to create a new interface.

interface IPostCreate

{

    void CreatePost();

}


interface IPostRead

{

    void ReadPost();

}



Dependency-inversion principle

High level modules should not depend on low level modules. Both should depend on abstrations.

Abstration should not depend upon details. Details should depend upon abstrations.

This principle in software, means that we should decouple modules. To comply with this principle, a design pattern called dependency inversion pattern exists, that most often is solved by dependency injection.

Dependency injection is an huge topic, it is used by injecting the dependencies of a class through its constructor as input parameters.

Let's take a look at an example:

class Post

{

    private ErrorLogger errorLogger = new ErrorLogger();


    void CreatePost(Database db, string postMessage)

    {

        try

        {

            db.Add(postMessage);

        }

        catch (Exception ex)

        {

            errorLogger.log(ex.ToString())

        }

    }

}



Observe that we create the ErrorLogger instance from within the Post class. This is a violation of the dependency inversion principle. If we wanted to use a different kind of logger, we would have to modify the Post class. 

Let's fix this by using dependency injection.

class Post

{

    private Logger _logger;


    public Post(Logger injectedLogger)

    {

        _logger = injectedLogger;

    }


    void CreatePost(Database db, string postMessage)

    {

        try

        {

            db.Add(postMessage);

        }

        catch (Exception ex)

        {

            logger.log(ex.ToString())

        }

    }

}


By using dependency injection we no longer rely on the Post class to efine the specific type of logger.

Conclusion

The principles that exist actually may not be the answer to everything, because new and improved ways of doing things are being discovered constantly. Personally, i intend to keep on par with the actual knowledge. 

If we follow good practices our code will be more bullet proof. More extensible, scalable, modifiable and so on. 

The requirements may constantly change so we should code in a way that allows us and everyone that use that code to rapidly make the needed changes. 

In another article i will talk about the patterns that derive from the principles i talked here.


sexta-feira, 21 de agosto de 2020

Aliexpress coupons



I'm writing this post because i have an excellent offer that i can give to new users that still don't use this e-commerce platform.

This is an online platform that sells a lot of products from China, from electronics, toys, clothes, almost everything you can think of. 

The big incentive of using is the prices which are cheap. Just be aware of you country politics from merchandise that comes from the outside. In Portugal, if i order something with a value below 25€ and i have means to prove it i don't even have to worry about it.

About the offer i have is the following, 24$ or 21,25€  in coupons, in other words, discounts. 

You just have to register through my referal:

https://a.aliexpress.com/_dUzzYZG 


Whish you a nice day and hope you find my post useful. 

Note: to be clear, this is really an offer you won't get otherwise. There in no con in registering through this referral. 


terça-feira, 18 de agosto de 2020

How to be organized




As a software engineer this theme turns out to be one of the most important for me, why? It's the only way i can improve my skills the most while at the same time wasting less energy. 

On a more serious note, if we want to get anywhere we need some organization and to apply routines or we would dive into chaos.

 

Below i leave some points and my idea is to keep upgrading this post


Getting enough sleep and nutrients 


This first point is a powerful remainder, but one of the most important ones. It can be easily neglected. 


In regards to sleep, we can stay up till late in the night for many reasons: we're watching that late show we like, playing a video-game, finishing some kind of task.


For almost every person there are enough reasons that can lead this path. 

But this is not an healthy path, it can mean we were not productive during the day and we're trying to compensate at the end of it. 

In some cases we simply cannot sleep well due to health issues and they can be psychologically. 


However the case may be, studies have shown that the quality of our sleep, makes a big difference on our cognitive performance during the day.


I'm sure, that a good night of sleep is proportional to my capacity to learn, to be collaborative, to be attentious, to have good reflexes, all of these in turn will help me spend energy in being organized.


It's worth mentioning that physical and mental exercises can help us through the day and especially the food we eat makes a great difference, because in the end that's what will give energy to the brain.


I can say from experience that while some protein and energetic snacks help me doing better on work/training, drinking beers while helping me being more relaxed certainly don't help with my concentration and memory. 


Defining goals

When defining our time, defining goals must be a priority. 

Whether it is about personal or work life, they are a starting point for us to focus our energy and serve as a starting point for identifying what needs to be done. 
The goals can be categorized as short, medium or long term goals, depending on how much time it will take for them to be accomplished. 

Once they are identified, it's time to start working and prioritizing them. 
Sometimes the goals can be worked sequentially, other times they can be interleaved, which will happen most of the time. 

To accomplish them we will need to subdivide each goal into tasks, smaller units of work to get the final objective, our goal tangible. 

A long term goal in our personal life can be owning a well furnitured house. 
This may not be hard for a few humans, but for most people it involves years of building savings while at the same time getting an idea of what we want.
Then when the opportunity arises and we have enough savings for a loan, we can finally buy the house and it's time to get the furniture and everything's needed to call it a home. 

On work, a goal may be working and finalizing a complex project. 
To start doing it, we need to start somewhere, it may be by the skeleton of the application, and then we keep adding functionality, always having in mind the bigger picture. 

Removing distractions and tracking time

When it's time to work, it's important to pick one topic and staying on it for some time without distractions.

For a burst of productivity, it helps to remove all distractions from the workplace. 
A cluttered desk is not helpful and if there is a lot of talking where we work it might be smart to find ways to tell our teammates about our intentions. Having the headphones on the ears is a clear signal of the time alone we seek. 

Estimating and tracking time is a great habit, not only for us to have an idea of the time the tasks take, but for teammates and superiors to adjust their expectations while we gain credibility. 

Taking time each day to review the progress of the work, helps to constantly evaluate how the overall work is going. 

It's important for us to remember that we need to stay some time on a task without constant distractions to be productive.

Multitasking is bad

No one really does multi-tasking, we do switch tasks and when we do that we're losing our line of thinking. 
We need to understand what needs to be done on a new task before we do it and when we go back to our last task we need to remember again what was done and were we left it.
The more switch tasks we do the more we increase the loss of productivity. 

When there are many tasks to do, it's really important to set priorities, like we previously talked. After that, starting with the one with highest priority is a must.

Using the right tools 

To track time of tasks, to place the remainders, to organize the tasks and prioritize them, take our daily notes, archive credentials and many more, we will need good tools for that. 

This point is crucial, maybe the most important for our organization depending on the tools and the usage we do from them. 

If the company already provides us tools, we better give good use to them, if some tools are not good enough then let's find alternatives. 

To summarize, we need good and reliable tools, not junk that we will never use. 


Stressful situation can happen


Studies confirm that a great percentage of workers say that one of the things that make them dislike the job the most is having to constantly put out fires, or in other words to fix urgent problems that otherwise would cause havoc. These are one of the moments that cause more stress to developer's. But this is out of the employees control and only gets better with how each one of us deals with these moments, maturity and experience helps solving the problems in a competent way.

In extreme cases, of many unjustified stressful situations, it's probably better to find another job.


Having lighthouses to guide us 


Programming notifications to notify us before an event actually happens, prepares our mind before we go into it while at the same time it prevents us from forgetting, which if it happens, will surely not only stress us but everyone involved. 


When there is not much control of the tasks we have to do, it helps to set deadlines and to track the progress.

Telling some colleague about these deadlines and having them, talking to us about it can help us meet the deadlines. They will be, on some sense a lighthouse for us and we should be the same for them. 


I can say from experience, that when there is no clear goals, we can be left without motivation. 


On a previous work i was working alone on the software of the company, no one really cared about it, no one would review the quality of my work, no one would do pair programming with me. 

I got into the trap of demotivation. 




As a last point, i would like to say that even applying all of this points, we need to like what we're doing and to tolerate the people that surround us. If everything is cool, it means we have the minimum conditions to keep doing more and better and being organized is ONE of the things that matters most to accomplish our objectives. 




Sources

https://www.workfront.com/blog/work-organization-tips-30-to-take-you-from-mess-to-master

https://www.the1thing.com/blog/productivity/how-to-get-organized-at-work




Software suggestions 


Many software tool choices are dependent on the flavor of each person. I can say what I actually use at work and what i use on my personal life. But in the end each one of us should use reliable and useful tools.


Email
  • Outlook (work) 
  • Gmail
Calendarization 
  • Microsoft teams (work) 
  • Google calendar
Tracking time
  • Harvest (work) 
  • Clockify 
Meetings and channels
  • Microsoft teams (work)
  • Zoom 
  • Slack 
Notes 
  • Office documents (work) 
  • Evernote 
  • Notepad 
Media cloud repository
  • Google drive 
  • One drive
Code repository
  • Github
Task management and backlog
  • Jira attlassian (work) 
Staff management
  • Clan HR (work) 

In progress…