When is a Dynamic Language Good? June 11, 2013
Yep… I'm exploring the other side
I'm a dyed in the wool static language guy. I used C++ for logic code in Mesa, even though the UI was in Objective-C.
Ruby's dynamic meta whatever stuff made it difficult for me to code.
Scala with it's mostly excellent type system is one of the most useful tools I've found for reducing the class of errors in my code.
But my recent projects have made coding against a static language less useful.
Meta Projects
I used to do a lot of line of business applications. Inventory systems… e-commerce systems… that sort of thing. An attribute of those systems is that the data forms are pretty well fixed early in the project. You've got a database schema that evolves slowly. You've got forms that don't change much. So, having a direct mapping between named/typed fields in objects that represent DB rows makes a ton of sense. Lift's Mapper assumes that it's the authoritative representation of the data.
In the last few years, I've been working on far more "meta" projects. Game platforms, content management systems, big data front ends, transaction systems where the business logic is changed by business people outside the application's source code, systems that produce and consume APIs.
One of the things I've been finding with Scala and the above category of projects is that I either see a lot of case classes that need to be updated as the use cases change and evolve (which they do far more quickly for the above class of meta systems), or keep everything around in Maps/Dictionaries.
A substantial percentage of code in the above systems (especially the ones that do heavy interaction with single page apps that have a ton of JavaScript on each page) is marshaling and un-marshaling code. Transforming from JSON to Scala data structures then running some logic and then Transforming back to JSON. We can replace JSON with XML or RDBMS in the prior sentence… but it's all the same Extract-Transform-Load cycle.
Dynamic use cases in tension with static languages
Given that the Scala code I write has a large part of the "load in and out of static" types code, it seems that the static code isn't always optimal… especially in cases where the application logic itself exists as data (game platform, transaction processing systems).
So, I've started looking into Clojure to see if the loss of some type information but having much more flexible, dynamic data structures that can much more easily be serialized will lead to faster initial development cycles and better maintenance cycles.
Put another way, will Clojure allow me to build a node in a great JSON transformation network… and the web is a great JSON transformation network… REST APIs from the browser… REST APIs to other services… shipping data back and forth… applying a smattering of transformation/logic at each phase.
The other thing that a Clojure seems to engender is the idea of something failing. In Scala, I find that much coding assumes success rather than assuming failure. Clojure coding seems to assume success far less often… nothing concrete about that… just a vibe.
Scala's star is dynamic
Interestingly, Akka, the most important project in the Scala ecosystem,
is a dynamic system. The type signature of an Actor is Any => Unit
. You send
an Actor a message of any type and you don't get anything back because the
only thing that happens is a side effect.
Yes, there's request/response layered on that. And Akka assumes failure.
So, if you're coding against Akka, then you are coding as if you were coding in a dynamic language (yes, the business logic behind each message processing computation is typed as well as Scala can type things).
And if you're coding in Akka, you let it crash.
Akka has a vibe that's much more like Clojure than most other Scala libraries (including Lift).
But needs more tests
I still find that I feel more comfortable with my Clojure code when I've written more tests.
Both Scala and Clojure are biased towards immutability (Clojure more so than Scala). So, testing for mutability-style failures isn't really that important.
In Clojure, because there's no type checking for function parameters, I tend to worry more about calling a function with something it doesn't expect. Although, with a function-focused language (rather than a method-focused language) "method not found" issues are less frequent.
Still, the Clojure compiler does less work for me, so I want to write more tests for my Clojure code than I do for my Scala code. I also find myself more TDD oriented in Clojure… trying bits of code out in the REPL then as tests… then moving on.
Not necessarily coherent or fully rational
I'm not sure if this vibe is coherent or fully rational. On the other hand, I have found less marshaling boilerplate in my Clojure code than I find in my Scala code. I wonder if that's just "where I am" or if it will continue as my Clojure codebase becomes larger and I'm dealing with more subtle issues.