scala, creating software and decoupling software components (and increasing cohesion)

As part of the application development process, I regularly look at new languages. Recently, I had reviewed and used, fairly extensively, groovy. Groovy programmers can start with java, then groovify the code incrementally. There is almost no "learning" tax and is fairly simple. I found myself using closures and and extension methods to help adapt some 3rd party libraries and make my code cleaner and more compact. I used many of the more functional list methods as well.

Based on some of the comments around groovy, I thought I would also look at scala. I am glad I did.

Scala is more focused on static type checking then groovy, which is dynamic in nature. Scala recently also added dynamic methods for those times you need them (groovy added more static type checking to their language). Both have some functional flavors, although I did find scala's functional roots more deep than groovy's.

After reading several books and blogs, I worked on some code. I was surprised that I quickly became productive in scala despite the syntax being fairly different than groovy or java I also found that scala offered some more clever (and hence more complex) layers of functional and object oriented programming than what java/groovy offered, or at least compared to java.

After thinking through, I have decided to use scala for most of my software going forward, instead of java or groovy. I'll still use groovy though for certain projects and certainly I use it for gradle programming.

There are some idioms to work out though. It had become second nature to compose software through OOP and composition, an object that required dependent services were injected, through the constructor or through property getters/setters, the objects necessary for operation. Everything was programmed through interfaces. Spring could compose the software either directly in java or through XML. When composed through XML, my software is essentially using runtime composition to set the dependencies. When using java-config, spring was ensuring dependencies were initialized in the correct order and could automatically pick up their dependencies (finding those dependencies is alot like implicits).

But I noticed that in addition to this standard approach to object composition, scala offered some more variations that only required a type-driven or functional or type+functional approach. The choices, as described in the blogs and books, are more complex than just the standard property/constructor composition approach. The same comments apply to extension, where you extend existing components to perform new processing capabilities.

I began to realize that scala could do the standard java property/constructor composition approach quite easily but what it was trying to do was add type/functionally driven composition approaches as well and most importantly, it was trying to use the compiler to ensure that my programs were well composed instead of debugging it during runtime. These scala approaches were more difficult to understand because it used types and functional concepts that were not as familiar to me and after having used spring and java for so long, I thought there was really only one major way to use the composition design pattern to create software. This is the point in the blog where people start talking about the cake pattern and self-types and case types and ...[something else that is more complex than java].

Once you decide that you would like to compose your software using the compiler to ensure you have all the components you need (at compile time) the complexity of the additional patterns start to make sense. You have the basic compositional pattern from spring and java you can still use and you should start there. However, once you realize that this traditional pattern actually involved two patterns, property setting/getting and variable provisioning, you start having more options for composing software and using different techniques. Instead of interfaces which can only specify methods, scala allows you to declare abstract traits that include both variable and method requirements (and more). And in fact, in many ways, interfaces were designed to ensure that service instance was provided to the implementation of that interface--this is equivalent to saying that an object would implement an interface to ensure that another dependent object was set into its respective property--that's why you see so many factory interfaces--factories produce objects and you would use factories to create an object then add that object, as a dependency, to another object that would use it. Of course, many java interfaces would also implement a single or small set of behavioral methods e.g. ServiceInterface.doit(someArgument).

And with regard to extending existing objects, you can use Spring, for example, to extend existing classes to have them perform functions that are specific to your application, for example, method injection or aspect oriented programming. Scala does not have exact equivalents in all situations, but it does have capabilities that may be sufficient or even more useful over the long run. Also note, Spring can do this for libraries, written in java, scala and groovy, that come from different authors. Scala also, requires that if you use the scala techniques, that you are mostly programming in scala to get the more complex composition and extension capabilities.

As a side note, I think the perception that scala is hard is the same perception that people think that other functional languages are hard, like javascript. Being good at functional programming is very different than being good at standard OOP language like java. The same applies to lisp-like languages like common lisp, scheme, clojure or haskell.

When you think about using the compiler to validate that your dependencies are wire together, you also realize that you want more from your type system. You want your type system to allow you to delay creating concrete objects until as late as possible in your types/functional code. You want to always delay anything concrete in your program until as late as possible (without taking this principle to its extreme case and makes the code hard to read). You also realize that you need to make your types much more finely sliced so you can compose just the right type of objects, with the right types of values and methods, that suits your needs. After all, Spring allows you to slice and dice up types and compose them for java programs. With scala, you want your scala type system to help you do this. It was hard to learn how to use Spring really well, and it will be just as hard (but not more or less) to learn how to use scala really well. However, with scala, since it can easily replace java, its all upside in my opinion.

So scala is my choice going forward and I know that I still need things like Spring. But I will work to making better abstractions by making fine slices of behavior and values, waiting as long as possible before instantiating and using compositional approaches beyond the constructor/property approach. And when using these tools, I realize that I may use less of Spring and shift some burden of programming to me the programmer to use the scala tools properly where it makes sense to achieve the benefits of reducing errors at runtime and catching more errors at compile time. Overall, my programming burden needs to decrease for the switch to scala to make sense. So far, in my opinion and even based on limited exposure, I have already captured some of that value.

Someone asked me whether it is possible to take a solid java programmer and turn them into a good scala programmer. For the most part, I think the answer is yes, if you use scala like java. If you want to use scala for its functional and more advanced OOP features, the answer is a bit more of a no.

I also acknowledge that you can use generics in java to achieve some of the compositional approaches that scala can also implement. For example, abstract type members map to generics and parameterized types in java can help with composition. Unfortunately, using them can be awkward because interfaces/classes in java cannot have method implementations so you wind up with a bit of an explosion of abstract classes and interfaces (all with generics) if you try and implement the same patterns used in scala.

Comments

Popular posts from this blog

quick note on scala.js, react hooks, monix, auth

zio environment and modules pattern: zio, scala.js, react, query management

user experience, scala.js, cats-effect, IO