Never stop

May. 15th, 2025 11:09 am
jducoeur: (Default)

(Posted this on LinkedIn, of all places, since it seems appropriate there. But let's also put it here, where my friends will actually see it.)

I was chatting yesterday with a sometime colleague -- a fellow programmer -- who just got laid off, who asked (paraphrasing) "How do you manage to stay hopeful in this terrible job market? What do you do in the meantime that helps?" Here are some thoughts on that.

Part of my response here is history, because I've kind of lived through it before. 2025 is starting to remind me of 2002 -- what we referred to at the time as the "nuclear winter" of the software industry, in the wake of the Dotcom Bust.

(Although this time around, the tariff mess seems to be popping the bubble earlier, and maybe a little less violently, than 25 years ago.)

Regardless, I expect the job market this year to be brutal for software engineers. We have a lot more programmers than jobs for the time being, after years of heavy hiring around the pandemic, so it's worth thinking about how to get through it.

The first question, hard but important, is: how serious are you about this? In 2002, part of how things resolved is that a lot of folks dropped out of programming and found something else to do. By that point, we had tons of folks for whom it was just a job, rather than a passion, and many of them found greener pastures elsewhere. That's 100% sensible, and I expect a fair amount of it this year.

For those of us who do consider ourselves to be software "lifers" -- the ones who can't imagine not programming on a constant basis -- I have two key pieces of advice:

  • Never Stop Learning
  • Never Stop Coding

On the first point, self-driven learning is the heart of software engineering: as a rule of thumb, I believe in spending several hours every week, even when fully employed, learning new stuff -- staying on top of things is a key part of my job in an industry that is constantly evolving.

That becomes more true when you're unemployed: you should take the opportunity to learn new languages, new techniques, new technologies. Take the time to expand your toolbelt and figure out new things you can do and find fun.

On the second, take the downtime as a chance to buff your portfolio. For most of us, our dayjob work is pretty hidden: the code is proprietary to our former employers, so we can't show it off.

So don't take too much time as enforced vacation. Instead, once you have your head straight, get back to "working" a full day every day on something open source. That both shows that you have some initiative, and lets you show off your chops to prospective employers.

Indeed, this is exactly what worked for me in 2002. I taught myself the then-newish C# language and built a dumb little shareware application in it. That proved directly relevant to my job hunt: I wound up getting hired to build the .NET middleware backend for a startup that I had my eye on.

(This time around, I'm taking the time to bring Querki, my own little product, up to modern snuff after years of neglect -- that's teaching me a lot about AWS, and should give me a chance to turn that crufty ancient Scala code into something I'm more willing to show off.)

Mind, it's still hard -- you have to put a lot of mental effort into not letting it get you down. But having a project to focus on will help with your mental game, and can help with the job hunt in unexpected ways. I recommend it.

jducoeur: (Default)

My technical blog is very Scala-centric, so not too many of the folks here are interested in it.

But for the programmers in the audience: I just finished posting a long-simmering series of articles about testing Scala services that some of you may find fun. It's somewhat heretical, including premises like:

  • Unit tests are mostly a waste of time for idiomatic Scala services.
  • You should focus on "scenario tests", that hammer the APIs and stub all externalities.
  • 100% test coverage is the only meaningful number, and you should get there.
  • Your code should be designed specifically to be testable, including hooks as needed to expose internal events to the test harness.

Not all of it applies to other languages and situations, but a fair amount of it does. So if you are curious about the topic, give it a read -- I'd love to get some conversation going about the topic, either there or here.

jducoeur: (Default)

Spreading the word for the other software-law geeks: the decision has come down on Oracle v Google, and it went the right way.

Summarizing very briefly (and possibly a little inaccurately -- IANAL, and I haven't read the ruling in detail yet): the Android phone operating system, like a large fraction of the software world, is more or less built on top of the Java Virtual Machine, which was invented by Sun decades ago and bought by Oracle. Google decided to reimplement the API for the JVM to suit their needs -- basically, providing a new implementation for the existing interface. This is totally normal (there are lots of reimplementations of parts of the JVM), but Oracle asserted that the API is their intellectual property, and sued.

(Note that pretty much everyone agrees that the implementation -- the code itself -- is copyrightable. The question was about the interface -- essentially, how you call that implementation from other code. If the interface is protected by copyright law, it becomes a legal minefield to try to write compatible, alternate implementations.)

Suffice it to say, the lower courts went with Oracle, and much of the industry has been on tenterhooks ever since. A lot was riding on this -- if Oracle had won, it would have tossed an enormous spanner into the software industry, and probably done a lot of damage to smaller companies. (Among other things, Querki's user interface is based on Scala.js, which necessarily reimplements a fair chunk of the JVM API. It's unclear whether Scala.js would have been able to survive if Oracle had won; in turn, that could have destroyed my company.)

The implication here, I believe, is that reimplementing APIs is now officially considered fair use, so the law matches the way the software industry has generally assumed things should work. So while on the one hand, this seems like an obscure technical point that most people don't care about, for those of us in the field it is extremely important, and really good news.

So yay for the Supreme Court for getting this one right...

jducoeur: (Default)

Howdy, all -- looking for thoughts, especially from the engineers in the crowd but not necessarily limited to them.

I've just found myself as one of the leaders of a big new software project -- big enough that we're going to be needing to spread the work across several teams, in various places around the world. That includes India, so figure ~12 timezones away from me. Collaboration is going to be a serious challenge, and one that we need to take seriously if we're going to succeed.

I'm sure that some of my friends have dealt with similar problems, so I'm looking for any and all thoughts. Tools, techniques, beartraps that you've run into -- this is an open-ended conversation, just keep it civil and accept that the team is what it is. I probably don't have the power to force this to all be on-shored, so the question is, how do we make the best of it?

We can probably slice-and-dice it so that different teams are working in different repos with distinct areas of responsibility, at least. The real question is how to manage questions and conversations about everything from coding style to architecture to requirements when we can't easily all get into a meeting together. It's not a rare problem, and I suspect there are best practices I don't know about yet.

Thoughts? Ideas?

jducoeur: (Default)

Well, that's kind of neat. Rally Health (my dayjob) just relaunched its company Engineering Blog, with a new article by me.

It's strictly for the programmers, showing how to build a Redis serializer/deserializer using typeclasses in Scala. If you're interested in how programming works in a more modern way, I recommend checking it out -- it's a good illustration of how this technique (which came from Haskell, but is now central to Scala and spreading to other languages) works. Questions more than welcomed here: I enjoy teaching this stuff...

jducoeur: (Default)

This one is mainly aimed at programmers, but I'm trying to teach a bit of programming, so it's not just for the FP geeks. (This is basically a bit of Functional Programming 101.)

In a comment on my earlier post, [personal profile] cellio asks what a Monad is. It's one of the most fraught questions in modern programming, but let's give it a stab. Bear with me -- this takes some explaining, and I am trying to avoid The Curse of Lady Monadgreen. This will be a practical description, rather than a precise formal one.

First, Functors

Let's consider several data types that we find in Scala. (And many other languages as well, often under other names, but I'm going to use Scala for my examples since it's what I know best. The concepts here are very general, but some languages express them better than others.)

On the one hand, take val o: Option[T]. This means that o is a box that may or may not hold a value of type T: o is either Some(t) or None. It's kind of like the idea of being able to be null, but much more principled. (Many languages use this either instead of null or provide it as an alternative.)

Next, let's look at val l: List[T]. This means that l is a box containing as many Ts as you want (possibly zero) with a specific order. (As opposed to Set[T], which has no intrinsic order.)

Finally, let's take val f: Future[T]. This one doesn't exist in as many languages: it basically says that f is a box that will eventually contain a T, assuming all goes well. (If all does not go well, it will eventually contain an error.) It's a good way to deal with asynchrony in programs, and can replace locks and callbacks and other such hell in many cases.

These types are all Functors. This means that they have a method called map(), which means "do the following transformation with every element in me". So for example:

  • o.map(x => x * 2) -- if o is, say, Some(5), this will return Some(10). OTOH, if o is None, the result will still be None.
  • l.map(x => x * 2) -- if l is List(1, 2, 3), this will return List(2, 4, 6).
  • f.map(x => x * 2) -- this returns another Future; if f eventually contains a 6, the resulting Future will eventually contain 12. And if f eventually returns an error, this resulting Future will contain that same error.

So the concept of a Functor[T] is that it is a box that contains "T-ness" in some fashion. You can transform the T's inside of it, getting another of the same kind of Functor with the transformed values.

Functors to Monads

All Monads are Functors, but with an additional kick: there is a sensible way to nest them. All of the above types are also Monads, and their Monad-ness can be expressed in for comprehensions, like the following.

val maybeUser: Option[User] = ...
val maybePhone: Option[PhoneNumber] = for {
  user <- maybeUser              // Option[User]
  profile <- user.maybeProfile   // Option[Profile]
  phone <- profile.maybePhone    // Option[PhoneNumber]
}
  yield phone

(I generally find it helpful to pronounce the <- arrow as from "in". So the first line of that for comprehension reads roughly "for each user in maybeUser".)

What the above is saying is:

  • I may have a User.
  • If so, put that User in a value named user.
  • If that user has a value in maybeProfile, put that in profile.
  • If that profile has a value in maybePhone, put that in phone.
  • If all that worked, return the phone number.

We are able to nest values or functions of type Option, and get another Option out at the end. If any of those steps returned None, then we get None out the end.

Next, let's do the same with List:

val regions: List[Region] = ...
val allCustomers: List[Customer] = for {
  region <- regions              // List[Region]
  dealer <- region.dealers       // List[Dealer]
  customer <- dealer.customers   // List[Customer]
}
  yield customer

This is saying:

  • Start with a List of Region.
  • For each of those Regions, get all the Dealers.
  • For each of those Dealers, get all the Customers.
  • Return all of those Customers.

It's the same concept: there is a logical concept of nesting. More importantly, there is a specific way in which you nest: in the case of nesting Lists like this, the results will all be concatenated together: the Customers for each Dealer in order in the resulting List, and all of the ones from Dealers in the same Region together.

Finally, let's try Future:

val userId: String = ...
val profileFut: Future[Profile] = for {
  user <- userDb.loginUser(userId)              // Future[User]
  prefs <- preferenceService.getPrefsFor(user)  // Future[Prefs]
  avatar <- photoService.getAvatarFor(user)     // Future[Photo]
}
  yield new Profile(user, prefs, avatar)

Each step in this case is a function that returns a Future. Putting it together:

  • First, try logging in with the given userId, and get back a box that should eventually contain a User.
  • Once we have that User, get a box that will eventually contain their Prefs.
  • After we have fetched the Prefs, get a box that will eventually contain the user's Photo.
  • When we've obtained all of that, assemble a Profile out of it.

Again, we are nesting these operations, and again, Future imposes some details: these steps will be conducted in order, each one starting after the previous one has finished, and if any step returns an error, everything after that will fall through and return that error instead of trying to continue.

Note that each kind of Monad knows how to combine with itself. That doesn't mean that they can easily combine with each other -- there are sometimes ways to combine different Monads in sensible ways, but it's a bit ad-hoc: not all combinations make sense.

Conclusion

So those are the high concepts. A Functor is a sort of box that contains "T-ness", where you can transform the Ts inside of it. A Monad is a Functor that has specific rules for how it can be nested within itself.

And yes, the names are weird. They come from Category Theory, a branch of abstract mathematics that turns out to be really useful for serious programming. The video linked from my previous post includes the legendary line, "a monad is a monoid in the category of endofunctors": literally true and correct in Category Theory terms while being utterly useless for actually understanding anything.

Anyone who wants to dig into this a little should pick up the delightful book How to Bake Pi, a fairly slim, Kindle-friendly book that teaches Category Theory in terms of baking: each chapter starts with a recipe, and then shows how that recipe relates to a mathematical concept. It doesn't teach programming per se (and requires no background in either math or programming), but it provides the underpinnings that this stuff all grew out of. I found it invaluable for getting comfortable with this stuff.

For the actual programming concepts, including Functors, Monads and other such fun types, I currently recommend the documentation for the Cats library -- the Cats community has taken documentation really seriously, and the documentation of each type does a delightful job of exploring why that type works the way it does. It is aimed at programmers, though -- I wouldn't recommend coming into it completely cold.

Hopefully folks will find this at least a little helpful. Questions welcomed...

jducoeur: (Default)

Content warning: Nazis, and mockery of both OO and FP.

This one is only for the hardcore programming nerds out there -- I suspect everyone else will just scratch their heads at it. But I thought it was horribly funny:

Video on YouTube

jducoeur: (Default)

I don't normally post simple links here these days (that's what Facebook/MeWe are for), but this one tickled my fancy, and besides -- it's about programming. And Mixology.

It's an article about Cocktail Similarity: using similar algorithms to the ones we use to ask "how similar are these two Strings?", applied to cocktails instead. It includes a dynamic generator for how to change any given cocktail recipe into any other cocktail recipe, charts of similarity, and lots of code.

It's wonderfully nerdy in a rather XKCD kind of way: taking two nerddoms and smashing them together. And it's Negroni-centric, which I totally approve of. Check it out...

jducoeur: (Default)

No, I haven't been posting much here lately. That's mostly because life has reached a pretty good pinnacle of crazy-busy.

Obviously, Querki continues to dominate my thoughts a lot. The project that we were going to do for Arisia didn't happen this year (since Arisia got Complicated), but has rather suddenly turned much more serious for next year, with a lot more people on board and the system likely because fairly central to Team Arisia.

I just got a new client at my dayjob. (Actually the same client I had for most of last year, but a different group -- last week involved a bit of amusing chaos as they shipped me an underpowered laptop, I pointed out that I needed something beefier, and then they figured out that my old laptop hadn't been wiped yet, and would I like it back?) So I'm in heavy ramp-up there.

After about 18 months of officially being the deputy of the Boston Scala Meetup, the founder finally recognized that he was a bit burned out, and he formally handed that off to me. So I ran a small survey of the community there, created a new Slack group as a result (and am now trying to get people to actually use it), and am starting to work out this year's Meetup schedule.

And today's new fun? I've had a talk accepted at a conference for the first time!

For all that I've been teaching Stuff (SCA dance most notably) for decades, and have been teaching Scala and presenting at Unconferences for several years now, I've never really done the conference circuit before about four years ago, and I've never done a talk before.

In this case, it's the Typelevel Summit, so I've dived into the deep end here. NE Scala is my "home" conference, a joint production of the Boston, New York and Philadelphia Scala Meetups -- this year is in Philly. But it's really three conferences joined at the hip: the Typelevel Summit, NE Scala proper, and the Unconference. The Summit is in some ways the bigtime: a gathering of the Scala-functional-programming hardcore, members of a growing group that encourages and collaborates on FP-centric Scala libraries. It includes a lot of the heavy hitters of the Scala world.

So I'm a tad intimidated, but also rather excited. My talk is specifically intro-level, and is about my own journey to finally building a pure-FP system for the first time -- in this case, Querki's new API-level test harness. The resulting code is some of the prettiest I've ever written, so I'm going to burble a bit about how that code evolved, and show off the relevant FP concepts that make it possible.

All of which goes to explain why I haven't had a lot to say about SCA, Fandom and stuff like this -- right at the moment, programming is dominating my brain, so I've mostly been posting over in my professional blog, which has wound up very Scala 3-centric for now. But I'll try to find some time to at least diarize and do some reviews here...

jducoeur: (Default)

I was just reminded that I've never shared publicly the document of Useful Scala Resources that I put together for Scalabridge a few months ago. Here it is, if anybody is interested.

Note that this is just an outline, but it's an outline with a considerable amount packed into a few pages. If anybody's interested in more info, I'm always happy to chat about this stuff...

jducoeur: (Default)

Fascinating article here about Priority Guides, a UX design tool that they are presenting as an alternative to wireframes. The core notion is to focus on the content of a page, using a discipline that specifically discourages you from worrying about the visual layout in this stage.

Very neat food for thought, especially for Querki. It would probably be easy enough to build a lightweight Priority Guide Designer in Querki, to use for future design of the system, and I suspect it would help prod things in more usable directions. Indeed, if it works I might make it into an app/mixin for others to use...

GraalVM

Apr. 17th, 2018 02:26 pm
jducoeur: (Default)

(Mainly for the programmers.)

Today in tech news is Oracle's announcement of GraalVM -- yes, that's "graal" as in "holy grail", and I'm sure they intend it. They claim that this new VM will:

  • Run in diverse environments.
  • Start fast and run fast, thanks to optional precompilation and linking.
  • Cover all major programming languages.

How they heck they are accomplishing that last one, given the diverse environmental expectations of different languages, I have no idea. One of the lessons of the Scala.js and Scala Native projects is that, yes, interoperability in diverse environments is possible, but it ain't simple. So I'm immensely curious what the interoperability in the GraalVM environment looks like.

It seems to be more than smoke and mirrors, though: they claim to already support all of the JVM languages and JavaScript, and they're working on Ruby, R and Python -- a nicely diverse set of target languages. And Twitter is apparently already using it in production. So this looks quite real, and if their performance claims stand up, it may be quite important.

Of course, this is coming from Oracle, who are not historically a fuzzy and cuddly company. Especially in light of their recent court win in the long-and-tiresome-but-important API battle against Google, I am quite concerned about the IP provisions are around GraalVM -- in particular, what patents it involves and what sort of copyrights they are asserting. Depending on the details, it may or may not be wise to build on; I think it's likely that this is Oracle's stake in the "technology lock-in" game.

That said, it's damned intriguing, and I'm curious to see how it plays out. In the meantime, I need to find some time to read into it...

jducoeur: (Default)

I've mentioned before that I now have a dayjob -- Artima, which is a small, Scala-focused consultancy. We currently have about half a dozen engineers, and are wrestling with the problem that no two of us live in the same timezone, much less state. (A couple aren't even on the same continent.)

We're trying to figure out how best to deal with communication among such an asynchronous team, where even video meetings don't work well due to timing. In particular, informal communication -- while we're okay having conversations in GitHub Issues where that is appropriate, we don't have a good place for transient, topical discussions. (We're also using Slack, but that's kind of so-so for asynchronous communication.)

This can't be a rare problem nowadays -- distributed teams are increasingly common. So here's a question for my friends and acquaintances: any suggestions of tools? What have you found to be helpful for distributed teams, especially for teams spanning many timezones?

jducoeur: (Default)

Just a quick shout-out to the Scala Center -- the group that shepherds the Scala language -- for their new accessibility initiative. They're exploring how to get the compiler working in a usable way with screenreaders, so that sight-impaired folks can actually make use of it.

(See the linked article and the SCP behind it for a bit more info, but the heart of the point is that literally rendering Scala code to speech produces nigh-incomprehensible results. So they're starting to study how to express the concepts in a way that can be understood through speech.)

jducoeur: (Default)

Got home last night from California, where I spent Thursday and Friday teaching a new course on Concurrent Scala. (We'll eventually get that listed on the company website.)

It's been an interesting experience. While I've done a fair amount of Scala teaching (both in conferences/Meetups and officially through Artima), and of course I've been teaching dance and stuff forever, this is the first time I've taught a whole programming course that I wrote largely on my own.

In general, I think it went pretty well. Some students thought parts were too elementary, while others thanked me for covering the basics, so I think we got the level-set about right. I didn't see too many people yawning, even through the epic three-hour talk on Friday morning, so I seem to still be pretty good at holding folks' attention and explaining stuff. It was a good class: larger than I'd expected, with a good deal of give and take with the students. As with dance, a lively group makes teaching a lot more fun.

The only serious fail came during the second day's Project Time. For this advanced class, instead of our usual approach of alternating short talks with half-hour blocks of formal exercises (with unit tests to check whether your answers are right), I instead did much more in-depth talks, and then had the students pair-program on less-formal projects. Basically, I gave them an initial skeleton app, and a stack of stories, which they were then to go off and implement. At the end of the day, we got volunteers to come up and show what they had written, and had the whole class talk about it.

All of which went fine until most of the way through Friday. Since it was a dead run getting the class finished, I hadn't gotten around to actually working through the projects myself -- after all, I knew the topics deeply, so I was confident it was all doable. Only I'd trusted the documentation while I was writing the skeleton app -- and as we all know, documentation lies. So the skeleton was actually misconfigured for what I had assigned them to do, and we lost half an hour during the projects figuring out the correct config settings.

But all in all, as fails go, I'll take it -- for the first run of a course, that wasn't too embarrassing, and I'm going to go fix it this week, so it's ready for next time.

And with that survived, I now get to do stuff that's a little less insane for the next couple of weeks...

jducoeur: (Default)

Just a quick link today, particularly useful for programmers who are trying to grok Functional Programming. This article describes the heart of the difference between imperative and functional programming in terms of a tiramisu recipe. (And a bit of Python code, but you really don't need to know Python to get the idea.) Well worth a read...

jducoeur: (Default)
Yesterday, I officially admitted to myself that I have been fighting a cold, probably for the past week and a half. It's been really slight -- just some sinus crap and a constant, moderate, dry cough -- so I haven't felt "sick" per se. But it does get draining after a while.

At this point, the biggest problem is that I'm just plain *tired*, and have the attention span of a particularly dim hamster. This isn't exactly good for my productivity, either for work (either for Artima or Querki) or fun projects.

But in the meantime, for the programmers in the audience (especially anybody into Scala), have a crazy little brainstorm from this morning...
jducoeur: (Default)
For those who are interested in it: I'm experimenting with posting some of my technically-focused articles on Medium. The first one is up: Don't hand out masks of your own face.

Don't worry, I'm not abandoning Dreamwidth -- most stuff will remain here. But I'm going to play with using Medium as a professional/technical blog, for articles where I am spouting off on techie subjects, and don't care quite as much about promoting followup conversation (which works better here).

So if you're interested in the programmer-y stuff, I encourage you to follow me on Medium, and we'll see where that goes...
jducoeur: (Default)

Since my Google-fu is failing me, I'm curious whether any of my friends might know:

I have one high-number port open on our home network, gatewayed to HTTP on my development machine, which is sometimes running an in-development HTTP server. (Sometimes Querki, sometimes other things.) Unsurprisingly, this leads to port scanners trying to break in; if I happen to be running the application at the time, I see fun errors in the log.

(No, there's nothing secret or interesting in the exposed web server -- it's just test data, and the open port is so that I can show folks outside the firewall what I'm currently up to. And if somebody actually can break into it through that, I want to know about that now, on my Linux dev box, rather than in production.)

This morning's errors are a mystery to me, though -- it looks like somebody is attempting to issue a REMOTE command. It's splashing with a "501 Not Implemented", of course, but I have no clue what it is. I had originally been entirely puzzled, since I'm not aware of a REMOTE method in HTTP, but then it occurred to me that, since this isn't port 80 or 443, there's no reason to believe they're trying to attack me with HTTP.

Any ideas what protocol they're sniffing for? This is just idle curiosity, but I like to have some idea how someone is trying to attack me, and there seems to be an automated probe trying this one about once an hour...

Profile

jducoeur: (Default)
jducoeur

June 2025

S M T W T F S
12 34567
891011121314
15161718192021
22232425262728
2930     

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags