Skip to main content

3 posts tagged with "developer"

View All Tags

Clean code: Write The Code You Want To Read (Part 2)

· 5 min read
Reda Jaifar
Lead Developer

author photo source

Functions

Functions constitute a centric component in the recent software programs, the reason why we should care a lot about all of their aspects from naming, length, composition, arguments and error handling.

Small

Yes "small" is the main rule a function should comply with, so it tell us what it does exactly because a function should do one thing, do it well and only.

To keep the function also short, [if, else, while, etc ...] statements should be only one line, and probably this line is function call:

fun bookTrain(bookingRequest: BookingRequest): Booking {
validBookingRequest(bookingRequest)
val booking = Booking.from(bookingRequest)
booking.status(BookingStatus.PENDING)
return booking
}

Single abstraction level

Or the principle of "Doing one thing", the idea is not about writing function with single line of code, or one step but writing it with the restriction to cover only one computation, see example below:

   fun validBookingRequest(bookingRequest: BookingRequest) {
if (bookingRequest.from == bookingRequest.to) {
throw InvalidBookingRequestException("departure and arrival stations are the same")
} else if (bookignRequest.stops > 5) {
throw InvalidBookingRequestException("more than 5 stops is not allowed")
}

}

The Step-down rule

We write code to be read, so writing functions in an order like a narrative text, if we have to put the functions of the above two examples, they should appear in the following order:

   fun bookTrain(bookingRequest: BookingRequest): Booking {
validBookingRequest(bookingRequest)
...

fun validBookingRequest(bookingRequest: BookingRequest) {
...

we can see clearly that the caller function is above the called one

Switch statements

While switch statement can easily impact badly you clean code, The key issue with switch statements is that they often lead to violations of the Single Responsibility Principle (SRP) and can make code harder to extend and maintain.

   fun calculateWashCost(vehicle: Vehicle): Money {
when (vehicle.type) {
CAR -> calculateCarWashCost(vehicle)
BUS -> calculateBusWashCost(vehicle)
MOTOCYCLE -> calculateMotoCycleWashCost(vehicle)
else -> {
throw InvalidVehiculeType(vehicle.type)
}
}
}

There many issues with this function above, first the function is large and each time new vehicle type will be added, it will grow even more. Second it violates the Single Responsibility Principle (SRP) because there is more one reason for it to change, but the worst probem is there will be more functions that will have the same structure:

  • CalculateParkingCost(vehicle: Vehicle): Money
  • CalculateCarbonTax(vehicle: Vehicle): Money

A solution proposed by Robert C.Martin is his book "Clean Code" is to hide the switch statement in an abstract factory, and the factory will use the switch statement to create the appropriate instances of the derivatives of Vehicle. And the various functions such as CalculateParkingCost, CalculateCarbonTax will be dispatched polymorphic through the Vehicle interface.


abstract class Vehicle {
abstract fun calculateWashCost(): Money
abstract fun calculateParkingCost(): Money
abstract fun calculateCarbonTax(): Money
}

abstract interface VehicleFactory {
abstract fun createVehicle(vehicle: Vehicle): Vehicle
}

class VehicleFactoryImpl() {
fun createVehicle(vehicle: Vehicle): Vehicle {
return when (vehicle.type) {
CAR -> Car(vehicle)
BUS -> Bus(vehicle)
MOTOCYCLE -> MotoCycle(vehicle)
else -> {
throw InvalidVehiculeType(vehicle.type)
}
}
}
}

Functions common patterns

Don't hesitate to make your function's name long if necessary in order to ensure a significant name. When it comes to function argument the ideal number is 3, then comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. The challenge with arguments resides in testing you can imagine the difficulty of writing all the test cases to ensure that all the various combinations of arguments work correctly. Have you ever heard about "Flag Argument"? Flag argument is an argument of type boolean where the function do a thing when it's true and another thing if it's false, these arguments violates the Single Responsibility Principle (SRP).

Argument Objects

If a function needs more than two or three arguments, there is probably a way to wrap some of them into an object, see the following example:

  fun deployApplication(applicationId: Int, cpu: Int, memory: Int, storage: Int, tag: String) {
// do something ...
}

We can reduce the number of argument by passing an object representing the infrastructure requirements, see example below

  fun deployApplication(applicationId: Int, infrastructureRequirements: InfrastructureRequirements, tag: String) {
// do something ...
}

Command Query Separation

The Command-Query Separation (CQS) principle states that a function should either perform an action (a command) or return data (a query), but not both. This makes the code more predictable, easier to test, and cleaner.

  // Query function: returns whether the withdrawal can happen (no state modification)
fun canWithdraw(balance: Int, amount: Int): Boolean {
return amount <= balance
}

// Command function: performs withdrawal by returning the new balance (state modification, no return of query data)
fun withdraw(balance: Int, amount: Int): Int {
return if (canWithdraw(balance, amount)) {
balance - amount // Returns the updated balance
} else {
balance // No changes if insufficient funds
}
}

fun main() {
var balance = 100

// Query if withdrawal is possible
if (canWithdraw(balance, 50)) {
// Command: Update the balance by performing withdrawal
balance = withdraw(balance, 50)
println("Withdrawal successful. New balance: $balance")
} else {
println("Insufficient funds")
}
}

Conclusion

Let's admit that functions are fundamental components of our code, so it's crucial to invest time and effort into defining them properly, including their names, arguments, and statements. Writing software is similar to any other form of writing—you begin by drafting your ideas, then refine them until they flow smoothly. Remember, we write code not just for execution, but also to be easily understood by others.


Clean code: Write The Code You Want To Read (Part 1)

· 6 min read
Reda Jaifar
Lead Developer

author photo source

Clean Code!

Why should I care?

We, software engineers almost spent more time reading code than writing new lines, how many times do we complain about someone else's code? Many factors can give us an idea about the quality of code and how much the writer cares about it. If you dislike reading bad code, you already made your first step toward writing good code if you care about your heritage. There are many good reasons to care about writing clean code, adding the artistic layer to your code is an inspiring reason for me to learn and apply the clean code rules and principles.

What clean code brings to me?

Clean code is what makes us professional programmers, someone with high-level ethics who cares about the present and the future of his code, he believes that lines of code can live for long and can be enhanced by others with ease and passion. Like a book author what makes him happy is how readers enjoy turning the pages of his book one after the other without realizing the time elapsed.

Clean code is about philosophy!

Clean code makes us more than a programmer, it helps us develop a good vision of the software we are building, caring about its growth, evolutionary, and enhancement. Clean code makes us a thinker about maintainability, design, and the ability of the software to cope with changes quickly and easily. Code is written to live but also to change and evolve.

We are authors

Yes, we programmers are authors, that said, we have readers, Indeed we are responsible for communicating well with readers. The next time we write a line of code, we'll remember we are authors, writing for readers who will judge our effort.

What clean code covers?

Naming

As a programmer the first step of writing code is choosing names, for variables, functions, classes, packages and source code files. While this seems easy and instinctive, choosing good names takes time but saves more than it takes.

Let's look at the following code snipped:

 d = Date.now();

The name "d" above has nothing to reveal, even tough it is a date object, but we cannot know the intention of usage, either its start date or end date. Note that even naming it startDate doesn't give it any sense, because we need to know as a reader what is the context of the start date. Hers is a suggestion for this example:

taskStartDate = Date.now();

Abbreviation

Abbreviation Is one of the most common mistakes concerning variable naming, as a programmer can you guess what this variable name below means?

msg

Can you know that msg may mean "message" or "most scored goal"? Personally, I don't want to spend time exploring many lines before or after this one to understand the context of this variable in case I need to make a change. The rule is to avoid any disinformation.

Distinction

Another issue with naming is the number-series such as (variable1, variable2), consider the following function:

public static void duplicateString(char a1[], char a2[]){
...
}

is it not more readable if we use "source" and "destination" as the names of the two arguments? I think yes, it is.

Adding noise words is another problem that impacts the cleanness of the code, you may want to specify that a variable is a String, so you name it: "emailContentString", Here the "String" is just redundant as is not part of the name but the type which has nothing to do with the meaning of the variable.

Word Sounding

As a programmer, there is a good chance that while we are writing code, our brain is pronouncing the text we type. when we cut the connection between our brain and the activity of writing, we usually type variable names that could be difficult to pronounce, and the consequences are multiple: other developers won't be able to retain them easily and these names will be demanding to discuss with the business analysts. While English is the most used natural language used to write code, using other languages such as French or Italian, apply the same rules regarding how easily the variables, functions, or classes names are pronounceable.

Are names accessible?

Each time I take over developing a new feature or fixing a bug that requires modifying a source code that not has been writing by me, I start by searching some keywords that I got from the context of the domain system. For Example when I was asked to fix a UI bug in a web application developed using ReactJS then I was trying to find the matching component in the source code, but it was not as easy as expected and I spent 30 minutes before finding the component named with a number prefix: 1CounterComponent. This is why choosing names that are straightforward to find is a very useful rule to follow.

Coding Conventions

Every programming language provides coding conventions regarding variables, functions, classes, and naming source code files. While the naming took a good part of these conventions, they also cover indentation, comments, declaration order, etc ... I don't hesitate to refer to these conventions. But during my modest experience, I came across some coding conventions from specific programming languages applied to another one. This is strongly discouraged or prohibited by the teams themselves.

Technical Vs Business Names

We write code to build software that will be solving a problem, For example: coding an application that computes taxes. Trying to be a good programmer implies differentiating technical things from business-related ones. whenever you code a technical concept don't try to use mainly a domain name, For example: declaring a variable that holds an instance of the HTTP client could have the following name: httpClient, but if we try to include the business-related usage we can name it: taxesRulesHttpClient as you can see in this case the domain doesn't bring any help instead is just making a technical thing harder.

A last note

Writing clean code requires a piece of cultural knowledge and good descriptive, communication, and writing skills, we can develop these skills by learning from communication experts either by reading books or taking courses on how to write, synthesis, and order ideas. Also evolving on the natural language we use to code. For example, if we write code in English, it will be helpful to learn more words, synonyms, sentences, etc...

So far I wanted to pay your attention to the importance of clean code, and how can impact the software's quality and maintenance, We covered mainly the naming concept in this part. Other articles will follow to cover other aspects concerned by clean code.


Few and permanent rather than many and intermittent

· 5 min read
Reda Jaifar
Lead Developer

author Photo by Rachen Buosa

This post's title is an old quote I've heard since my early edge, but I never gave it much attention or tried to go beyond this phase, just some words shared by older people in my family. Unfortunately, it took me years before I mind the importance of continuously complete small tasks and cut off with the idea of doing the whole job at once. Thanks to agility I'm changing my mind and acquiring new ways of working and producing. Before sharing with you why and how splitting any job or mission into small tasks helped me to achieve goals, I would like to share the pain encountered while trying to provide many efforts at once.

I remember the school-age when I was trying to prepare for my exams, I always adopt the same strategy by spending a whole day revising my courses, doing exercises, and once I got tired I close my books mark the material as completed. I often succeeded in my exams but many times I recognize that I could do better, but who cares, I wasn't obsessed about getting the highest score.

While I'm writing these lines, I remember the time when I want to get abs and being fit, I can't tell you that my motivation was something other than having the summer body. As a consequence, I start going to the gym and training in late April, But for 3 years consecutively, and contrary to my exam story, I've never reached my goal even though exercising 6 times per week for not less than two months. From these two stories shared above, I retain one lesson providing much effort in a short period may, or not work.

But what if I could change something to increase my chances to get a shaped body, maybe be coached by a professional! Yes, I did, maybe follow a restricted diet! Yes, I did, the only thing that I could do and not did it is starting my program earlier and going slowly but surely.

Few and permanent

A few years ago I've had the opportunity to discover agility at my university, then I worked on an agile project, 1 month after starting the project our web application was in production, users interacting with and we are having feedback, this is really amazing and so satisfying. I do believe that the key rules for such success were

  • defining small but valuable feature
  • continuously delivering

Breaking a big task down into small, more feasible ones helped me avoid procrastination and an overwhelmed workload. Here are some steps to follow for breaking a task down, but remember that you're the only one capable of doing that depending on the context, the knowledge, and priorities:

1 - Make sure you visualize the big picture, that means what the end product or make sure you visualize 2 - Think about the order, which one should be completed first, second, and so on... 3 - Define milestones: make a short plan which will help you stay on track. 4 - Complete your tasks early to have additional time for a final review

I do believe that permanent iteration pays in the end, with the adoption of a few concepts we gain confidence and progression:

  • Going slowly, how many times have we heard that? but Have we ever enjoyed it as much as we can. Going slowly means to me doing things at my pace while giving all my attention and concentration to do it the right way and achieve high quality. Consider coding a small program or write a report, try to do it rapidly and at once, then do it slowly over 3 times within 1 day, then compare your results, I have no doubt that quality will differ.
  • But Surely, yes make sure at any stage, you are performing with your best efforts, concentration, and passion.
  • While doing things over many periods, make sure at the end of each milestone you create something tangible, deliverable, and useful.
  • With dedicated attention to detail, because details make the difference.

How the rule of "few and permanent" affected my motivation and productivity:

  • When I started scheduling my job and tasks as few ones completed over many steps, I begin to feel more confident, and sure about my achievement. In my unconscious mind, I'm convinced that I'll reach the expected goal whatever how many iterations I'll go through.
  • My motivation and passion are often at the top, as completing tasks that are tangible, apparent, and useful. As a software engineer, I do love to deliver small features as soon as they can be deployed to production and being used by end-users, But this is certainly true in other fields of application.
  • As my tasks are small, they are completed early so I can get feedback on their useless then I'll iterate to improve and optimize, rather than reviewing a whole job with many comments and issues to handle.

We always need to remind that

Overwatering can kill flowers, a moderate and continuous one give them chances to grow up