Code And Cocktails

GOOS Guide to Testing and Designing

| Comments

(The second in a series in which I reread Growing Object Oriented Systems and try to digest it better. Overall this section, Chapters 4-8, is filled with timely reminders to me about several things about good design.)

The Walking Skeleton

This is one of the points in this book which seem like such small items but I think have more importance than initial appears. In fact I am surprised in my rereading that the authors advocate the end-to-end tests to be done on deployed systems - that is not something I’ve ever really tried and seems very daunting.

The important things to remember here about the Walking Skeleton is that it is not about writing real functionality, but meant to flush out issues both technological and organizational. It will be definitely smaller than an MMF. It might take a surprising amount of time to write it nonetheless. This is because there will be a whole lot of learning happening. The same goes for the first few features. (Boy is this a timely reminder for me right now…)

Unfortunately this slowness at the beginning of a project can seem like a bad thing - but it is really not. The beginning feels a bit rocky - but then it smooths out as deploy and integration issues have been resolved. In a ‘normal’ project the beginning might be smooth but the deploy and integration problems will crop up and make the end rough.

How to Write a Test

The way they describe to write a test is something I try to do - but it bears repeating (this is valid for tests at any level):

  1. Write the test you want to read (write helper code to make this possible).
  2. Watch it fail - keep working on it until it fails for the right reason with a good error message).
  3. Now write the production code to make it pass.

By taking the time to do this you will ensure that the goal and intent of the part you are working on is clear. When done ensure it has a clear intention revealing name - this is how you will understand the system later.

Start by writing an acceptance test for the feature. Write it in terms of the domain and the user. An acceptance test gives feedback on the external API of the system and upon major integration points both with external APIs and internal components. Since the acceptance test is likely to be failing until all parts of the code is written it will need to be separated from the main build.

Once the acceptance test is well written then start moving down a level to the objects that the acceptance test uses and unit test their functionality into existence. This is the idea of testing from inputs to outputs. Jumping to a lower level object too soon will lead that object to have an interface which does not reflect what it really needs to be. Only by building the objects after building their callers can you know what is really needed.

The Authors have a bit of simple advice as to what to test first: they suggest going for a simple successful path, and they make a good point why. Tests provide feedback, if you focus your initial tests around error or edge cases then your design feedback will be about that instead of the normal work of the component you are writing.

One final important point the authors make on how to write tests is: “If an area is hard to test don’t just ask how can we test this? but why is it hard to test?. If something is hard to test it could be the tests are trying to tell you something. This is one place I have trouble with - I seem to have too much tolerance for pain while coding - a tolerance I need to cure myself of.

How to Design Code (and How Tests Affect That)

Obviously writing tests before the code affects how the code is designed - the pressures to keep each object isolated are very powerful. The book contains a good set of design points which are not unique to the book and not new to me. There were a few specific points I thought good to note.

When objects are composed together the interface for the composite object must be less complex than the union of the interfaces of the composed objects. This makes it a higher abstraction which hides some of the complexities. Higher abstractions allow us to manage complexity.

Each object must be context independent e.g. everything it needs to do its job needs to be passed into in via the constructor or the specific method in question. Thus each object has external knowledge on a “need to know basis”. This leads to the ability to recompose objects to get different behavior.

Create plenty of Value types. This combats Primitive Obsession and also creates attractors for functionality.

Object peers (those objects which are communicated with directly) should be mocked out in tests. This causes coupling and interface problems to be evident. Value types should not be mocked. Neither should third party APIs be mocked since the feedback provided cannot be used since the API cannot be changed. Also mocking external APIs runs the danger of testing against behavior you believe the API has, but may not actually have. Third party APIs should be wrapped in a thin adapter layer which can be mocked in unit tests.

Where do Types Come From?

I rather like the Author’s descriptions of how types are ‘found’ when working in the code. The three ways are valid for both Value and Object types:

  1. Breaking Out: When the code shows that an class is becoming too complex that is a sign that it is doing too much. Some of the functionality could be split into helper types.

  2. Budding Off: When there is a new domain object a new type should be created, even if is empty or contains only one piece of data. The type will act as an attractor for further data and behavior.

  3. Bundling Up: When a group of classes are always used together they can be bundled together. Remember that composite objects should have a less complex interface than their composed parts.

A Final Note About Mocking

I find that now that I can mock concrete classes in Java that I do not use interfaces as heavily as I used to. The Authors specifically point out they use interfaces quite a bit - again because they are concerned with the communication between objects. I think this is one item I’ll keep an eye on as work through the examples. I have used interfaces in this way before but it seems lately I have not been doing so.

Conclusion

I agree with their design ideas. I already try to follow them. I am quite excited to work through the example with them (something I did not do when I read the book previously). I hope that by doing (and blogging about it) these good ideas will sink in more; becoming more normal for me.

I also intend to blog more frequently on it instead of lumping large chunks together like I did here.

The Lotus Eaters

| Comments

From the Odyssey:

…but gave them to eat of the lotus, which was so delicious that those who ate of it left off caring about home

I believe that the Sazerac may be my ‘lotus’ - what is yours?

Rereading Growing Object Oriented Systems

| Comments

Why

I read GOOS severals years ago but I have decided to reread it as I felt I didn’t think it really got into my head the first time. Definitely I did become more comfortable with mocking in tests - but I felt there was probably more that I missed. So I am rereading it - and more importantly - taking a few notes. It is those notes that I will be writing about, every chapter or two - hopefully not a project that will end in a whimper.

Chapter 1

A learning process

“Software is a learning process.” I am not sure why I didn’t catch this last time. It is something that makes absolute sense to me now; and moreover I don’t know a time when it would not have made sense to me over the last decade. If software is a learning process, getting feedback on that learning is of utmost importance.

Nothing to lose

The boxed-text about ‘nothing to lose but your bugs’ strikes me as ‘sales pitch’. Having believed, then being bitten by this catch phrase I don’t buy it. TDD will not help the developers write the right feature - just help ensure that what they write is what they intended. It is not a silver bullet; and I’d think that Pryce and Freeman had not intended that; so I hope that I’ll see something that backs up this claim from them.

(However I do feel that implementing via TDD helps drive out cases that might get missed until later exploratory testing. By finding them earlier in the process we have a big win.)

After finishing the rest of the chapter I see their claim is that all the levels of TDD practices: end-to-end; integration and unit; could reduce the chance of writing the wrong code.

Refactoring

Pryce and Freeman say that refactoring is a local change. This made me immediately realize that easily fall into large refactorings. This is something I want to keep an eye on. Not just for refactorings - but for any work - I should work in small chunks.

A rose by any other name…

It annoys me that there are so many terms for different levels of tests. I personally use ‘Integration’ test for any test that integrates two or more components (except for those sets of components which I consider a Unit - then of course that would be a Unit test…). They keep talking about ‘Acceptance Tests’ which to me are ‘User Tests’ - and given I just got back from some training from Jim Shore I am currently at least moderately against automated user tests. I do like End-to-End tests - that they call Acceptance test - but need to keep them under control since they have the drawback of slowness and brittleness.

I really like to have clear terms for things - terms that are understood generally by people. I think it eases communication. That being said I see in myself a lacking of clarity when I discuss topics. Reading this book is bringing this up to me; perhaps it is something I need to work on for myself.

Chapter 2

A web of messages

I think the important idea presented in this chapter is the idea the domain concepts are not embodied by a particular classes in your code but by the connections of those classes embodied by the messages that they pass each other. This is an idea I remember having trouble with when I first read this book and I am again having a little trouble making it concrete in my head. Hopefully this second read will help solidify it.

Values & Objects

The authors present a nice terminology for two types of collections of data and functionality found in code. Simply: Values are immutable without distinct identity; Objects have changing state and have distinct identity.

Here again is a reminder to me to have a clear, consistent terminology to aid in communication.

Tell don’t ask

While I am familiar with the “Law of Demeter”, it is one of those things that seems to quickly fall by the wayside as I code. Another thing to add to my list of things to improve.

There seems to be a lot of good discussion about this on the internet - one discussion and explanation of it I like is that from Avdi Grimm in his blog post Demeter: It’s not a good idea. It’s the law. In it he points to method chaining and points out:

>Look again at the definition of the Law: it never says anything about the
>number of methods called, or the number of objects a method uses. It is
>strictly concerned with the number of /types/ a method deals with.

So it is OK to chain a set of method calls together that all do different things to collections of objects, or Strings for example; but not when there are multiple different types of objects.

In Conclusion (for now)

I am looking forward to continuing my rereading of this book. I think I will gain from this review of important topics (Object Oriented Design and TDD). I may not end up agreeing with it - but I hope to solidify my thoughts and practices in this area through it.

Along the way I plan on continuing to take notes and then making blog posts about it. I think through this process I will do an even better job of understanding what I have read. I hope you all don’t mind too much.

Postscript - Chapter 3

Chapter 3 was a discussion about using JMock. Nothing really to note or report. I have no yet decided what language(s) I will be using while doing the exercises. I think I may just do it in Java with JMock so that I can easily follow along with their examples. However another part of me wants to do them in Ruby or Groovy or Clojure to help me compare and contrast.

In any case, any code written will of course be published to my Github.

Reflections Upon the Art of Agile Training

| Comments

What

I am returning home from the Art of Agile Boot Camp presented by James Shore and Diana Larsen in New York City.

The training turned out to be review for me given that most of my coworkers are Cyrus Innovations employees and they all attended this training in October of 2011. They came back and implemented some of the ideas from the training - so in a way I’ve been living this stuff since then. Even before that we were a pretty well functioning agile team.

Even though it was a review I still thought it was very beneficial to me. There are always opportunities to improve; and details/reasonings that had been forgotten. Old ideas can become new again through re-iteration.

The training was split into two parts. The first two days covered Agile Planning and the last three Agile Delivery. The latter was what I was most interested in - but I think I may have gotten just as much out of the first section.

90 Minute Iterations?! - Crazy!

It was in the second half of the class that we got to “experience” Agile Delivery for ourselves. In our groups we delivered working software four times in four iterations; each iteration was 90 minutes long. It seemed crazy and a few times it felt crazy - but we did deliver running software (a cheesy text based ‘game’) in 90 minute iterations. During these 90 minutes we did everything from release planning, to coding (TDD’d naturally), exploratory testing, and releasing.

Crazy as it may seem - it is a brilliant exercise. By making us so focused we needed to organize ourselves, help each other out and really work to remove all roadblocks. Also it forced us to make, quickly, decisions about what was going to be in and what was not. We couldn’t let ego get in the way and argue too much about anything; we could always pivot and change our minds later.

Relearning what Stories are

Even as a well functioning agile team I have to say that there were some things related to stories that I now think I/We were doing wrong or not so well. Firstly, I was reminded that Stories are not requirements. Stories are conversations about the requirements and they are negotiable. It is really important that they are small and independent. A story on its own is not likely to be a complete feature (MMF) - they ought to be much smaller than that.

Another point about stories that Jim makes a point of is that they should not be re-estimated. This seemed odd to me so I made a point to discuss it further. It seemed to me that one should re-estimate a story if more information is known. For example we may come to know that the implementation needed for a story is harder than first thought, or easier (perhaps it is becoming routine).

Jim’s point is that estimates are always wrong, but they should be consistent. So if something was estimated as a ‘1’; then anything like it should also be a ‘1’; even if find out that it was easier/harder. The reason is because if we change our estimations then our velocity becomes less meaningful. It is our velocity that should be changing to reflect our capability for doing N 1-point stories. That N will go up and down as 1 point stories are harder/easier.

Velocity: settling

Instead of simply doing Yesterday’s Weather, Jim suggests letting velocity ‘settle’. The way he put it was: Decrease velocity easily. Increase velocity pessimistically.
The idea is that if you always use Yesterday’s Weather that your velocity may tend to to be erratic, and more importantly that it prevents the team from having consistent time for Slack. While I can understand this intellectually I find it hard to grok. Perhaps that is because of long standing bad habits from previous work environments. It is something I’d like to experiment with.

</span>

Focus on Delivering Value

Duh. I just needed to be reminded of this.

Fluencies

Diana and Jim presented an idea of ‘Fluency’ in Agile Practices. Each level is useful, none of them are ‘bad’. They are:

  1. We build code.
  2. We create business value.
  3. We deliver business value.
  4. We optimize business value.
  5. We optimize our organization’s business value.

The idea is that you are ‘fluent’ at a level, as with a language, when you can easily work at that level, even under pressure. I think our current team, and myself, is largely fluent at the level of delivering business value and day-to-day we do some work at the level of optimizing that value.

So What

The First Thing to Build…

Diana mentioned a good quote: The First thing to build is Trust. The idea is that the first thing the team needs to get good at is delivering on its commitments - consistently.

</span>

Iteration Planning is a design activity

This is an interesting idea that I need to think more about. The idea is that because Iteration Planning involves choices about what will be built; that it affect design.

People over…

I always find interacting with people who are interested in or driven to learning very energizing. A change in this time I realized what that now I was the person who was answering questions of and encouraging people who were new to Agile. I am starting to realize that I know this stuff and have something to offer. It was also great to see a coworker doing the same, and doing a better job than I did.

Now What

There are some things I want to try for myself and for my team.

Demos

Right now on my current project we do not have Customer Demos. I said a few times during the training that my project does not yet have a Customer, but what it really doesn’t have is a User. I think we could start demoing it now to whoever wanted to see it. At the least demoing to fellow team members may help us be focused and see a bigger picture.

Story sizing

Currently our features are not quite Minimum Marketable Features. They tend to be larger than that. Furthermore it seems our Product Manager (the Customer Proxy) doesn’t care much about anything smaller than that. However that is leaving us with only a story or two per iteration - which is not helping us achieve a more stable velocity.

I need to do some brainstorming on how we can (or if we should) shrink our features. Then figure out ways to split stories into smaller chunks so we can have several per iteration (at least 4). The important thing here is to keep business value in each story. While I do not think this will magically cause my Product Manager to care about the smaller stories; but I hope it will help engage them more if we can show business value progress with each one.

Related to this is the problem that it seems there may be some expectations about when the current release will be shippable. My current projections are much further out from those expectations. I need to use tools like Velocity, Release Planning with Risk calculations (ala Rabu which I currently use) to bring data to the table in my discussions with the Product and Project Managers.

Root Cause Analysis

Now that I’ve had this review I feel that I and my team have not been doing a good job of doing root cause analysis on the issues in our process which we discuss in our Retrospectives. Furthermore we are not doing a good job of root cause analysis on any bugs that come up.

(On the topic of bugs I want to more seriously have the “Bugs don’t happen here” attitude.)

Conclusion

In conclusion the training was fantastic - even for someone who is not new to Agile methodologies. I am bringing back some good ideas which may help me and my team achieve even better fluency in our work. It also solidified for me some existing ideas that I thought I/we already did pretty well.

Fixing python/pygments.rb Problem in Octopress

| Comments

After I posted my last blog post it was reported to me that my code blocks were no displaying properly. The readers were seeing an error like: "Liquid error: Could not open library ‘/usr/local/lib/libpython2.7.a’: ...".

Some googling informed me that the problem seemed to be somewhere in RubyPython. The instructions were relatively straightforward - but it wasn’t clear to me if I needed to do both of the directions.

The quick answer is yes. To fix this problem one must do the following:

  1. Make sure RubyPython is locked to 0.5.1 in the Gemfile (i.e. gem 'rubypython', '= 0.5.1'
  2. Create a file plugins/ruby_python_heroku_fix.rb with the contents: RubyPython.configure :python_exe => 'python2.6' (the filename is not actually important).

My Problems Bootstrapping Midje

| Comments

(A Tragedy of My Own Devising)

Abstract

I had a lot of problems setting up my first Midje tests for my Clojure project (defdrink) last night and thought it might be useful for me to write about it.

(And helpful it was… I see plenty of mistakes I made and summarize the lessons learned at the end).

Background

First a quick background. (defdrink) will be/is a web application which will assist in the choosing of a cocktail based upon the contents of the users liquor cabinet. I am using this project as a means of learning Clojure. I have put all the source on github (as one does…) and in this post will refer to particular commits to illustrate different steps.

In the Beginning…

At the point where our story begins I had slapped together a quick (and ugly) prototype. The purpose of the prototype was to get a Clojure project which has a web page which allowed retrieving and saving data into a database; all served up on Heroku. Being a prototype - it had not tests (horrors). This moment in time is commit 0da77fbafc87634e94e0342e409e5b071b8d6c1f.

Trying to put in the first Midje test.

It took me two tries to get my first Midje test (and that first test merely proved that Arithmetic worked: (fact (+ 2 2) => 4)).

My first attempt was me doing what I thought was ‘obvious’ and what I thought the Midje wiki was telling me I should be able to do: put a bit of magic in my projects.clj file and then a test file with a (fact ...) in it.

That attempt ending with frustration at the fact the only feedback I was getting was a bunch of Java stack traces.

My second attempt was simply making these same stumblings - I had wrongly assumed that I had I simply not quite understood the previous time.

After I realized that my second attempt was heading toward another failure I finally rolled back and tried to take the next smallest step. I wanted to run Midje (with Lazytest) and get it to report something like “0 tests”. With the help of the lein-midje plugin Readme I got this working in not too much time. If you look at that commit you will notice a glaring error - one that was not obvious to me as I tried to continue.

My first Midje test…

A Problem of My Own Devising

Ages ago when I started this project I ran lein new defdrink and then, since I didn’t have any tests, I removed the test subdirectory. Now, a month later, I couldn’t remember just how the test directory was supposed to be laid out, and it was obvious to me that it needed to have some special directory tree/naming to find the files etc. Mixed into that was a lack of understanding Clojure namespaces and directory structures (this was just me being dense). At this point I kept getting stack traces about not finding namespaces, which all seemed right - but obviously lein, midje, clojure or all three didn’t agree.

Finally I had just ran lein new foo in a temp directory and saw the structure needed. That was the clue I needed – the clue I couldn’t find this little simple piece of information out on the web either for Midje or Clojure’s own test framework. Now that I had the directory structure right, the namespace in the file right it would work right? Right?

…wrong…

As I am sure all of you playing along at home can see - I never added a dependency on Midje itself in the previous step. That means at this point I started getting messages that said:

Could not locate midje/sweet__init.class or midje/sweet.clj on classpath

Let me tell you this was very confusing after all I knew that I already had Midje working. Now that I added a test it says it can’t find Midje?! Finally I saw my error and fixed it. Now at long last, I had a Midje test! Of course it was just a dummy test but it was actually running.

Now, let’s do it for reals…

My next step was to get a real test. My premise for these tests was to remove some hardcoded SQL code in my model class. I was going to push that code down into a couple helper classes so that I could isolate myself from the database. The first test was to show that my defdrink/all method would delegate down to my new sql/select method with the :drinks parameter (that is the table name).

I once again had some odd and annoying problems with the only feedback being cryptic stack traces. I don’t remember all the details but they involved statements such as ‘provided not being defined in this context’ - which led me down wild chases to determine if I had all the right modules required etc. Fortunately/unfortunately the problems resolved themselves (I hate that) and I got my first real test running:

A Small Step for One Programmerdefdrink/test/defdrink/test/models/drinks.clj
1
2
(fact (all) => [...drink1... ...drink2...]
      (provided (sql/select :drinks) => [...drink1... ...drink2...]))

(I sort of like how it turned out… I like the metacontstants feature and am excited to try it out more.)

And now for my encore…

Now that the select statement was sequestered, I turned my attention to the insert statement. This is where I again ran into problems.

This new test, like the previous, was going to be a simple test of delegation. Did the model layer properly call down to the database layer to query or persist the data. The test I wanted to write was to say that the defdrink/save method called the sql/insert method with the correct parameters. My first attempt at this ended… (wait for it…) in frustration.

What’s wrong THIS time?!

In Ruby or Java/Groovy I’d simply have my test call my method and test the expectation on my mock object that the sql/insert method was called with the correct parameters. Unfortunatly for me, I could not figure out how to do that in Midje. I ended with the following unhappy test:

An Unhappy Testdefdrink/test/defdrink/test/models/drinks.clj
1
2
3
(fact
     (insert ...name...) => ...not-important...
     (provided (sql/insert :drinks {:name ...name...}) => ...not-important...))

I’ll freely admit that while trying to write this test I began to have doubts (which I still hold) that perhaps I shouldn’t even by trying to right this test. It just seemed like a code smell to me. The way the test ended up seems to be telling me: “Mark, just what are you thinking?!”

Conclusion

In conclusion (finally) my problems were much of my own devising. Whether it was shooting myself in the foot, trying to do something quickly because “its easy right?”, not yet understanding this language/environment I am trying to work in, or simply because I am trying to write Clojure tests as I would Ruby or Java tests – I’ve had a hard time getting to this point.

Even admitting my own problems, I have to say, IMNSHO that it would have been nice to see a tutorial/cookbook out there of how to get started with Midje. What I’d have liked to have found would be something which stepped me through:

  1. what to put in my project.clj file for midje, lazytest, and lien
  2. a simple example of getting one’s first tests off the ground
  3. and then a bit more showing mocking for example.

In researching this blog post I see I did overlook some resources on the Midje wiki that would have helped, at least with the second two points.

So the moral is:

  1. slow down
  2. small steps
  3. read the docs, not just look at them.

I do think I might try to contribute this sort of tutorial to the Midje project. Because I can’t be the only dope who thinks he knows what he’s doing, who will get frustrated because there is not a tutorial to hold his hand through the first steps.

Kraftwerk @ MoMA

| Comments

We arrived

We were going to see Kraftwerk at MoMA and the trip didn’t start well as we sat in stop-and-go traffic through Connecticut right into NYC. Luckily we were not driving ourselves, but I still worried this was an ill omen. We even had trouble finding some quick food before the show. Even with all these problems the show was fantastic.

Wendy and I staked our claim to a bench off to the side and at the back while the surprisingly young crowd filled in in front of the stage. The view was just fine from where we were.

Before the Start

The show began with the dropping of the curtain - showing the band at their podiums.

Man Machine

They started the album off by playing Man-Machine and with the 3d glasses the visuals were interesting… but when Spacelab started they were fantastic.

Spacelab

The images of Spacelab orbiting the earth was great. They even used a cheap 3d trick of having the orbiting ship head straight into the audience; cheap but still fun.

Spacelab

The huge looming buildings, and slow pans through them fit with the song Metropolis perfectly.

Metropolis

The visuals for The Model were all black-and-white fashion shots - not much more interesting in ‘3d’ than not, but the next song (Neon Lights) used the 3d effects better.

Neon Lights

The album performance was capped off with We are the Robots. Everyone went wild over the robo-kraftwerk dancing and looming over the audience.

We are the Robots

Now that the album was over I was not sure what to expect; I was not disappointed with their choice of Autobahn - the visuals being computer generated VW Beetle and other cars on a seemingly infinite Autobahn. The song ended with VW pulling off the highway.

Autobahn

Up next was Radioactivity followed by Trans Europe Express. Then ComputerWorld and Tour De France.

Tour de France

Then my phone battery died - so not more pictures. So you’ll have to take my word on it that the rest of the show, including Technopop was fantastic.

My full set of pictures is availble on my flickr stream

Old Blog Posts Migrated

| Comments

Using this updated migrator for Jekyll I have managed to get all my old Posterous blog posts loaded into this Octopress blog.

There is still a problem with some posts - the media they contained are not currently available. I think it was the posts where I had emailed a picture to Posterous (which would then bounced to Flickr and Twitter). But any post I composed as an email seems to be here.

The time it takes to generate the site has really dropped off unfortunately. Hopefully it will not just get linearly worse…

A Year Without a Office Desk

| Comments

(Well not quite true I don’t have a desk at all… but effectively I don’t have one).

About a year ago I changed to a new job. In all previous jobs I’ve had I had a desk, in fact I had a office (sometimes shared) or at least a cube of my own. It was different at the new job; when I showed up on my first day at the new work there was a little bit of confusion about what cube I could be given and as a ‘temporary’ solution I was given a desk in the lab.

Given the way we work on the team, I spent very little time at my desk. It became simply a place where I put my bag & coat; a place for my coffee mug; a place for my notebook at the end of the day. I did use it to check my email first thing in the morning before everyone arrived (I’m an early person) - but other than that - unused. As the months went on I used it less and less everyday.

Then in January the new DBA consultant started sitting at it with his laptop so he could be with the team; thus I was partially evicted from my ‘desk’. I still kept my inbox there - but now I didn’t even use the desk to read my email in the morning.

At this same time there was a new coworker starting and with that a little angst about where they would sit (the cube situation was in fact no better; but actually worse). A cube was found for her; but I felt that by giving up my desk entirely I was making a personal statement about desks, cubes, offices.

I do have regrets periodically when I need to do some personal matters; but we have a shared office nearby the lab and a few cubes that can be used in a pinch for private work/calls.

In all - I have not really missed having a desk. I have found out that I don’t need much more than space for my inbox; maybe someday space for some filing. This conclusion is NOT what I would have expected from myself; I remember clearly wanting an office and bemoaning my fate of being in cubes. It seems I have accepted the team-room setting more than I had imagined I could have.