If you are reading this blog there may be two reasons. First, you are the programmer and second, you want to be a better programmer.
So here we go,
Even bad code can function, But if the code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of the poorly written code. But it Doesn’t have to be that way.
So there might be a question in your head what is clean code?
The answer to that is your logic must be straight forward to make it hard for any bug to hide and which can be read and enhanced by a developer other than its original author. clean code always looks like written by someone who cares.
So there are some rules which we will discuss:
1)Meaningful names
It is easy to say that a name should be relevant intent. Choosing good names to take time but save more than it takes. So take care of your name and change them to better ones. Everyone who read your code will be happier including you. which can improve consistency, clarity and code integration . The name of the function or class should answer all big question. Suppose your variable name is
val x = 10 // This variable name reveals nothing
The name “x” doesn’t reveal anything.
Use Intention revealing the name
We should choose a name that specifies what is being measured and the unit of that measurement.
val elapsedTimeinDays // This reveals what is being measured and unit of measurement
Programmers must avoid leaving false clues that obscure the meaning of the code. We should avoid words whose entrenched meanings vary from our intended meaning. For example, hp, aix, and sco would be a poor variable name and avoid misleading names like which may create confusion
def getAccount ()
def getAccounts()
def getAccountInfo()
Use pronounceable name because a name like “genymdhms” means (generate date,year,months,day,hours,minutes,seconds) so we can’t walk around and say “gen why emm dee aich emm ess” which is very hard to discuss on which can be write
As “generateTimeStamp” would be a better choice.
You also don’t need to prefix member variables with m_ anymore. Your classes and functions should be small enough that you don’t need them. And you should be using an editing environment that highlights or colorizes members to make them distinct. prefixes become unseen clutter and a marker of an older code
class Part {
var m_dsc = "manager";
def setName(name:String){
m_dsc = name;
}
}
class Part{
var description:String = "Manager";
def setDescription(description:String) {
this.description = description;
}
}
Class and object should have a noun or noun phases name like Customer, wiki page,
Account etc… avoid a name like Manager, Data or Info. Class name should not be a verb.
Methods should have verb or verb phrase names like post payment, deletePage, or save. Accessors, mutators, and predicates should be named for their value and prefixed with getting, set. Pick one word for one abstract concept and stick with it. For instance, it’s confusing to have fetched, retrieve, and get as equivalent methods of different classes
Example of good coding practice for the method shown below
def genymdhms(t: Any): Timestamp = {
val d1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS")
val d2 = date1.parse(token_exp.toString)
new Timestamp(parsed2.getTime)
}
Clean code Would be
def getCalendarTimeStamp(token_exp: Any): Timestamp = {
val dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS")
val parsedDate = dateFormat.parse(token_exp.toString)
new Timestamp(parsedDate.getTime)
}
2)Functions
“Functions should DO ONLY ONE THING They should Do It Well They should Do IT only”.
The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. So this means that your function should not be large enough to hold nested structures. Therefore, the indent level of a function should not be greater than one or two. This technique makes it easier to read, understand and digest.
Your function can take the minimum number of argument that is zero. Such function doesn’t depend on any input so there’s always going to be some trivial output from it. It will be easy to test.
Next comes one (monadic) which is based on functional programming rules, followed closely by two (dyadic). Three arguments (triadic) should be avoided wherever possible. More than three (polyadic) requires very special justification and then shouldn’t be used anyway.
If any in case the number of arguments are more than 3, then we should group them into a meaningful object.
def registerUser(name: String, password: String, email: String,address:String,zip:Long): String = {
implicit val session = AutoSession
dBConnection.createConnectiontoDB()
val token = UUID.randomUUID().toString
import java.util.Calendar
val calendar = Calendar.getInstance
val token_gen = new Timestamp(calendar.getTime.getTime)
calendar.add(Calendar.MINUTE, 30)
val token_exp = new Timestamp(calendar.getTime.getTime)
withSQL {
insert.into(UserData).values(name, password, email, address,zip,token, token_gen, token_exp)
}.update().apply()
token
}
Which can be written as
case class User(name: String, password: String, email: String,address:String,zip:Long)
def registerUser(user:User): String //
3)TDD means “Test Driven Development”
The primary goal of TDD is to make the code clearer, simple and bug-free. In TDD approach, first, the test is developed which specifies and validates what the code will do.
How TDD work is??
- Write a test
- Make it run.
- Change the code to make it right i.e. Refactor.
- Repeat process
By now everyone knows that TDD asks us to write unit tests first before we write production code. But that rule is just the tip of the iceberg. Consider the following three laws
First Law You may not write production code until you have written a failing unit test.
Second Law You may not write more of a unit test that is sufficient to fail, and not compiling is failing.
Third Law You may not write more production code that is sufficient to pass the currently failing test.
And Also that there should be a single concept per test and only one assertion per test which is said to be good practice
example:-
"document is empty" should {
"not be able to convert a document into an entity" in {
val result = UserDataDao.documentToEntity(Document())
assert(result.isFailure)
}
}
References
- clean code by robert c. martin