Book Chat: 97 Things Every Software Architect Should Know

97 Things Every Software Architect Should Know is a selection of pithy articles with titles like “There Is No One-Size-Fits-All Solution” and “Communication is King; Clarity, and Leadership, Its Humble Servant.” To me they were all common sense ideas in the big picture. None of them were wrong, but none of them are anything anyone who has done the role well or is really ready to do the role shouldn’t be aware of already.

If you ended up thrust into a software architecture position without having a strong idea of how to do it check this out, it will give you some of the big picture stuff to check out. Otherwise just skip it.

Advertisements

Book Chat: Programming in Scala

I had previously mentioned Programming in Scala when discussing Scala for the Impatient, saying that Scala for the Impatient was written as a reaction to the ~800 page bulk of Programming in Scala for people who wanted just enough to get started with. After having read Programming in Scala it feels like criticism of its length is fair. The first half of the book was massive overkill for people who had experience in any C derived language or any other sort of object oriented language. There were sections that were marked off as optional reading  if you were familiar with Java because the behavior being described was similar. In comparison, the second half of the book was a wonderful experience even for an experienced programmer, since there were in depth explanations of all of the advanced language features.

Some of the things I learned were simple. For instance, that regular expressions can be used as extractors, which is a straightforward idea. Or, that predef is implicitly imported everywhere. Or that the arrow operator is actually defined as an implicit conversion in predef and not an explicit part of the language.

Other sections were more complex. The rules for how for expressions get mapped into other syntax were similar to what I had figured out, but the rule about how conditionals and assignments within the expression are evaluated added a lot of clarity to what I had learned by doing. I learned the ways you can use type bounds to improve variance indicators. The authors also discussed the transform method on futures that will be available in Scala 2.12, which has me excited to get to that upgrade.

There were some other things covered that even after a considerable study I’m not sure I understand. I understand the syntax for refinement types but I don’t think I understand the value even after the provided in-depth example using currencies. There was also an in-depth discussion of how the designers arrived at CanBuildFrom in the collections package. CanBuildFrom enables extraction of common operations from many collections but returns a collection of that same type and not some supertype. It makes sense in an abstract sense, but I don’t think I could implement a similar pattern without copying it directly out of the book.

Despite the book’s heft, there were a couple of topic I would have liked to know more about. I was hoping for a discussion of the reflection capabilities provided by manifests, type tags, and class tags, but since they are just library pieces and not integral to the language they weren’t covered. There were some oblique references to how bytecode gets generated from various Scala structures, but I was hoping for more insight into how to make interfaces that are less susceptible to breaking changes under the hood even when the Scala side looks fine.

Overall it’s a good read and not as long to read as you would think a book this size would be. It’s easily divided up into small sections so you can easily sit down and read a page or two and make progress over time.

Book Chat: How To Solve It

How To Solve It isn’t a programming book. It’s not exactly a math book either, but you will find yourself doing geometry while reading it. It isn’t a book on logic, but it is all about structured thought processes. I would describe it as a manual to teaching a systematic approach to problem solving to others, using geometry and a series of examples. It tries to lay out all of the thoughts that whiz through your head when you see a problem and understand how to solve it without really contemplating how you knew it. It’s a fast read, assuming that you know the geometry he uses in the examples.

The problem solving process is broken into four basic steps: understanding the problem, devising a plan, carrying out the plan, and looking back. At first it seems obvious, but that’s thing about a structured approach, you need to cover everything and be exhaustive about it. For example, to understand the problem you identify the unknown, identify the data, identify what you want to accomplish, try to draw a picture, introduce suitable notation, and figure out how to determine success. If you wanted to know should you buy milk at the store this sort of formal process is overkill, but if you are struggling with a more complex problem like trying to figure out what’s causing a memory leak or setting up a cache invalidation strategy it might be valuable to structure your thoughts.

I haven’t had a chance to apply it to a real problem yet. I did use some of the teaching suggestions – how to guide the pupil to solve their own problems – with one of the junior engineers I mentor and it seemed productive. I got him to answer his own question, however not enough time has passed to see if it improves his problem solving abilities in the future.

Overall the book was an interesting experience to read and seems practically applicable to the real world.

Monads for the Working Programmer

The monad is a backbone of functional programming. However, the mathematical definition of what a monad is highly inaccessible. I want to try and describe a monad for a programmer who is new to functional programming. This isn’t intended to be a precise definition, it is intended to be enough to help understand what the monad is, how to use it, and why it’s a helpful construct.

Consider the monad as a box. The box can be empty and the box doesn’t really care what’s in it. You can go get a box and put something in it. Someone can open up the box, take out what’s in there, work with it, then put their output back in the box. That’s really all there is to it.

Sometimes the box is less tangible than other boxes. For instance, Future in Scala or IO in Haskell don’t have an actual value yet, but the promise of a value later. Think of it like a package in the mail, the box may not be here yet but you can make plans for when it gets to you. You can plan to open the box and combine it with another value you have and put it back in the box. In programming terms it’s a continuation, you take the first box and attach some code to it so that when the value in the box does show up you run the continuation with it.

Sometime the box is a bit bigger than others, like the List monad. The List monad has more than one thing in the box like an egg carton, but they’re all of the same type. You can still open up the box and take out an egg and do something with it, or you can process each of the eggs in turn.

When you want to use a monad it’s as easy as that – your functions all start wrapping their return types in that monad. Their callers then open the box and do their work and return the new value to the box. So instead of pseudo code that looks like


values = [3, 4, 5]

for(int i =0; i<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>< values.length; i++) {

	values[i] = values[i] * 2;

}

 

 

You get pseudo code that looks like


values = [3, 4, 5]

doubled = values.map(value => value * 2)

But what’s the point of this programming style, what does it get you? First, it helps you work with immutable data. In the first example above you are mutating whatever values is. That’s fine in object oriented or procedural programming, but functional programming sacrificed mutable data for thread safe composability. Second, it produces code that is easily composable. If I wanted to subtract one before doubling the values in the above monad example, I could add another map statement entirely, separating the two concerns. In the initial example the two concerns would be mixed into the same control flow. Third, the monad itself can contain a fair bit of logic to enrich the programming experience. The ability to interact with a Future, an Option, a List, or any other monad in the same way simplifies a lot of refactorings. If you want to replace an Option with a List application logic doesn’t need to change much. Hopefully all of this helps demystify the Monad and helps you to write better code.