Friday, January 28, 2022

New Directions

 I've been learning lately.

I mean, I have been learning a lot.  Some of it is completely new, some of it is just fresh perspective on old ideas.

This is undoubtedly the natural consequence of being put in charge of developing a green-field project (can you believe it?!?) using both familiar and unfamiliar technologies.  It's a mobile app.  It's an API.  It's a cloud native, event driven...  work in progress.  As a consequence, I run into unexpected things all the time.  I also get to see up close what works and doesn't, as my client is flexible enough to let us experiment with features.

I think I need to record this stuff for anyone who might be interested.  I'm not saying that I will be giving up on discussions of OOP principles, but I will also be expanding my reach.

There was no single trigger for this, but the past year or so has helped me to understand a few new tools and concepts.  I'm still working out others, as I have been all along.  But now I'm going to write it down here.

I hope it proves useful.


JD

Saturday, February 15, 2020

Mary had a little lambda

Java 8 brought a lot of changes to the imperative/object oriented world of corporate software development.  So many changes that to this day the more fluent and functional style of code this enables is still not as prevalent as one might hope.

Today I'm going to discuss one aspect of these changes, lambda expressions.

What is a lambda?  It's a function without a name, and with an initially odd looking syntax.

When you see something that looks like this:
.map(t->t.getModels())

You may get a bit confused.  I know I did, and it took me a little while to comprehend this structure.

But really, it's just creating a method call with slightly different syntax.  When written with a bit of the fluff left in it may start to look rather familiar:

map((t)->t.getModels())

Or
map((t)->{ return t.getModels(); })

These all do the same thing.  This is a method, one designed to do only one thing, return the models contained within the parameter object passed to it.  The big difference is that there's no name for the method and we've added a little '->' to indicate that it's not to be executed now but at need.  That is what makes it a lambda, mostly.  It is a method or function, but one which can be passed around to whoever might be interested in it, but whether or not it runs depends on if the program needs results from it.  

Note that you would probably never write this as a stand-alone method.  You already have a one-liner in whatever 't' represents.  

And that "whatever 't' represents" is one of the issues that can make it a little harder than it has to be to understand.  I don't love one letter variable names, so maybe it would be more straightforward to write it like this:

.map(manufacturer->manufacturer.getModels())

I haven't seen that done very often, but I'm going to go this way for my own work because it expresses the intention with perfect clarity.  Sure, in IntelliJ I get hints along the right side of the screen that inform me about types, but what about a code snippet from GitLab or something?

There is one additional thing you absolutely must understand about lambda expressions:  Everything you hand to one has to remain unchanged until the thing actually executes.  If you try to put a mutable variable in there you're gonna have a bad time.  Only the parameter(s) can be different from call to call.  

Finally, there can be a temptation (especially given the syntax of that third example) to stick a few more lines of code inside the brackets.  Don't do that.  If it is a unit or work, it's worth naming it and making it available to others.  Extract a method and call that instead.  I almost wish that we couldn't write things that way, because programmers tend to be...  Oh, let's say expedient about getting things done.  I completely understand that, but please don't do this:

.map(manufacturer-> {
 if (manufacturer.getName.equals("blahblah") {
   doSomething();
 } else {
   doSomethingElse();
 }
 logger.info("Hey, look, I'm screwing up lambdas for all!");
 return manufacturer.stream()
            .collect(asList(manufacturer.getModels()));
 }

Just don't.  If it deserves curly braces, it deserves a name.