Coding Best practices to follow with Scala

Table of contents
Reading Time: 4 minutes

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

  1. clean code by robert c. martin


Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading