Spring IoC & Dependency Injection

It’s possible that in technical meetings you listened these terms, at the beginning they sound a little confusing and complex but the true is that they are just principles in Software Engineering.

Inversion of Control (IoC) is a concept to delegate the full responsibility to manage objects to some container or framework. Using this concept allows you more flexibility in your code as switching between implementations, decoupling your code and letting your code easy to be tested by the simple reason that the components will be isolated.

And one way to achieve it is using Dependency Injection (DI)

Dependency Injection is a pattern where the main idea is to have a separate object responsible to populates a dependency for another object.

Looking at an example below related to Books and Sections, if we don’t use DI and we need to create a book object, in this case we need to define a specific implementation for “sections” inside the constructor, and we create an unnecessary coupling:

public class Book {
    private List<Section> sections;
 
    public Book() {
        sections = new ArrayList<>();    
    }
}

On the other hand, if we use DI we can delegate the responsibility to create “sections” to other object, container or framework, and this lets your code more flexible.

public class Book {
    private List<Section> sections;
    public Book(List<Section> sections) {
        this.sections = sections;
    }
}

And using the Spring Framework and just using an “annotation” allows us to delegate the responsibility to another object that could has many implementations and letting easy to interchange between them:

public class Book {
    @Autowired
    private List<Section> sections;
}

I hope it allows you to understand better!

References:

https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring

https://www.martinfowler.com/articles/injection.html

Why do I need to use Spock framework?

Today we have many excellent frameworks that we can use to test our code, some are breadth known that uses JUnit 4 rules, others that include Hamcrest with JUnit 5 and that makes the job to cover the code with Unit Tests, Integration Tests, Functional Tests, etc.

Then, Why do I need to change of tech if what I’m using is enough? Well, First of all It’s always important to look at other technologies to explore the benefits and to directly answer the question, there are other technologies that made an effort to improve readability in your test code and also let it simpler.

For example, in the official Spock’s repository https://github.com/spockframework/spock-example/tree/master/src/test/groovy there are many Groovy samples that I found useful to start, I copied one example only to show how the code is easier to read:

import spock.lang.Specification

import static spock.util.matcher.HamcrestMatchers.closeTo

/**
 * Hamcrest matchers are deeply integrated with Spock's condition mechanism.
 * The syntax for using a matcher in a condition is simple:
 * {@code <expected-value> <matcher>}. If the condition fails, both the usual
 * condition output and the matcher's output will be shown.
 *
 * @author Peter Niederwiser
 * @since 0.5
 */
class HamcrestMatchersSpec extends Specification {
  def "comparing two decimal numbers"() {
    def myPi = 3.14

    expect:
    myPi closeTo(Math.PI, 0.01)
  }
}

I have other samples I wrote in SpringBoot-Spock repository to show how to use the Given / When / Then structure and to show how the code looks like:

class SampleServiceTest extends Specification {

    SampleService sampleService
    SampleRepository sampleRepository

    def setup() {
        sampleRepository = Mock()
        sampleService = new SampleService(sampleRepository: sampleRepository)
    }

    def "validate getSample with data"() {
        given:
        def title = "world"
        SampleEntity sampleEntity = new SampleEntity(id: 5, title:'sampleA', rate: 2.45)
        1 * sampleRepository.getByTitle(title) >> Optional.of(sampleEntity)

        when:
        SampleEntity sampleEntityResponse = sampleService.getSample(title)

        then:
        sampleEntityResponse.rate == sampleEntity.rate

    }

    def "validate getSample without data"() {
        given:
        def title = "anyTitle"
        1 * sampleRepository.getByTitle(title) >> Optional.ofNullable()

        when:
        SampleEntity sampleEntityResponse = sampleService.getSample(title)

        then:
        sampleEntityResponse == null

    }

}

I know that using JUnit these tests could be written with some more lines of code, but the Spock framework includes validations for every phase that makes it a bit more interesting. I know there is no tool that is better at everything, but some tools are better for specific goals, and in my opinion, Spock helps on the goal to let your code in a cleaner way.

I hope it helps!

Scalar UDFs with Optional (Option, Some, None)

If you are using Spark SQL and you need specific logic to act on each row, it’s recommended to use UDF (User Defined Functions) to not include complex logic in the query.

Right, but what happens when some values are null and you don’t want to include if blocks that makes your code less readable? Well It’s possible to include Optional scala methods to let your UDFs in a cleaner way.

Let see some examples:

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions.udf

val spark = SparkSession
  .builder()
  .appName("Spark SQL UDF scalar example")
  .getOrCreate()

val applyLogicByCountry = (country: String, amount: Long) => {
      Option(country) match {
        case Some("Peru") | Some("Spain") => amount * 2
        case Some("Brazil") | None | Some("Portugal") => amount * 3
        case _ => amount
      }
 }

spark.udf.register("apply_logic_by_country", applyLogicByCountry)

spark.sql("SELECT id, country, amount, apply_logic_by_country(country, amount) FROM test").show()

I hope it helps!

References:

https://spark.apache.org/docs/latest/sql-ref-functions-udf-scalar.html

https://www.baeldung.com/scala/option-type

https://www.geeksforgeeks.org/scala-option/