Tuesday, December 29, 2015

Year-End Book Statistics

Looking at my largest keywords in the blog this year, I see that I've spent more time talking about books than anything else.  As such, I thought it would be fitting to share with you some analytics and statistics about my book consumption this year.

First of all, some notes:

  • The following data only includes books I read for fun/entertainment.  They do not include any technical books I read for work, although they do include books read on the craft of writing.
  • I make no distinction between books consumed via physical instance, kindle, or audible.  I consider books finished via all of those mediums as "read," even though some were listened to, strictly speaking.
  • I read at least one book on this list twice, but I only counted individual instances of books.

Now, for the high-level statistics:

Total books read 37
Total pages read 13089
Longest book 635 (American Gods, Neil Gaiman)
Shorted book 76 (The Last Airbender: The Search, Gene Luen Yang)
Average book length 354

These numbers are interesting, but let's get a little more detailed, shall we?

As you can see, the reading really picked up in the second half of the year.  This began with me reading "On Writing" by Stephen King.  One of the things he mentions in there is that in order to be a good writer, you need to be a prolific reader.  It reminded me of the fact that I used to be a prolific reader, but had really fallen out of the habit lately.  At that point, I decided to start reading more, and wound up getting a bunch of books for my birthday.


The breakdown by genre is pretty telling.  I'm most interested in the fantasy and sci-fi genres, but managed to get a couple of other ones in there.  The graphic novels and Christmas stories were actually really short, totaling less than 400 pages together.


I did manage to spread the love around quite a bit from the authorship perspective.  I read 4 Dresden novels by Jim Butcher, 3 each by Scott Meyer and Lev Grossman (two sets of trilogies), a couple of 2-fers (including the Christmas stories, both by Charles Dickens), and the rest just a single book from each.  In total, I read 26 different authors.  This is actually fairly uncommon for me.  My typical approach is to find a small set of prolific authors I like and stick with their stuff.  I'm really glad that I've finally branched out some, although I now find myself liking a much larger number of prolific authors.  I think that's a good problem to have.

It's possible I'll finish another book before the end of the year, but it really doesn't look like it.  My goal for next year is to read 50 books.  I think, given my pace during the last five months of this year, I'll be able to attain that goal.

The *real* question is: will I break down and *write* a book this year?  Only time will tell... ;)

Friday, December 25, 2015

Christmas Traditions

Around our house and family, we don't really have many Christmas/Holiday traditions.  The season is very busy -- socially, work-wise, and involves lots of travel.  This year was no exception.

It all starts one of two ways.  During years where the boys spend Christmas with me, I pick them up and bring them back to the metroplex with me on the Friday when they get out of school.  This is the first of a couple of 3-hour road trips we take over the course of less than two weeks.

Regardless of when we pick the boys up, Tanya's birthday party occurs on the Saturday prior to Christmas (unless Christmas falls on a Sunday, when it will be up in the air).  We (almost) always host it at our house, and we typically spend the day preparing the food and house for the occasion.  This year, Igor and Anjelika's youngest sons came with them, so I split time between hanging with the adults and playing video games with the boys.

This timing coincides with my father's side of the family having a Christmas celebration somewhere near Abilene, Texas.  I get to hear about all of the shenanigans without having to be caught up in them, which is probably a good thing.  One of these years, we'll be able to make it out there.  Until then, keep it silly, Bentley Clan!

Work continues until a couple of days before Christmas.  This year, we managed to not be on call during the week, although I still acknowledged a couple of alerts and checked on the dashboards.  So yes, I took my work computer with me, in case you were wondering.  I promise, most of the time I was on it, I was just checking social media or working on Cartagena (which is done-ish... more on that in another post).

My parents have an anniversary two days before Christmas, and we like to take them out to dinner to celebrate.  We drive to Salado (second 3-hour road trip) to do so (picking up my boys on the way in years when they're not already with us).  When you've been together as long as my parents have, I think treating them to a meal which they didn't have to prepare or clean up from is a better gift than something coinciding with a yearly theme.

Christmas Eve is the time for opening gifts for us.  This is usually because everyone wants to do a little something in their own houses early on Christmas morning.  It's also relatively easy to get everyone together on Christmas Eve.  I was, apparently, a good boy this year, receiving headphones, a book, a day-hiking backpack, a Miyazaki movie, a t-shirt, CDs, candy, and cash.

Christmas Day, then, is for stockings.  More candy to be found in mine, along with an orange.  The orange is a Christmas Tradition, meant to represent prosperity (monetary, usually), that my mom always adheres to.  The irony is that I always appreciate getting it, but I rarely actually eat it.  Honestly, who wants to eat a piece of fruit that they've just pulled out of a musty old sock?

We then travel back home (3rd 3-hour road trip) in order to prepare for Russian Christmas, which takes place on the Saturday following Christmas (tomorrow, in this year's case).  In years where the boys start Christmas with us, they get dropped off on the way; otherwise, they come with us.  Russian Christmas is hosted by either Tanya G. or Anjelika.  Pictured here is goroshek (Russian pea salad), which we will be bringing.  This is another evening with the folks from Tanya's party, so time is spent playing with kids and adults in their turn.

The following week, counter to popular belief, is actually a productive work week for us.  We'll stop working early on New Year's Eve, however.  In years when we pick the boys up after Christmas, we will stay up playing board games or video games until midnight on New Year's Eve, at which point we'll watch the ball drop and drink grape juice of varying ferment levels.  The trip back to drop the boys off happens the next day at some point (although I'm not counting this 3-hour trip, since I counted the one where I pick them up first).

You know, I started off this blog post by stating that we don't have many traditions.  Upon further reflection, I'm forced to admit that is not the case.  Everything I've described above has happened in multiple years, and if it's not a tradition yet, it soon will be.

All of that to say, I'm very thankful that these traditions, and everyone involved with them, exist.  I hope that everyone reading this has had and continues to have very Happy Holidays!

Sunday, December 20, 2015

Cartagena, part 2


This week brought "interesting" progress on the implementation of Cartagena.  A note before we begin, however.  Tim's version of pirates is NOT a Cartagena implementation as I'd originally thought.  My apologies if this caused any confusion.  Tim's game is actually WAY MORE COOL, as you get to sail your pirate ship to all the ports in the Caribbean.  In any case, it's a different game (at least, for now).

OK, now on with the show.  I started this week by refactoring the board to "pieces" instead of "cards."  I also added stubbed tests to outline my thoughts of how the implementation should go from that point forward.  This is almost like taking notes and can help you think through a problem, which I definitely need help with.

(deftest shuffle-cards-test
  (testing "Returns a random collection of N cards"))

(deftest initialize-player-test
  (testing "Returns a player data structure full of initial state data")
  (testing "Each player should have six pirates")
  (testing "Each player should have six cards"))

(deftest new-game-test
  (testing "Player count should be equal to the number to which it was initialized")
  (testing "All players should be in jail")
  (testing "Active player should be player 1"))

(deftest player-move-test
  (testing "Player can play card and move pieces")
  (testing "Player can move backward and receives cards")
  (testing "Player without cards must move backward")
  (testing "Player with no available spaces behind cannot move backward")
  (testing "Player with pirate on ship can move that pirate backward"))

(deftest game-over-test
  (testing "Game ends when a player has all pirates on the ship"))

The next bits involved managing some state.  I created atoms for managing the card draw and discard piles while writing tests and implementing card shuffling.  Once cards are shuffled, a player could be initialized.  While implementing that function, I realized I hadn't implemented a function for drawing cards, so I paused the player initialization in favor of writing a function for drawing cards from the draw pile.  After that, I finished out the player initialization.


(def draw-pile (atom []))
(def discard-pile (atom []))
(defn place-cards!
  "Puts the full set of cards into the discard pile"
  []
  (reset! discard-pile (->> icons
                            (map #(repeat 17 %))
                            flatten
                            vec)))

(defn shuffle-cards!
  "Shuffles the card in the discard pile, placing them in the draw pile"
  []
  (when (and (not (empty? @discard-pile))
             (empty? @draw-pile))
    (reset! draw-pile (vec (shuffle @discard-pile)))
    (reset! discard-pile [])))

(defn initialize-board!
  "Returns a vector populated with icons from the 6 of the board pieces concatenated."
  []
  (->> all-board-pieces
       shuffle
       (take 6)
       flatten
       vec))

(defn draw-cards!
  "Takes n cards off of the top of the draw pile"
  [n]
  (let [cards (take n @draw-pile)]
    (reset! draw-pile (drop n @draw-pile))
    (vec cards)))

(defn initialize-player
  "Initializes a player data structure"
  [{:keys [name color]}]
  {:name name :color color :pirates [-1 -1 -1 -1 -1 -1] :cards (draw-cards! 6)})

Now that we have cards and players, it seemed like it was time to try to initialize a new game.  I created yet another atom to hold general game state.  At this point, I had several atoms, which is a TERRIBLE smell.  I stopped forward progress in order to refactor all of the state storage into a single atom.  This caused a fair amount of refactoring at each function's level, mainly due to removal of state management from those functions.  This actually felt REALLY nice, and I was more pleased with the implementation at that point.


(def game-state (atom {}))

(defn initialize-board
  "Generates a board from 6 random pieces"
  []
  (->> all-board-pieces
       shuffle
       (take 6)
       flatten
       vec))

(defn shuffle-cards
  "Shuffles and returns passed cards"
  [cards]
  (vec (shuffle cards)))

(defn initialize-cards
  "Puts the full set of cards into the discard pile"
  []
  (->> icons
       (map #(repeat 17 %))
       flatten
       shuffle-cards
       vec))

(defn initialize-player
  "Initializes a player data structure"
  [{:keys [name color]}]
  {:name name :color color :pirates [-1 -1 -1 -1 -1 -1] :cards []})

(defn draw-cards
  "Pulls cards off the top of the draw pile, returning a map of the new hand and what remains in the draw pile"
  [n player draw-pile]
  {:player (assoc player :cards (apply conj (:cards player) (take n draw-pile)))
   :draw-pile (vec (drop n draw-pile))})

(defn new-game!
  "Initializes a new game"
  [players]
  (let [board (initialize-board)
        players-draw-pile (loop [ps (vec (map initialize-player players))
                                 cards (initialize-cards)
                                 acc []]
                            (if (empty? ps)
                              acc
                              (let [player-draw-pile (draw-cards 6 (first ps) cards)]
                                (recur (rest ps) (:draw-pile player-draw-pile) (conj acc player-draw-pile)))))
        init-players (vec (map :player players-draw-pile))
        draw-pile (:draw-pile (last players-draw-pile))]
    (reset! game-state {:board-spaces board
                        :players init-players
                        :current-player 0
                        :draw-pile draw-pile
                        :discard-pile []}))


  #_(let [game-state (assoc {}
                     :players
                     (vec (for [player players]
                            (initialize-player player))))]
    (assoc game-state :current-player 0)))

With that done, I moved forward with implementing the actions a player can take on a turn, beginning with playing a card.  While beginning this code, I realized that I'd missed a case for drawing cards: what happens when there aren't enough cards in the draw pile?  Shuffle the discard pile back into the draw pile.  I quickly added a couple of tests (draw has no cards, draw has cards but not enough to cover the entire need) and the code to make the tests pass.

Then, something unfortunate happened.  I had this notion that perhaps the player portion of the game state would be better managed by color instead of by name.  I spend several hours refactoring the code to try to support that notion.  At the end of that effort, I still had a couple of broken tests, but the worst part was that when I looked at the code, it was LESS consumable than the prior version.  I reverted that work (thank you for making that painless, git!).

Let this serve as a lesson for you, kids.  When you're doing TDD and the tests don't lead you toward a design (meaning, you have a notion about a design that hasn't really emerged), don't change the design.  Wait until the test reveals the need for the design change, THEN do the necessary refactoring.

However, this surfaced a larger issue: I wasn't convinced that the way I was managing state was good enough.  I decided to fill out a sample game state map and get some feedback on it.  I have the luxury of being married to a divine software engineer, and asked her for her opinion on it.  She looked at it and gave some small but critical feedback: the board should know which pieces are on which spaces; the player shouldn't care about anything other than its cards.

Let this serve as a second lesson for you, kids.  Asking for feedback or help is ALWAYS preferable to spinning your wheels.  It's ok to try to figure something out on your own.  In fact, you SHOULD try to figure it out on your own.  However, put a time box around the effort.  For me, if I work with something for more than four hours without making tangible progress, it's time to punt.  By that point, I've not only exhausted myself, but I'm pretty crotchety about not being able to figure it out.  Maybe I should cut my time box in half so that I don't get to the "unapproachable" point...

From there, I was able to move forward with implementing the playing of a card.  This actually turned into a small series of functions, each of which was covered by an independent set of unit tests.


(defn is-open-target?
  "Returns true if the space matches the icon and has fewer than three pirates"
  [space icon]
  (and (= icon (:icon space))
       (< (count (:pirates space)) 3)))

(defn open-space-index
  "Returns the index of the first open space for the given icon after the starting index."
  [starting-index board icon]
  (or
    (some #(let [space (get board %)]
            (when (is-open-target? space icon) %))
          (range (inc starting-index) (count board)))
    (dec (count board))))

(defn play-card
  "Discards the card and moves a single pirate from the space to the next available space."
  [player icon from-space board discard-pile]
  (let [[pre-cards post-cards] (split-with #(not= icon %) (:cards player))
        [pre-pirates post-pirates] (split-with #(not= (:color player) %) (:pirates from-space))
        space-index (.indexOf board from-space)
        next-open-space-index (open-space-index space-index board icon)
        next-open-space (get board next-open-space-index)]
    {:player {:cards (concat pre-cards (rest post-cards))}
     :board-spaces (assoc board space-index (assoc from-space :pirates (vec (flatten (concat pre-pirates (rest post-pirates)))))
                         next-open-space-index (assoc next-open-space :pirates (conj (:pirates next-open-space) (:color player))))
     :discard-pile (conj discard-pile icon)}))

Even though there are a couple of spots in the play-card function that should be scrutinized further, I feel much better about this design.  I don't have any justification for that feeling aside from the fact that it emerged from the needs driven by the tests and it appears to actually work.  :)

That's it on progress for the week.  The good news is that I continue to work on it a little bit every day, and enjoy doing so (generally).  I'll try to sneak in a non-dev blog post sometime this week.  Since it's Christmas week, I don't think it'll be a problem from the content perspective...

Sunday, December 13, 2015

Cartagena, part 1


WARNING: this entry is technical.  I suspect several of the next few in the weeks to come will be.  I'll label them with Cartagena (with parts).

Impetus

Several weeks ago, Tanya and I attended clojure/conj, an industry conference for functional developers using the clojure language.  It was a great experience on several levels.  First of all, it was my first trip to Philadelphia, where the weather was fantastic and the cheesesteaks were... actually not as good as I'd hoped.  We saw several former coworkers as well as a lot of really interesting discussions about clojure and how it's being used to make the planet a better place.  Or, at least, how it's being used.  :-)

One of the presentations we saw was a juxtaposition of object oriented design and functional design.  If you're really interested, you can have a look at API First vs Data First design. I'll skip over the first part of the presentation, as he engages in a bit of reductio ad absurdum.  The second part, however, he talks about data first design, and he uses an implementation of the game Cartagena as his example.  It prompted me to at least consider doing my own implementation, except as a TDD exercise.

Full disclosure: my brilliant coworker Timothy Pratley is also working on an implementation.  His is going to be prettier, I have no doubt.  It'll be full of figwheel and buttons and menus and all sorts of nice things.  Mine's going to be a plain ol' TDD, starting with the engine and *maybe* working up to a nicer UI at some point... :-)

Starting

First things first: I've never played the game, so I needed to find a set of rules and pictures for references.  Luckily, the game is popular enough to have the instructions/rules listed on a handy-dandy webpage.  I read through them briefly to make sure they were complete.

Next, I created a new clojure project.  Luckily, accomplishing this in clojure is ridiculously busy.

$ lein new app cartagena

Having an application locally doesn't do anyone any good if my machine gets abducted by aliens.  Why aliens would abduct it is beyond me.  I am, after all, only a human.  To avoid the consequences of that potential catastrophe, I need to get the project under source control.  I do that by using git and github.  The commands are really simple.
$ cd cartagena
$ git init

I am also using a tool called scm_breeze locally to help manage git repositories.  As such, adding the files to the local code repository I just initialized is a *breeze*.  I hope you see what I did there...


$ gca

After this, a copy of my project is in a local source code/version control repository.  I still need to get it onto the Internet so that I can destroy my computer if need be.  To do this, I need to create a repository on the Internet and then synchronize it with my local repository.  I use github to accomplish this.  I won't go through the details here, aside from saying that you have to have a github account, and you have to press the "New Repository" button.  I name my remote repository (the one on the Internet, in github) the same as my local to avoid confusion.

All that's left to do is tell my local repository about my remote repository.  Just a couple more commands to enter.

$ git remote add origin git@github.com:rusty-software/cartagena.git
$ git push -u origin master

Github actually tells you about these commands, so you don't even need to figure them out yourself.  I love it when tools help me look smart!

First Content and Tests

Now that I've got a remote repository, and no longer have to live with the constant fear of catastrophic failure of my machine, I can settle down enough to get to implementation work.  The first real changes I made to the code base have to do with the README file.  I want to document at least the basic instructions and rules locally just in case the webpage I'm using as a reference is unexpectedly removed.  

I spend a few minutes reviewing the source webpage and realize that it refers to the board configuration, but it feels like there might be specific board constructs that aren't covered.  I spend a few more minutes looking for pictures of the playing pieces and find a few.  From those pictures, I figure out that the board is made up of six pieces with specific configurations of the iconography.  I make note of this in the README and move on to documenting the rest of the basic rules.  I read over the full set, then commit the changed content to the local repository and push those changes to the remote repository.

I'm finally ready to start coding.  The first thing I want to do is initialize a board.  I implement a test to ascertain when I've done this successfully.

(deftest initialize-board-test
  (let [board (initialize-board)]
    (is (= 36 (count board)))
    (doseq [icon [:bottle :gun :hat :key :knife :skull]]
      (is (= 6 (count (filter #(= icon %) board)))))))

Running this test fails.  In fact, since I haven't defined the calling function, it fails pretty miserably.  I stub out the function and have a legitimate failure on my hands.  It doesn't do at all what I want it to do, and that's perfect.  I have a RED test!  Let's make it green!

Notice that I have two basic assertions here.  The first is that I think the board should have 36 spaces.  The second is that each icon should be represented 6 times.  To that end, I begin to codify what I know the board segments are.

(def card1 [:bottle :gun :hat :skull :knife :key])
(def card2 [:knife :bottle :key :gun :hat :skull])
(def card3 [:hat :key :gun :bottle :skull :knife])
(def card4 [:key :bottle :skull :knife :hat :gun])
(def card5 [:gun :key :knife :hat :skull :bottle])
(def card6 [:hat :knife :key :bottle :gun :skull])
(def card1r (vec (reverse card1)))
(def card2r (vec (reverse card2)))
(def card3r (vec (reverse card3)))
(def card4r (vec (reverse card4)))
(def card5r (vec (reverse card5)))
(def card6r (vec (reverse card6)))
(def all-cards [card1 card2 card3 card4 card5 card6
                card1r card2r card3r card4r card5r card6r])

I've named the vars "cards for now.  This is probably a bad idea, as cards are other things in the game.  However, it's good enough for this first test to pass, and I just want to get something accomplished.

The next thing to do is implement the initialize board function.  Given that I have a collection of all of the possible cards, getting a random sample of them is simplicity in itself.

(defn initialize-board
  "Returns a vector populated with icons from the 6 of the board pieces concatenated."
  []
  (->> all-cards
       shuffle
       (take 6)
       flatten
       vec))

I'm using the thread-last operator here.  My initial implementation consisted of the function calls embedded within each other.  This seems slightly clearer to me.

Given this implementation, I re-run the test, and now they pass!  Yay!  This is a good commit point, so I commit my changes and push them to the remote repo as well.

I realize that there is another test to write.  I want to ensure that boards are varying as they are instantiated.  One more test should do the trick.

(deftest initialize-board-test
  (testing "Returns the right number of spaces as well as icons"
    (let [board (initialize-board)]
      (is (= 36 (count board)))
      (doseq [icon [:bottle :gun :hat :key :knife :skull]]
        (is (= 6 (count (filter #(= icon %) board)))))))
  (testing "Boards are not exactly alike"
    (is (not (= (initialize-board) (initialize-board))))))

As you can see, I extended my original test, adding some testing description.  Now I've got a test to make sure the boards are different.  Running the test, everything passes as expected.

There are two important points here.  The first is that I make small, incremental steps toward a larger solution.  The second is that I have now ensured that this rules are enforced on a going-forward basis.  These are good practices, as if something breaks I can be fairly certain the scope of the breakage is small and if someone else does something to break my rules, they know about it.

I stopped here for the day, realizing that there are two immediate changes I'll be making next time -- the aforementioned card var name, and the board itself is too simplistic.  We'll need to store state about which pieces are on which spots.  However, that didn't happen in THIS set of rules, so we delayed implementing that complexity until the simpler things were done.

More on this as it develops.  In the meantime, I hope you'll let me know if you have questions or comments.  I like feedback!  :-D


Saturday, December 5, 2015

Oops!


Oops, there I go again... not posting for a month or more...

I mean, uh, I MEANT to do that!  Yeah, that's it!  That's the ticket!  I didn't post ON PURPOSE so that life would have a chance to catch up with me.

A lot has happened in the last six weeks or so -- some good, some bad.  The bad is on a much larger scale than my day-to-day life, so you don't need to worry about me personally.  The good has been very and inexorably good.  Things like:


  • My youngest son turned 15 years old.  Wow.
  • Both of my sons made it through the classroom portion of drivers education.  One of them procured a learner's permit, and the other will have it once his documentation has been processed.  Double-wow.
  • Tanya and I went to Philadelphia for a professional conference, learned a lot, and ran into a bunch of friends and former coworkers.
  • Thanksgiving, and all that entails.
  • beasanta.org raised over $20,000 for the kids of Penny Lane.  If you don't know what this is, you should check it out.  :-)


This is also the time of year when I'm most reminded that I have control of absolutely nothing in my life.  OK, that's not entirely true.  I have at least perceived control over little things, but I find myself struggling with things that were easier in the spring and summer.  If you're thinking "he's talking about his belly (or exercise in general), isn't he?", then you are as astute as post-Thanksgiving pumpkin-pie-reduced mental faculties allow for.  I find that, despite my "best" efforts, losing weight and/or staying in shape in the winter is hard.  I suppose there's a large set of biological tendencies working against me, but dammit! -- I'm an evolved human, capable of conscious thought and control of my impulses, aren't I?

Willpower is lower for me in the winter.  Maybe that's another reason blog posts are harder to come by... ;-)  I'll try to do better, gentle reader.  I'll try.

Right after I make these cookies.

Thursday, October 22, 2015

Book review: "The Killing Floor" by Lee Child

Encapsulate the plot of this book in one sentence.

An ex-military police officer accidentally stumbles into the small town in rural Georgia where his long lost brother happened to be investigating the largest counterfeiting operation in recent history and (the ex-MP) is dead set on shutting the operation down while avenging said brother's murder.

(if that sounds like it's full of miraculous coincidence, you're not wrong)

When and where did you get this book?

August 2015, amazon.com and audible.com

What year or edition?

Both the kindle edition and the audio edition.

Did you finish it?

Yes, although it was an exercise in persistence more than anything else.

What's your verdict?

I think this is the first book Lee Child wrote, and it shows a little.  It's the first of the Jack Reacher novels for sure, told in first person.  I thought the prose style, when read aloud in the audiobook, was pretty effective.  I didn't like it written, but worked through it.  It's extremely abrupt, truncated, and full of incomplete sentences, making it seem like Jack Reacher was unintelligent where he's supposed to be really sharp.  However, I can see how that style appeals to others and might be pretty prolific in the crime genre.

His characters weren't as fully fleshed out as I'd hoped.  Reacher himself hinted at some depth, but most of the others were pretty one-dimensional.  One specific hangup I absolutely loathed was that everyone said "right?" when trying to verify that others were tracking on their thought processes, regardless of the character's background.  One character is Harvard educated, and does it a lot, as does Reacher, as do the bad guys.

My biggest annoyance has already been mentioned in the plot sentence.  There was so much coincidence that I gave up on anything being purposeful fairly early on.  I suspect that the story telling, style, and character development get better as the series progresses (it seems unlikely that there would be 22 of them otherwise.

What surprises did it hold, if any?

The biggest surprise is that the author stuck with the mega-contrivances to keep the plot strung together.  I wasn't really surprised by the way the plot unfolded, although I was pleased with a couple of the switch-backs.

Which scenes will stay with you?

I actually liked the opening seen very well, as well as a few of the action-y scenes.  Lee Child has a great sense of how to describe the action succinctly but interestingly, connoting the sense of urgency and tension from the main character's point of view.  I'm curious to see if he grows that style out to other aspects of his writing in future books.

Which characters will stay with you?

The main character, Jack Reacher.  I expected him to be slightly more super-human than he was.  I also expected him to come across as more thoughtful than he did.  Maybe what I missed was a sense of refinement, a smoothing out of the roughest edges of Reacher's characterization that would make him slightly more monstrous and relatable at the same time.  I'll blame Tom Cruise for this expectation.  Say what you want about the guy -- he's a good actor.

What genre would you say it is?

Mystery/crime.

Have you read anything else by this author?

Not yet, but I will.  Stephen King endorsed the series, so I'm willing to read at least two more.

Is it available today?

Yes, in all versions.  I suggest the Kindle and audible versions to see which you like better.  At this point you can probably get the entire set in a used bookstore.

Give me a good quote.

I'll give a short series.

“The United States motto?” I said. “E Pluribus Unum? Adopted in 1776 by the Second Continental Congress, right?”

Child, Lee (2006-04-25). Killing Floor (Jack Reacher, Book 1) (p. 15). Penguin Publishing Group. Kindle Edition. 

“He’s a big deal around here,” Finlay said. “His operation out there pays us a lot of taxes, does us a lot of good. A lot of revenue and a lot of benefit for the town without a lot of mess, because it’s so far away, right? So we try to take care of it for him. But now it’s a homicide scene, and you’ve got explaining to do.”

Child, Lee (2006-04-25). Killing Floor (Jack Reacher, Book 1) (p. 17). Penguin Publishing Group. Kindle Edition. 

“I wasn’t leaving a homicide scene,” I said. “I was walking down a damn road. There’s a difference, right? People leaving homicide scenes run and hide. They don’t walk straight down the road. What’s wrong about walking down a road? People walk down roads all the damn time, don’t they?”

Child, Lee (2006-04-25). Killing Floor (Jack Reacher, Book 1) (p. 18). Penguin Publishing Group. Kindle Edition. 

There's a lot of that.  And it bothers me.  Hopefully, it'll become a buzz instead of an annoyance.  :-)

Monday, October 12, 2015

Another great outing...

I just wanted to give a quick shout-out to the great folks in the MIS 374 class at UT Austin.  The students and instructors (Clint and Bruce) are fantastic and gracious.  For those of you that don't know, I do a guest lecture for the class once a semester on Agile Principles, and always enjoy the experience.  This semester's lecture was last Monday, and I wanted to touch on something cool.


This year was a new experience, both for the students and for me.  The MIS 374 class has moved into a new classroom, one of the Active Learning Classrooms at the McCombs School of Business.  Instead of being set up as a lecture classroom, the students sit around mobile tables with white boards and displays on every wall.  It made the presentation quite a bit more interactive, as I could walk around the room while I talked.

It also provided an opportunity to trim down the lecture to the bare-bones, this-will-help-you-on-you-project things while making a class-participation exercise possible.  We wound up doing a prioritization exercise, where the instructor took the role of the product owner and did an initial prioritization of the product backlog.  The students then stood around the backlog and asked the instructor questions about why they had prioritized the cards thusly.  They then pushed back and suggested that a different order would be more sensible, or less risky, or higher value based on how the instructor answered the questions.

Hopefully, the exercise made the lecture more real for the students than it was in lectures past.  In either case, I'm really pleased with the new format and the new classrooms, and look forward to doing it again.  Only next time, there will be even LESS lecture and MORE group exercises!

Tuesday, September 29, 2015

Book review: "Wonderbook" by Jeff VanderMeer

Just this morning, I finished "Wonderbook" by Jeff Vandermeer.  I'm not going to do a Magrs Method review here because this book, as fantastic as the cover presents it to be, is a how-to book.  In fact, the subtitle is "The Illustrated Guide to Creating Imaginative Fiction."

This book lives up to its cover in every way.  It is fantastic, especially if you are a fledgling or even intermediate writer that is looking for guidance about how to improve your craft or seeking some inspiration from the minds of other highly creative (and successful) authors.

The author, despite what you may think on first glance, offers a very consistent and easy to follow guide to creating fiction.  Starting with things as simple as "make sure your space inspires your creativity," he progresses to describe the different parts of the story and subsequently show how to think and act on every part.

You can't really talk about the prose in this book without calling out the illustrations.  If you think the cover is good, you ain't seen nothin' yet.  Jeremy Zerfoss is the principle illustrator, and the book is full of his sublime work.  Literally, this is the most beautiful book I've read in quite some time.  The book also features other illustrations of the wondrous and strange.  Every picture struck a chord with me, and I actually spent time studying each one.

Beyond the guide, the book also has writing exercises along the way that help drive home the points that are being made when the exercise is introduced.  The appendix of the book is full of ANOTHER set of exercises as well.  If the first rule of writing is "WRITE!" then this book encourages you to obey the rules.  I did most of the exercises and was pleasantly surprised by at least a few of them.

I have always thought I have at least one good story in me.  It's quite possible I've got more than one, given the way my brain seems to work.  For the time being, however, I still consider myself a non-writer.  As such, this book was slightly overwhelming, but thankfully made me aware of two very important things.

1)  Writing is a job you do because you love it.  It's ridiculously hard, has aspects that are tedious, presents situations you simply have to fight through, and possesses every other facet of a day job that frustrates everyone else.

2)  The writing community is full of people that are genuinely happy to help other people realize a dream of becoming a published author.  The publishing community, not so much.  Alright, that might be harsh.  The fact of the matter is that there is a LOT of content in the wild that most people wouldn't enjoy consuming, and agents, editors, and publishers serve as wilderness guides in a very real sense.

Oh, one other thing about the book.  It includes contributions from a bunch of different authors, including (but not limited to) Neil Gaimon, Lev Grossman, Ursula K. Le Guin, and George R. R. Martin.  I found these contributions really insightful, and they offered perspectives of people that have been in the business of writing for the better part of their lives.  If you want a peek inside the operating procedures of some of the best and most popular authors in recent history, this book provides the keyhole.

I really can't say enough about this book or recommend it highly enough.  I will certainly read large parts of it again as I work through the exercises in the appendix.  If you've ever had a hankering for writing or were curious to see what the process looks like, pick up a copy of this book.  If you always suspected that writers were only semi-normal people, pick up this book to validate that suspicion.  If you enjoy a good how-to book with lots of pretty pictures, pick up this book.  If you have a birthday coming up and $25 is the gift purchase limit, you should add this book to your wish list.

Happy reading!

Saturday, September 26, 2015

Book review: "Armada" by Ernest Cline

Encapsulate the plot of this book in one sentence.

An eighteen-year-old boy is called upon to utilize the skills gained during countless hours of video-gaming playing to save the world from an impending alien destruction.

When and where did you get this book?

I got this book from the local Barnes and Noble in July of 2015.

What year or edition?

First edition (2015), hardback.

Did you finish it?

Yes!

What's your verdict?

This book is definitely worth reading if you liked the style and content of "Ready Player One".  I enjoyed this book but it didn't engage me the same way "Ready Player One" did.  I will almost certainly read it again, especially if a sequel is written.

What surprises did it hold, if any?

There was a subtext that was introduced fairly early on that I was surprised to see used in separate layers.  That's the best way I can say it without spoiling too much. :-)

Which scenes will stay with you?

[SPOILER ALERT!]
There's a scene where a group of people are watching a video introducing the alien opposition.  The video is narrated by Carl Sagan, who (along with other leading scientists) had been part of a government cover-up to keep the knowledge of the aliens secret.  This secret is held into perpetuity by the leaders of the scientific community, spearheaded by Neil deGrasse Tyson currently.

With both of Ernest Cline's books, I've found myself suspending disbelief quite a bit in order to fully submerge and enjoy the world he's creating.  In retrospect, I found this to be particularly offensive.  It's preposterous that the leaders of the scientific community would withhold knowledge of one of the greatest discoveries in human history, regardless of the manner in which it was discovered.  It's a fundamental tenet of science.

Which characters will stay with you?

You would hope is was Zack, the main character.  However, aside from the fact that he's involved in every scene, he's not nearly as memorable as Lex, his love interest.  We first meet her in the auditorium where a group of people have been gathered for a briefing.  She's sitting alone, near the top, drinking from a flask painted like R2-D2.  She's immediately identified as an all-around bad-ass, dressed in black, tattooed, and having hacked the techno-gadget she'd been given.  She subsequently proves her bad-assery on multiple occasions, acting almost like a deus ex machina.

Plus, she's from Austin.  :-)

What genre would you say it is?

Science fiction, with a bit of nostalgia thrown in for extra bonus.

Have you read anything else by this author?

Yes.  "Ready Player One", which I feel I can recommend to anyone that grew up in the 80's or at least has a fondness for the decade.

Is it available today?

Yes, although I don't think the paperback has been produced yet.

Give me a good quote.

There are actually several pretty good quotes.  Here's a sampling.

     "Shit!" I heard Diehl shout over the comm. "I just lost my gorram shields because I'm already out of frakkin' power!"
     "Dude," Cruz said. "You shouldn't mix swears from different universes."

     "That’s how you know you’ve mastered a videogame—when a bunch of butt-hurt crybabies start to accuse you of cheating in an effort to cope with the beatdown they’ve just suffered at your hands."

     I rolled my eyes.  "I find it hard to believe that you were ever a Girl Scout."
     Her eyes narrowed, then she reached out and rolled down her striped knee sock, revealing a dark green Girl Scouts of America logo tattooed on her left calf.
     "I stand corrected," I said.  "Are you hiding any other cool tattoos?"
     She punched me in the shoulder -- hard -- then pointed at the flask, still in my hand.  "Quit stalling, baby face.  Bottoms up."

Sunday, September 20, 2015

Book reviews pending!

You may recall back in July I posted that I had a few books in my reading queue.  Since then, I've redone my queue entirely thanks to a huge influx of kindle books for my birthday.  The list of pending books has grown to 21 as of this posting.  Apparently I need to learn to read faster.  That, or dedicate more time to reading and less to work.  Hey, I like that idea!  ;-)

I have managed to make it through a few of the books in both the original and updated queues.  The issue is that I've been dissatisfied with the way I review them.  I think my resistance to give spoilers limits the efficacy of the review and doesn't tell anyone interested enough about the book to know whether or not they'd really like it.  At the same time, I recently read a blog post by Carrie Green (author and marketer extraordinaire -- learn more about her here) introducing a light-weight book review method called the Magrs Method.

The Magrs Method of book reviewing looks like it was originated by Paul Magrs (pronounced "Mars"), an author, artist, and lecturer.  The first entry I can find of him using this method is here. The method entails an initial encapsulation of the book's plot in a single sentence, subsequently answering ten questions about the book, and ending with some good quotes.  Specifically (for anyone that hasn't been clicking the links so far):

  1. Encapsulate the plot of this book in one sentence.
  2. When and where did you get this book?
  3. What year or edition?
  4. Did you finish it?
  5. What's your verdict?
  6. What surprises did it hold, if any?
  7. Which scenes will stay with you?
  8. Which characters will stay with you?
  9. What genre would you say it is?
  10. Have you read anything else by this author?
  11. Is it available today?
  12. Give me a good quote.
As I mentioned earlier, I'm not a fast reader.  As such, the queue of read books is not very long, and I'm not sure I'll review all of them.  However, expect reviews of at least the following in the near future:
  • Armada, by Ernest Cline
  • Killing Floor (Jack Reacher #1), by Lee Child
  • A Walk in the Woods, by Bill Bryson
  • The Handmaid's Tale, by Margaret Atwood
  • American Gods, by Neil Gaiman
  • The Magicians, by Lev Grossman
I still owe you a talk about how cutting the cord with "cable" is going as well.  I might interview Tanya about that, since she's the mastermind behind that particular scheme.  That, and I like the thought of sitting her down for an interview... :-D

Friday, September 4, 2015

Epitaph for Granny

My grandmother died yesterday morning.  She was the last of my surviving grandparents.  I went to look for her obituary in the Temple Daily Telegram.  It said:

“Mary R. Hughes, 89, of Salado died Thursday, Sept. 3, at her residence.  Services are pending with Dossman Funeral Home in Belton.”

It lacks verbosity, don’t you think?  To be fair, many of the obituaries were sparse, and follow the pattern of being an announcement first, then a proclamation later.  

I assume it will fall to my mother to write the final obituary, or she and her brothers together.  I wonder what epitaph they’ll give her?  If they ask me, I suppose I’ll have some things to draw on.  I’m not sure of the validity of any of it, since the sources were Granny or stories about Granny I heard from my mom, both of which are now filtered through the faulty sieve of my recollection.  Take anything factual in the following with a grain of salt. Trust that opinions shared are absolute truth from my perspective.

Mary Ruth Hughes was born in Coleman, Texas, in February of 1926.  I want to say it was February 4th, but that might not be right.  She had a sister, Theda, and a brother, Jerrol Max (and don’t quote me on the spelling of his name, as it’s always been pronounced “Jurl”).  They were raised by her mother after her father left them.  Despite the hardships of growing up fatherless and during the Great Depression, I was always left with the sense that Granny enjoyed her childhood.  Maybe she only ever told me the good stories on purpose.

She married my grandfather when she was 16, so sometime in 1942.  You’ll notice that she was too young to get married without some kind of special consent.  Luckily for her and my grandfather, grandpa was already in the army, and quite wily.  He pulled some private in off the street to attest that “yes, he’s known Mary a LONG time, and of course she’s 18!”  Shortly after they got married, my grandfather went off to fight in World War II.  I’m not sure about the details of any of the scheduling, but my mother was born near the end of August of 1944.  You do the math.

Granny and Grandpa and Mom moved around quite a bit, as many army families did.  I know there were stints in Camp Hood (before it was a proper fort) and El Paso.  Ultimately they ended up in San Antonio, where my uncles did most of their growing up and from whence my mom departed for college in Abilene.  All of my early Christmas memories involve long trips from Salado to San Antonio.  There were two houses involved, although I can barely remember the first one (the Harding house).  The more prominent one was the Glasgow house.

When we were little, Granny would pay us a nickel to look for bugs in her hair.  I can’t remember ever finding one, but she kept offering the nickels every time we’d see her, and we’d keep looking faithfully, reveling in our new-found riches.  It wasn’t until years later, when I was having my own head massaged, that I realized what she had been doing.  CHILD LABOR LAWS BE DAMNED was probably her motto.  Crazy old lady.  

When I finally caught the chicken pox, it was Granny that wound up taking care of me.  Both Mom and Dad had to work, so Mom drove me to San Antonio for a full week of hanging out with Granny.  I remember sleeping late every morning, and Granny singing me awake to the tune of “Lazy Bones… sleepin’ in the sun.  How ya ‘spect ta get your day’s work done?  You’ll never get your day’s work done… sleepin’ in the noon-day sun.”  I spent my time playing with Hot Wheels, my Millennium Falcon and Star Wars action figures, and watching Shirley Temple movies on the Classics movie channel.  I itched, but it was a pretty great week.  I don’t remember feeling lonely or homesick.  Granny had a way of making you feel like you were home.

My grandparents moved to Salado in the early 1980’s.  My grandfather came up first, living in a camper while building an aluminum-sided barn with an apartment above it where he and Granny would live for a fair amount of time while I was in elementary school.  They subsequently helped build my parent’s current house and then built one for themselves.  The only years my sister and I rode the bus home from school on a regular basis was in order to stay after school at Granny’s until Mom or Dad got home.  After what seemed like an hour on the bus, we would arrive, climb the stairs to the apartment, and Granny would be there to greet us with an after school snack.  Those were some of the best snacks ever.  I watched Tom and Jerry cartoons, which Granny seemed just fine with.

One of the last times I rode my 10-speed bike, I wiped out on some gravel about a mile from my house.  It was kind of a bad wipe-out, leaving me in a state where I couldn’t ride the bike very well.  I’d earned a pretty neat abrasion on my knee, and my left elbow had a gash in it deep enough to leave a lasting scar (which I still bear today).  Granny’s house is only a couple of hundred yards from my parent’s house, so I had walked the better part of a mile, trailing small drops of blood from my knee and elbow, when I decided to stop there.  I’m not sure why I did; I think I just wanted to rest a minute.  She made sure I was OK, and then asked me if I wanted her to take me the rest of the way up the hill.  I said no, that I was fine, I would just walk the bike the rest of the way.  It didn’t occur to me until after I became a parent myself that she might have wanted to take me up there.

I used to practice my trumpet outside, typically pointing it down the hill toward Granny’s house.  She often told me that she liked to hear me playing.  That was all the encouragement I needed.  I kept doing it through the end of high school.

My first car was a 1983 Thunderbird (which my parents generously bought for me).  It was originally my uncle Steve’s car, purchased for him by my grandparents.  I loved that car.  It was a V8 and could MOVE.  When it came time to get another car for me, I sold the Thunderbird back to Granny and Grandpa.  I can’t remember if I ever thanked them for letting me keep it as long as I did.

Granny worked for years down at the Salado Galleries across from the Stagecoach Inn Restaurant.  I would visit her there from time to time, typically after some school- or church-related activity ended.  Truthfully, I was visiting to see if Susie Cosper was there, whom I had a fairly large crush on.  Oddly enough, my grandmother approved of the match, and never failed to remind me of the fact anytime Susie’s name came up in conversation.  Still, it was Granny from whom I bought stuff there, most notably the fireballs (hard cinnamon candy).  For the record, hard candy was a big winner for Granny.  Brach’s butterscotches were some of her (and my) favorites.

Good grief, I haven’t mentioned food yet, or if I have, I haven’t given it nearly enough emphasis.  Granny was a tremendous cook.  Every holiday would find her slaving away in her kitchen, preparing feasts fit for royalty.  Everything that was worth making was worth making from scratch, and typically without the guidance of an actual recipe.  She simply knew how to make all of the foods she liked.  She made especially fine pies, of which lemon and chocolate were my favorite.  Each pie was topped with lightly browned but exquisitely fluffy meringue.  They were, in a word, delicious.

One quick aside about pies… one of my favorite stories from my grandparent’s early marriage involved pie.  My grandfather was ornery and a constant (but good-natured) teaser of my grandmother.  One time she had made a pie for him that she genuinely wasn’t sure about with regard to taste.  She asked him whether or not it was good.  He replied that it would have been perfect if it had had just had a bit more ketchup.  She promptly grabbed the ketchup bottle off the table and proceeded to dump a load onto the piece of pie my grandfather was consuming.  He ate the rest of it in silence.  Every.  Last.  Crumb.

Granny always claimed that the ketchup incident was an accident, that the cap must’ve been left loose on the last use.  I have my doubts.  I’ve often wondered if he was scared of her at that point or not…

Granny was, in many ways, one of the wisest people I’ve ever known.  She was a pretty good judge of character.  She warned me about associating with certain people and encouraged me to associate with others.  She gave advice regarding what I should study in college (and where I should go to college).  She always claimed credit for me getting into computers, although I’m pretty certain that credit has to be shared with a lot of people.  Some of her advice I took, other bits I discarded.  I think she was right far more often than not, and I would be a better person if I’d been better at swallowing my pride earlier in life and heeded her wisdom more often.

She was also pretty smart.  She did sums in her head faster and more accurately than I ever could.  She did crossword puzzles practically every day of her life when given the opportunity.  She had an opinion on everything, although she often qualified it with “well, I don’t know…” just prior to launching into everything that she knew or felt on whatever the subject was.  She claimed to not be smart; I never really understood why, because she obviously was.  It’s possible that my grandfather was a genius, and perhaps she compared herself to him.  In any case, she was smart, and I enjoyed our conversations on pretty much anything, even when we disagreed.

Granny had beautiful handwriting.  I wish I had letters or even Christmas cards with her script in them.  I’m hoping that my mom does.

My grandmother was not an overly or overtly spiritual person.  We had a couple of talks about it.  My grandfather was a flat-out atheist.  He’d seen too many horrors in life to allow him to believe in a personal, benevolent, loving, caring, or even just god of any kind.  Granny, on the other hand, felt like there was something greater than us, although maybe not in a personal sense.  I can only recall her attending church with us a handful of times at most.  I think the idea of organized religion rubbed her the wrong way, since she saw the truth in most human-run institutions.  Still, she did believe that something happened after we shrugged off our mortal coils, and I’m glad she believed it.

After the passing of my grandfather eight years ago, the life seemed to slowly drain out of Granny as well.  She had lived for a long time as his caregiver, and I think she might’ve felt purposeless afterward.  In the course of about a year, she had gone from fairly active to almost immobile.  Her back had gotten into a state where she couldn’t straighten up comfortably.  She moved slower and slower.  She loathed the thought of being a burden of people, and told me so on more than one occasion.  I think the truth of the matter was that she despised not being self-sufficient, but didn’t have the will to regain that state after Grandpa died.

Her funeral will be on Tuesday at 10 a.m.  I’m not sure if the headstone will be there already or not, although I think it will.  I’m curious to see what it will say.  If it were up to me, I think I’d keep it simple, perhaps similar to what is on my grandfather’s:

Mary
Ruth 
Hughes
Feb 4 1926
Sept 3 2015
Beloved Wife
Mother
Granny


Thursday, August 27, 2015

Switching contexts

WARNING!  There's some technical stuff in this one.  Skim over anything that makes you too cross-eyed.

My first computer was a Commodore 64.  I got it in the 6th grade, and it was a fantastic computer, I didn't do much programming on it (I was only 11 years old at the time), but I did play a ton of games with it.  It became my de facto gaming machine, graduating from the coarse user experience of the Atari 2600 (which I also played the heck out of, and may it rest in peace).

When the power supply for the Commodore 64 eventually burned out, I graduated to the Commodore 128.  Again, I did very little programming on it, and in fact spent most of my time booting into 64 mode in order to play games.  This was a wonderful feature for me, as I didn't have to learn very many new operations.

My mom got an Apple IIc at some point in my junior high or high school career, but I didn't warm to it too much -- too different from the Commodore line, and I was pretty loyal to my current context.  Mom eventually got a Vendex Headstart II, which was the computer I used up until my junior year of college.  It had a word processor, which was the most important thing to me since I needed to type papers.  Nevermind the fact that I couldn't type properly.  :-)

My junior year of college was a turning point for me, as I got an IBM PS/2 25 SX running Windows 3.1.  From that point on, I was a PC/Windows guy.  I spent the next 20 years doing software development in that technology stack, being mostly successful along the way.

Two years ago, I joined a company that doesn't do Windows/PC development, and the default work station was a MacBookPro.  It took me a while, but I managed to get a pretty fair handle on the new paradigm.  I suppose an old dog can learn new tricks when forced to.  I liked the machine so much that when it came time to replace my personal computer, I went with a small MacBookPro instead of a Windows PC.  This marked the first time I ever bought an Apple computer for myself.

Despite this new-found adoration of Apple, I've been trying to keep tabs on the Windows world.  Some really good things are happening in the company.  I installed a release candidate of Windows 10 on my personal MacBookPro (using VirtualBox) and ran it quite successfully.  I was very pleased with the changes they made, dumping most of the annoying Windows 8 features and pulling some of the best things about Windows 7 forward (including the Start button).

Two days ago, I took the plunge; I created a BootCamp partition and installed Windows 10 on my personal MBP.  The installation went flawlessly.  Dual-booting has been a breeze.  I've been really pleased with the experience so far.

There are, of course, some struggles.  Strangely, they aren't in anything to do with the software.  Instead, they have to do with the small context switching that's required when going between the operating systems.

Key bindings are the worst.  For example: in OSX, you press command+tab to toggle through open applications.  On Windows, you should use alt+tab.  They're right next to each other on the keyboard, and I constantly press the wrong combination (aside: Windows 10 handles this quite gracefully; OSX does not).  The command versus alt/ctrl context switch is rough.

A minor context switch has to do with the trackpad.  On OSX, you can tap the surface to click.  On Windows 10, you have to click the trackpad to click.  It's a subtle difference, but my fingers tend to ache a bit if I have to click the trackpad too much.

The good news is that even though I'm struggling a little, it doesn't have anything to do with either OS -- it's a PEBKAC issue.  If you've been considering trying Windows 10, I encourage you to do so (especially if you're on Windows 8).  I won't try to convince anyone from the OSX crowd.  They're pretty loyal to their current context...